From 20d641a4eb1a3ffe1cff41491b64b6b857982847 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Thu, 26 Jan 2012 11:17:37 +0100 Subject: [PATCH] Started implementation of offscreen canvas FBO rendering API Change-Id: I15b1799982d20d16c9c5e08eee7095cf087b49e1 Reviewed-by: Kim M. Kalland --- src/quick/items/qquickcanvas.cpp | 25 ++++++++++++++ src/quick/items/qquickcanvas_p.h | 5 ++- src/quick/items/qquickwindowmanager.cpp | 55 ++++++++++++++++++++++++++---- 3 files changed, 76 insertions(+), 9 deletions(-) diff --git a/src/quick/items/qquickcanvas.cpp b/src/quick/items/qquickcanvas.cpp index ac7928f..72300f9 100644 --- a/src/quick/items/qquickcanvas.cpp +++ b/src/quick/items/qquickcanvas.cpp @@ -204,6 +204,30 @@ void QQuickCanvasPrivate::polishItems() updateFocusItemTransform(); } +/** + * This parameter enables that this canvas can be rendered without + * being shown on screen. This feature is very limited in what it supports. + * + * There needs to be another window actually showing that we can make current + * to get a surface to make current AND for this feature to be useful + * one needs to hook into beforeRender() and set the render tareget. + * + */ +void QQuickCanvasPrivate::setRenderWithoutShowing(bool render) +{ + if (render == renderWithoutShowing) + return; + + Q_Q(QQuickCanvas); + renderWithoutShowing = render; + + if (render) + windowManager->show(q); + else + windowManager->hide(q); +} + + void forceUpdate(QQuickItem *item) { if (item->flags() & QQuickItem::ItemHasContents) @@ -253,6 +277,7 @@ QQuickCanvasPrivate::QQuickCanvasPrivate() : rootItem(0) , activeFocusItem(0) , mouseGrabberItem(0) + , renderWithoutShowing(false) , dirtyItemList(0) , context(0) , renderer(0) diff --git a/src/quick/items/qquickcanvas_p.h b/src/quick/items/qquickcanvas_p.h index d5021d8..45b87c6 100644 --- a/src/quick/items/qquickcanvas_p.h +++ b/src/quick/items/qquickcanvas_p.h @@ -93,7 +93,7 @@ class QTouchEvent; class QQuickCanvasRenderLoop; class QQuickCanvasIncubationController; -class QQuickCanvasPrivate : public QWindowPrivate +class Q_QUICK_EXPORT QQuickCanvasPrivate : public QWindowPrivate { public: Q_DECLARE_PUBLIC(QQuickCanvas) @@ -152,6 +152,9 @@ public: void syncSceneGraph(); void renderSceneGraph(const QSize &size); + bool renderWithoutShowing; + void setRenderWithoutShowing(bool enabled); + QQuickItem::UpdatePaintNodeData updatePaintNodeData; QQuickItem *dirtyItemList; diff --git a/src/quick/items/qquickwindowmanager.cpp b/src/quick/items/qquickwindowmanager.cpp index b5dd2da..d54be90 100644 --- a/src/quick/items/qquickwindowmanager.cpp +++ b/src/quick/items/qquickwindowmanager.cpp @@ -208,6 +208,16 @@ public: void run(); + QQuickCanvas *masterCanvas() { + QQuickCanvas *win = 0; + for (QHash::const_iterator it = m_rendered_windows.constBegin(); + it != m_rendered_windows.constEnd() && !win; ++it) { + if (it.value()->isVisible) + win = it.key(); + } + return win; + } + public slots: void animationStarted(); void animationStopped(); @@ -249,6 +259,7 @@ private: QSize viewportSize; uint sizeWasChanged : 1; + uint isVisible : 1; }; QHash m_rendered_windows; @@ -276,6 +287,7 @@ public: void canvasDestroyed(QQuickCanvas *canvas); + void initializeGL(); void renderCanvas(QQuickCanvas *canvas); void paint(QQuickCanvas *canvas); QImage grab(QQuickCanvas *canvas); @@ -329,7 +341,10 @@ QQuickWindowManager *QQuickWindowManager::instance() void QQuickRenderThreadSingleContextWindowManager::initialize() { Q_ASSERT(m_rendered_windows.size()); - QQuickCanvas *win = m_rendered_windows.constBegin().key(); + + QQuickCanvas *win = masterCanvas(); + if (!win) + return; gl = new QOpenGLContext(); // Pick up the surface format from one of them @@ -378,6 +393,7 @@ void QQuickRenderThreadSingleContextWindowManager::handleAddedWindow(QQuickCanva CanvasData *data = new CanvasData; data->sizeWasChanged = false; data->windowSize = canvas->size(); + data->isVisible = canvas->visible(); m_rendered_windows[canvas] = data; isExternalUpdatePending = true; @@ -489,7 +505,7 @@ void QQuickRenderThreadSingleContextWindowManager::canvasVisibilityChanged() CanvasTracker &t = const_cast(m_tracked_windows.at(i)); QQuickCanvas *win = t.canvas; - Q_ASSERT(win->visible() || t.toBeRemoved); + Q_ASSERT(win->visible() || QQuickCanvasPrivate::get(win)->renderWithoutShowing || t.toBeRemoved); bool canvasVisible = win->width() > 0 && win->height() > 0; anyoneShowing |= (canvasVisible && !t.toBeRemoved); @@ -541,6 +557,9 @@ void QQuickRenderThreadSingleContextWindowManager::run() wake(); unlock(); + if (!gl) + return; + while (!shouldExit) { lock(); @@ -591,7 +610,10 @@ void QQuickRenderThreadSingleContextWindowManager::run() Q_ASSERT(canvasData->windowSize.width() > 0 && canvasData->windowSize.height() > 0); - gl->makeCurrent(canvas); + if (!canvasData->isVisible) + gl->makeCurrent(masterCanvas()); + else + gl->makeCurrent(canvas); if (canvasData->viewportSize != canvasData->windowSize) { #ifdef THREAD_DEBUG @@ -660,7 +682,9 @@ void QQuickRenderThreadSingleContextWindowManager::run() printf(" RenderThread: --- wait for swap...\n"); #endif - gl->swapBuffers(canvas); + if (canvasData->isVisible) + gl->swapBuffers(canvas); + canvasPrivate->fireFrameSwapped(); #ifdef THREAD_DEBUG printf(" RenderThread: --- swap complete...\n"); @@ -1141,15 +1165,30 @@ void QQuickTrivialWindowManager::renderCanvas(QQuickCanvas *canvas) CanvasData &data = const_cast(m_windows[canvas]); + QQuickCanvas *masterCanvas = 0; + if (!canvas->visible()) { + // Find a "proper surface" to bind... + for (QHash::const_iterator it = m_windows.constBegin(); + it != m_windows.constEnd() && !masterCanvas; ++it) { + if (it.key()->visible()) + masterCanvas = it.key(); + } + } else { + masterCanvas = canvas; + } + + if (!masterCanvas) + return; + if (!gl) { gl = new QOpenGLContext(); - gl->setFormat(canvas->requestedFormat()); + gl->setFormat(masterCanvas->requestedFormat()); gl->create(); - if (!gl->makeCurrent(canvas)) + if (!gl->makeCurrent(masterCanvas)) qWarning("QQuickCanvas: makeCurrent() failed..."); sg->initialize(gl); } else { - gl->makeCurrent(canvas); + gl->makeCurrent(masterCanvas); } bool alsoSwap = data.updatePending; @@ -1165,7 +1204,7 @@ void QQuickTrivialWindowManager::renderCanvas(QQuickCanvas *canvas) data.grabOnly = false; } - if (alsoSwap) { + if (alsoSwap && canvas->visible()) { gl->swapBuffers(canvas); cd->fireFrameSwapped(); } -- 1.7.2.5