aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/context2d/qquickcanvasitem.cpp
diff options
context:
space:
mode:
authorGunnar Sletta <gunnar.sletta@digia.com>2013-11-27 17:04:06 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-12-03 18:06:36 +0100
commit9ad9615d0003c9fb84255152f0cbb473ee2a7a70 (patch)
treec4aba681ddacd7eadb4defe7312e9020b43407c2 /src/quick/items/context2d/qquickcanvasitem.cpp
parent9e77d6c31b406e5941a2d287f3c8842954815db4 (diff)
Improve the Canvas threading model
The canvas classes were mixing scene graph resources and GL content across threads. This led to a number of potential crashes in addition to that the FBO based rendering had significant potential for stalling. QQuickContext2DTexture is no longer a QSGTexture with ambiguous ownership. Instead we use textureForNextFrame which is called on the render thread while the GUI is locked to synchronize state from the Context2D's "texture" into the actual QSGTexture. This means that cleanup of the QQuickContext2DTexture and the QSGTexture used for display is no longer in conflict. QQuickPixmap no longer contains a QSGTexture either as these are strictly for use on the scene graph thread. The Images are anyway loaded explicitly as QImage files in QQuickContext2DContext and uploaded again for every Canvas, so relying on the GL paint engine to do the caching will give us the same with less code. I also changed the default strategy to Immediate as that one supports the full API (cooperative does not support readback) and because cooperative is pretty bad for performance since the rendering happens in the sync() step. Task-number: QTBUG-34268 Task-number: QTBUG-31052 Task-number: QTBUG-21935 Task-number: QTBUG-30689 Task-number: QTBUG-29007 Change-Id: Ic540b22d5faa1188e21e56a3beee24191d13f423 Reviewed-by: Mitch Curtis <mitch.curtis@digia.com> Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
Diffstat (limited to 'src/quick/items/context2d/qquickcanvasitem.cpp')
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp64
1 files changed, 34 insertions, 30 deletions
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index ba3592986c..19a161a605 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -44,8 +44,10 @@
#include <private/qquickitem_p.h>
#include <private/qquickcanvascontext_p.h>
#include <private/qquickcontext2d_p.h>
+#include <private/qquickcontext2dtexture_p.h>
#include <qsgsimpletexturenode.h>
#include <QtQuick/private/qquickpixmapcache_p.h>
+#include <QtGui/QGuiApplication>
#include <qqmlinfo.h>
#include <private/qqmlengine_p.h>
@@ -58,19 +60,15 @@
QT_BEGIN_NAMESPACE
-QQuickCanvasPixmap::QQuickCanvasPixmap(const QImage& image, QQuickWindow *window)
+QQuickCanvasPixmap::QQuickCanvasPixmap(const QImage& image)
: m_pixmap(0)
, m_image(image)
- , m_texture(0)
- , m_window(window)
{
}
-QQuickCanvasPixmap::QQuickCanvasPixmap(QQuickPixmap *pixmap, QQuickWindow *window)
+QQuickCanvasPixmap::QQuickCanvasPixmap(QQuickPixmap *pixmap)
: m_pixmap(pixmap)
- , m_texture(0)
- , m_window(window)
{
}
@@ -78,8 +76,6 @@ QQuickCanvasPixmap::QQuickCanvasPixmap(QQuickPixmap *pixmap, QQuickWindow *windo
QQuickCanvasPixmap::~QQuickCanvasPixmap()
{
delete m_pixmap;
- if (m_texture)
- m_texture->deleteLater();
}
qreal QQuickCanvasPixmap::width() const
@@ -105,18 +101,6 @@ bool QQuickCanvasPixmap::isValid() const
return !m_image.isNull();
}
-QSGTexture *QQuickCanvasPixmap::texture()
-{
- if (!m_texture) {
- if (m_pixmap) {
- Q_ASSERT(m_pixmap->textureFactory());
- m_texture = m_pixmap->textureFactory()->createTexture(m_window);
- } else {
- m_texture = m_window->createTextureFromImage(m_image, QQuickWindow::TextureCanUseAtlas);
- }
- }
- return m_texture;
-}
QImage QQuickCanvasPixmap::image()
{
if (m_image.isNull() && m_pixmap)
@@ -194,7 +178,7 @@ QQuickCanvasItemPrivate::QQuickCanvasItemPrivate()
, hasCanvasWindow(false)
, available(false)
, renderTarget(QQuickCanvasItem::Image)
- , renderStrategy(QQuickCanvasItem::Cooperative)
+ , renderStrategy(QQuickCanvasItem::Immediate)
{
antialiasing = true;
}
@@ -246,10 +230,14 @@ QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
The Canvas.FramebufferObject render target utilizes OpenGL hardware
acceleration rather than rendering into system memory, which in many cases
- results in faster rendering.
+ results in faster rendering. Canvas.FramebufferObject relies on the
+ OpenGL extensions \c GL_EXT_framebuffer_multisample and
+ \c GL_EXT_framebuffer_blit for antialiasing. It will also use more
+ graphics memory when rendering strategy is anything other than
+ Canvas.Cooperative.
The default render target is Canvas.Image and the default renderStrategy is
- Canvas.Cooperative.
+ Canvas.Immediate.
\section1 Tiled Canvas
The Canvas item supports tiled rendering by setting \l canvasSize, \l tileSize
@@ -489,7 +477,7 @@ void QQuickCanvasItem::setCanvasWindow(const QRectF& rect)
context will choose appropriate options and Canvas will signal the change
to the properties.
- The default render target is \c Canvas.FramebufferObject.
+ The default render target is \c Canvas.Image.
*/
QQuickCanvasItem::RenderTarget QQuickCanvasItem::renderTarget() const
{
@@ -531,7 +519,7 @@ void QQuickCanvasItem::setRenderTarget(QQuickCanvasItem::RenderTarget target)
the GUI thread. Selecting \c Canvas.Cooperative, does not guarantee
rendering will occur on a thread separate from the GUI thread.
- The default value is \c Canvas.Cooperative.
+ The default value is \c Canvas.Immediate.
\sa renderTarget
*/
@@ -689,6 +677,15 @@ void QQuickCanvasItem::updatePolish()
}
}
+class QQuickCanvasNode : public QSGSimpleTextureNode
+{
+public:
+ ~QQuickCanvasNode()
+ {
+ delete texture();
+ }
+};
+
QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
Q_D(QQuickCanvasItem);
@@ -698,9 +695,9 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
return 0;
}
- QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode*>(oldNode);
+ QQuickCanvasNode *node = static_cast<QQuickCanvasNode*>(oldNode);
if (!node)
- node = new QSGSimpleTextureNode;
+ node = new QQuickCanvasNode();
if (d->smooth)
node->setFiltering(QSGTexture::Linear);
@@ -712,8 +709,15 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
d->context->flush();
}
- node->setTexture(d->context->texture());
- node->markDirty(QSGNode::DirtyMaterial);
+ QQuickContext2D *ctx = qobject_cast<QQuickContext2D *>(d->context);
+ QQuickContext2DTexture *factory = ctx->texture();
+ QSGTexture *texture = factory->textureForNextFrame(node->texture());
+ if (!texture) {
+ delete node;
+ return 0;
+ }
+
+ node->setTexture(texture);
node->setRect(QRectF(QPoint(0, 0), d->canvasWindow.size()));
return node;
}
@@ -916,7 +920,7 @@ void QQuickCanvasItem::loadImage(const QUrl& url)
if (!d->pixmaps.contains(fullPathUrl)) {
QQuickPixmap* pix = new QQuickPixmap();
QQmlRefPointer<QQuickCanvasPixmap> canvasPix;
- canvasPix.take(new QQuickCanvasPixmap(pix, d->window));
+ canvasPix.take(new QQuickCanvasPixmap(pix));
d->pixmaps.insert(fullPathUrl, canvasPix);
pix->load(qmlEngine(this)