Enable threaded/immediate rendering for FBO(step 1)
authorCharles Yin <charles.yin@nokia.com>
Thu, 17 May 2012 23:58:09 +0000 (09:58 +1000)
committerQt by Nokia <qt-info@nokia.com>
Thu, 31 May 2012 00:23:02 +0000 (02:23 +0200)
1. Create a new gl context if the scenegraph render thread is different with context2d render thread
2. Expose the gl context and window surface from context2d
3. Get the right current gl context before painting

Change-Id: I5e252a8142d760442f9dfb53ed8a8ce289379af9
Reviewed-by: Glenn Watson <glenn.watson@nokia.com>

src/quick/items/context2d/qquickcontext2d.cpp
src/quick/items/context2d/qquickcontext2d_p.h
src/quick/items/context2d/qquickcontext2dtexture.cpp

index 11bc8ea..637377b 100644 (file)
 #include <qqmlengine.h>
 #include <private/qv8domerrors_p.h>
 #include <QtCore/qnumeric.h>
+#include <private/qquickcanvas_p.h>
+#include <private/qquickwindowmanager_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <qpa/qplatformintegration.h>
 
 #ifdef Q_OS_QNX
 #include <ctype.h>
@@ -3319,6 +3323,9 @@ QQuickContext2D::QQuickContext2D(QObject *parent)
     : QQuickCanvasContext(parent)
     , m_buffer(new QQuickContext2DCommandBuffer)
     , m_v8engine(0)
+    , m_windowManager(0)
+    , m_surface(0)
+    , m_glContext(0)
 {
 }
 
@@ -3344,11 +3351,8 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
     m_canvas = canvasItem;
     m_renderTarget = canvasItem->renderTarget();
 
-    // For the FBO target we only (currently) support Cooperative
-    if (m_renderTarget == QQuickCanvasItem::FramebufferObject) {
-        canvasItem->setRenderStrategy(QQuickCanvasItem::Cooperative);
-    }
-
+    QQuickCanvas *canvas = canvasItem->canvas();
+    m_windowManager =  QQuickCanvasPrivate::get(canvas)->windowManager;
     m_renderStrategy = canvasItem->renderStrategy();
 
     switch (m_renderTarget) {
@@ -3356,7 +3360,12 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
         m_texture = new QQuickContext2DImageTexture(m_renderStrategy == QQuickCanvasItem::Threaded);
         break;
     case QQuickCanvasItem::FramebufferObject:
+    {
         m_texture = new QQuickContext2DFBOTexture;
+        // No BufferQueueingOpenGL, falls back to Cooperative mode
+        if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::BufferQueueingOpenGL))
+            m_renderStrategy = QQuickCanvasItem::Cooperative;
+    }
         break;
     }
 
@@ -3366,6 +3375,24 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args
     m_texture->setCanvasSize(canvasItem->canvasSize().toSize());
     m_texture->setSmooth(canvasItem->smooth());
 
+    QThread *renderThread = QThread::currentThread();
+    QThread *sceneGraphThread = canvas->openglContext() ? canvas->openglContext()->thread() : 0;
+
+    if (m_renderStrategy == QQuickCanvasItem::Threaded)
+        renderThread = QQuickContext2DRenderThread::instance(qmlEngine(canvasItem));
+    else if (m_renderStrategy == QQuickCanvasItem::Cooperative)
+        renderThread = sceneGraphThread;
+
+    if (m_renderTarget == QQuickCanvasItem::FramebufferObject && renderThread != sceneGraphThread) {
+         QOpenGLContext *cc = QQuickCanvasPrivate::get(canvas)->context->glContext();
+         m_surface = canvas;
+         m_glContext = new QOpenGLContext;
+         m_glContext->setFormat(cc->format());
+         m_glContext->setShareContext(cc);
+         if (renderThread != QThread::currentThread())
+             m_glContext->moveToThread(renderThread);
+    }
+
     connect(m_texture, SIGNAL(textureChanged()), SIGNAL(textureChanged()));
 
     reset();
index 409c165..22addf3 100644 (file)
@@ -70,7 +70,9 @@ class QQuickContext2DCommandBuffer;
 class QQuickContext2DTexture;
 class QQuickPixmap;
 class QSGTexture;
-
+class QQuickWindowManager;
+class QSurface;
+class QOpenGLContext;
 
 class QQuickContext2D : public QQuickCanvasContext
 {
@@ -223,6 +225,9 @@ public:
     QPainterPath createTextGlyphs(qreal x, qreal y, const QString& text);
     QImage createImage(const QUrl& url);
 
+    QOpenGLContext *glContext() { return m_glContext; }
+    QSurface *surface() { return m_surface; }
+
     State state;
     QStack<QQuickContext2D::State> m_stateStack;
     QQuickCanvasItem* m_canvas;
@@ -232,6 +237,9 @@ public:
     v8::Local<v8::Value> m_strokeStyle;
     v8::Handle<v8::Value> m_v8path;
     QV8Engine *m_v8engine;
+    QQuickWindowManager *m_windowManager;
+    QSurface *m_surface;
+    QOpenGLContext *m_glContext;
     v8::Persistent<v8::Object> m_v8value;
     QQuickContext2DTexture *m_texture;
     QQuickCanvasItem::RenderTarget m_renderTarget;
index 1beee8c..52f3161 100644 (file)
@@ -68,6 +68,25 @@ static inline int qt_next_power_of_two(int v)
     return v;
 }
 
+struct GLAcquireContext {
+    GLAcquireContext(QOpenGLContext *c, QSurface *s):ctx(c) {
+        if (ctx) {
+            Q_ASSERT(s);
+            if (!ctx->isValid())
+                ctx->create();
+
+            if (!ctx->isValid())
+                qWarning() << "Unable to create GL context";
+            else if (!ctx->makeCurrent(s))
+                qWarning() << "Can't make current GL context";
+        }
+    }
+    ~GLAcquireContext() {
+        if (ctx)
+            ctx->doneCurrent();
+    }
+    QOpenGLContext *ctx;
+};
 
 Q_GLOBAL_STATIC(QThread, globalCanvasThreadRenderInstance)
 
@@ -241,6 +260,8 @@ void QQuickContext2DTexture::paint()
     if (canvasDestroyed())
         return;
 
+    GLAcquireContext currentContext(m_context->glContext(), m_context->surface());
+
     if (m_threadRendering && QThread::currentThread() != globalCanvasThreadRenderInstance()) {
         Q_ASSERT(thread() == globalCanvasThreadRenderInstance());
         QMetaObject::invokeMethod(this, "paint", Qt::QueuedConnection);