From 76859e50d4b986fb88c2f193a70fd9b40963c59a Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Fri, 1 Aug 2014 11:22:31 +0200 Subject: More QQuickCanvas cleanup handling. Avoid calling into QQuickContext2D from QQuickContext2DTexture after QQuickContext2D has been deleted. We acheive this by 1. Giving the texture a direct pointer to the gl context and and surface, so that it doesn't need to go through m_context to get to them (which may have been deleted). 2. Protect access to QQuickContext2DTexture::m_context with a mutex and make sure it is set to 0 in a safe manner when the QQuickContext2D object is deleted. Change-Id: Ie0a30f9fc46f844224838a7cdf2f28a62e8ce322 Reviewed-by: Laszlo Agocs --- src/quick/items/context2d/qquickcontext2d.cpp | 12 +++--- src/quick/items/context2d/qquickcontext2d_p.h | 3 +- .../items/context2d/qquickcontext2dtexture.cpp | 50 ++++++++++++++-------- .../items/context2d/qquickcontext2dtexture_p.h | 10 ++++- 4 files changed, 47 insertions(+), 28 deletions(-) diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index 8858958dbc..7964f650d6 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -4084,6 +4084,8 @@ public: QOffscreenSurface *surface; }; +QMutex QQuickContext2D::mutex; + QQuickContext2D::QQuickContext2D(QObject *parent) : QQuickCanvasContext(parent) , m_buffer(new QQuickContext2DCommandBuffer) @@ -4097,6 +4099,8 @@ QQuickContext2D::QQuickContext2D(QObject *parent) QQuickContext2D::~QQuickContext2D() { + mutex.lock(); + m_texture->setItem(0); delete m_buffer; if (m_renderTarget == QQuickCanvasItem::FramebufferObject) { @@ -4120,6 +4124,7 @@ QQuickContext2D::~QQuickContext2D() // currently be doing. m_texture->deleteLater(); } + mutex.unlock(); } QV4::ReturnedValue QQuickContext2D::v4value() const @@ -4190,6 +4195,7 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args m_glContext->setShareContext(cc); if (renderThread != QThread::currentThread()) m_glContext->moveToThread(renderThread); + m_texture->initializeOpenGL(m_glContext, m_surface.data()); } connect(m_texture, SIGNAL(textureChanged()), SIGNAL(textureChanged())); @@ -4379,10 +4385,4 @@ void QQuickContext2D::setV8Engine(QV8Engine *engine) } } -QQuickContext2DCommandBuffer* QQuickContext2D::nextBuffer() -{ - QMutexLocker lock(&m_mutex); - return m_bufferQueue.isEmpty() ? 0 : m_bufferQueue.dequeue(); -} - QT_END_NAMESPACE diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h index bd1a83ce08..c679bc33cb 100644 --- a/src/quick/items/context2d/qquickcontext2d_p.h +++ b/src/quick/items/context2d/qquickcontext2d_p.h @@ -185,7 +185,6 @@ public: QQuickCanvasItem* canvas() const { return m_canvas; } QQuickContext2DCommandBuffer* buffer() const { return m_buffer; } - QQuickContext2DCommandBuffer* nextBuffer(); bool bufferValid() const { return m_buffer != 0; } void popState(); @@ -255,7 +254,7 @@ public: QImage m_grabbedImage; bool m_grabbed:1; - QMutex m_mutex; + static QMutex mutex; }; diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp index 4007713152..c8bea6f97e 100644 --- a/src/quick/items/context2d/qquickcontext2dtexture.cpp +++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp @@ -90,6 +90,8 @@ struct GLAcquireContext { QQuickContext2DTexture::QQuickContext2DTexture() : m_context(0) + , m_gl(0) + , m_surface(0) , m_item(0) , m_canvasWindowChanged(false) , m_dirtyTexture(false) @@ -146,8 +148,12 @@ void QQuickContext2DTexture::setAntialiasing(bool antialiasing) void QQuickContext2DTexture::setItem(QQuickCanvasItem* item) { m_item = item; - m_context = (QQuickContext2D*)item->rawContext(); // FIXME - m_state = m_context->state; + if (m_item) { + m_context = (QQuickContext2D*) item->rawContext(); // FIXME + m_state = m_context->state; + } else { + m_context = 0; + } } bool QQuickContext2DTexture::setCanvasWindow(const QRect& r) @@ -239,12 +245,15 @@ bool QQuickContext2DTexture::canvasDestroyed() void QQuickContext2DTexture::paint(QQuickContext2DCommandBuffer *ccb) { + QQuickContext2D::mutex.lock(); if (canvasDestroyed()) { delete ccb; + QQuickContext2D::mutex.unlock(); return; } + QQuickContext2D::mutex.unlock(); - GLAcquireContext currentContext(m_context->glContext(), m_context->surface()); + GLAcquireContext currentContext(m_gl, m_surface); if (!m_tiledCanvas) { paintWithoutTiles(ccb); @@ -434,7 +443,7 @@ QSGTexture *QQuickContext2DFBOTexture::textureForNextFrame(QSGTexture *lastTextu } if (m_dirtyTexture) { - if (!m_context->glContext()) { + if (!m_gl) { // on a rendering thread, use the fbo directly... texture->setTextureId(m_fbo->texture()); } else { @@ -492,18 +501,18 @@ bool QQuickContext2DFBOTexture::doMultisampling() const void QQuickContext2DFBOTexture::grabImage(const QRectF& rf) { Q_ASSERT(rf.isValid()); - if (!m_fbo) { - m_context->setGrabbedImage(QImage()); - return; - } - - QImage grabbed; - { - GLAcquireContext ctx(m_context->glContext(), m_context->surface()); - grabbed = m_fbo->toImage().mirrored().copy(rf.toRect()); + QQuickContext2D::mutex.lock(); + if (m_context) { + if (!m_fbo) { + m_context->setGrabbedImage(QImage()); + } else { + QImage grabbed; + GLAcquireContext ctx(m_gl, m_surface); + grabbed = m_fbo->toImage().mirrored().copy(rf.toRect()); + m_context->setGrabbedImage(grabbed); + } } - - m_context->setGrabbedImage(grabbed); + QQuickContext2D::mutex.unlock(); } void QQuickContext2DFBOTexture::compositeTile(QQuickContext2DTile* tile) @@ -586,7 +595,7 @@ void QQuickContext2DFBOTexture::endPainting() if (m_multisampledFbo) QOpenGLFramebufferObject::blitFramebuffer(m_fbo, m_multisampledFbo); - if (m_context->glContext()) { + if (m_gl) { /* When rendering happens on the render thread, the fbo's texture is * used directly for display. If we are on the GUI thread or a * dedicated Canvas render thread, we need to decouple the FBO from @@ -641,9 +650,12 @@ QQuickContext2DTile* QQuickContext2DImageTexture::createTile() const void QQuickContext2DImageTexture::grabImage(const QRectF& rf) { Q_ASSERT(rf.isValid()); - Q_ASSERT(m_context); - QImage grabbed = m_displayImage.copy(rf.toRect()); - m_context->setGrabbedImage(grabbed); + QQuickContext2D::mutex.lock(); + if (m_context) { + QImage grabbed = m_displayImage.copy(rf.toRect()); + m_context->setGrabbedImage(grabbed); + } + QQuickContext2D::mutex.unlock(); } QSGTexture *QQuickContext2DImageTexture::textureForNextFrame(QSGTexture *last) diff --git a/src/quick/items/context2d/qquickcontext2dtexture_p.h b/src/quick/items/context2d/qquickcontext2dtexture_p.h index 186863c1aa..e41a4809e4 100644 --- a/src/quick/items/context2d/qquickcontext2dtexture_p.h +++ b/src/quick/items/context2d/qquickcontext2dtexture_p.h @@ -113,6 +113,11 @@ public: virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame) = 0; bool event(QEvent *e); + void initializeOpenGL(QOpenGLContext *gl, QOffscreenSurface *s) { + m_gl = gl; + m_surface = s; + } + Q_SIGNALS: void textureChanged(); @@ -135,7 +140,10 @@ protected: QRect createTiles(const QRect& window); QList m_tiles; - QQuickContext2D* m_context; + QQuickContext2D *m_context; + + QOpenGLContext *m_gl; + QSurface *m_surface; QQuickContext2D::State m_state; -- cgit v1.2.3