diff options
Diffstat (limited to 'src/quick/items/qquickshadereffectsource.cpp')
-rw-r--r-- | src/quick/items/qquickshadereffectsource.cpp | 108 |
1 files changed, 83 insertions, 25 deletions
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp index 33776be712..c55b1ca7f5 100644 --- a/src/quick/items/qquickshadereffectsource.cpp +++ b/src/quick/items/qquickshadereffectsource.cpp @@ -54,6 +54,39 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(qmlFboOverlay, QML_FBO_OVERLAY) +namespace +{ + class BindableFbo : public QSGBindable + { + public: + BindableFbo(QOpenGLFramebufferObject *fbo, QSGDepthStencilBuffer *depthStencil); + virtual ~BindableFbo(); + virtual void bind() const; + private: + QOpenGLFramebufferObject *m_fbo; + QSGDepthStencilBuffer *m_depthStencil; + }; + + BindableFbo::BindableFbo(QOpenGLFramebufferObject *fbo, QSGDepthStencilBuffer *depthStencil) + : m_fbo(fbo) + , m_depthStencil(depthStencil) + { + } + + BindableFbo::~BindableFbo() + { + if (m_depthStencil) + m_depthStencil->detach(); + } + + void BindableFbo::bind() const + { + m_fbo->bind(); + if (m_depthStencil) + m_depthStencil->attach(); + } +} + class QQuickShaderEffectSourceTextureProvider : public QSGTextureProvider { Q_OBJECT @@ -239,6 +272,7 @@ void QQuickShaderEffectTexture::grab() delete m_fbo; delete m_secondaryFbo; m_fbo = m_secondaryFbo = 0; + m_depthStencilBuffer.clear(); m_dirtyTexture = false; if (m_grab) emit scheduledUpdateCompleted(); @@ -272,13 +306,12 @@ void QQuickShaderEffectTexture::grab() delete m_secondaryFbo; QOpenGLFramebufferObjectFormat format; - format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); format.setInternalTextureFormat(m_format); format.setSamples(8); m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); + m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo); } else { QOpenGLFramebufferObjectFormat format; - format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); format.setInternalTextureFormat(m_format); format.setMipmap(m_mipmap); if (m_recursive) { @@ -287,6 +320,7 @@ void QQuickShaderEffectTexture::grab() m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture()); updateBindOptions(true); + m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo); } else { delete m_fbo; delete m_secondaryFbo; @@ -294,6 +328,7 @@ void QQuickShaderEffectTexture::grab() m_secondaryFbo = 0; glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); updateBindOptions(true); + m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_fbo); } } } @@ -336,7 +371,7 @@ void QQuickShaderEffectTexture::grab() m_renderer->setClearColor(Qt::transparent); if (m_multisampling) { - m_renderer->renderScene(QSGBindableFbo(m_secondaryFbo)); + m_renderer->renderScene(BindableFbo(m_secondaryFbo, m_depthStencilBuffer.data())); if (deleteFboLater) { delete m_fbo; @@ -354,7 +389,7 @@ void QQuickShaderEffectTexture::grab() QOpenGLFramebufferObject::blitFramebuffer(m_fbo, r, m_secondaryFbo, r); } else { if (m_recursive) { - m_renderer->renderScene(QSGBindableFbo(m_secondaryFbo)); + m_renderer->renderScene(BindableFbo(m_secondaryFbo, m_depthStencilBuffer.data())); if (deleteFboLater) { delete m_fbo; @@ -368,7 +403,7 @@ void QQuickShaderEffectTexture::grab() } qSwap(m_fbo, m_secondaryFbo); } else { - m_renderer->renderScene(QSGBindableFbo(m_fbo)); + m_renderer->renderScene(BindableFbo(m_fbo, m_depthStencilBuffer.data())); } } @@ -504,6 +539,8 @@ QQuickShaderEffectSource::~QQuickShaderEffectSource() QQuickItemPrivate *sd = QQuickItemPrivate::get(m_sourceItem); sd->removeItemChangeListener(this, QQuickItemPrivate::Geometry); sd->derefFromEffectItem(m_hideSource); + if (canvas()) + sd->derefCanvas(); } } @@ -599,6 +636,9 @@ void QQuickShaderEffectSource::setSourceItem(QQuickItem *item) QQuickItemPrivate *d = QQuickItemPrivate::get(m_sourceItem); d->derefFromEffectItem(m_hideSource); d->removeItemChangeListener(this, QQuickItemPrivate::Geometry); + disconnect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*))); + if (canvas()) + d->derefCanvas(); } m_sourceItem = item; @@ -608,18 +648,25 @@ void QQuickShaderEffectSource::setSourceItem(QQuickItem *item) // parent, but if the source item is "inline" rather than a reference -- i.e. // "sourceItem: Item { }" instead of "sourceItem: foo" -- it will not get a parent. // In those cases, 'item' should get the canvas from 'this'. - if (!d->parentItem && canvas() && !d->canvas) { - QQuickItemPrivate::InitializationState initState; - initState.clear(); - d->initCanvas(&initState, canvas()); - } + if (canvas()) + d->refCanvas(canvas()); d->refFromEffectItem(m_hideSource); d->addItemChangeListener(this, QQuickItemPrivate::Geometry); + connect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*))); } update(); emit sourceItemChanged(); } +void QQuickShaderEffectSource::sourceItemDestroyed(QObject *item) +{ + Q_ASSERT(item == m_sourceItem); + m_sourceItem = 0; + update(); + emit sourceItemChanged(); +} + + /*! \qmlproperty rect ShaderEffectSource::sourceRect @@ -841,22 +888,35 @@ static void get_wrap_mode(QQuickShaderEffectSource::WrapMode mode, QSGTexture::W } +void QQuickShaderEffectSource::releaseResources() +{ + if (m_texture) { + m_texture->deleteLater(); + m_texture = 0; + } + if (m_provider) { + m_provider->deleteLater(); + m_provider = 0; + } +} + QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) { if (!m_sourceItem || m_sourceItem->width() == 0 || m_sourceItem->height() == 0) { + if (m_texture) + m_texture->setItem(0); delete oldNode; return 0; } ensureTexture(); - QQuickShaderEffectTexture *tex = qobject_cast<QQuickShaderEffectTexture *>(m_texture); - tex->setLive(m_live); - tex->setItem(QQuickItemPrivate::get(m_sourceItem)->itemNode()); + m_texture->setLive(m_live); + m_texture->setItem(QQuickItemPrivate::get(m_sourceItem)->itemNode()); QRectF sourceRect = m_sourceRect.width() == 0 || m_sourceRect.height() == 0 ? QRectF(0, 0, m_sourceItem->width(), m_sourceItem->height()) : m_sourceRect; - tex->setRect(sourceRect); + m_texture->setRect(sourceRect); QSize textureSize = m_textureSize.isEmpty() ? QSize(qCeil(qAbs(sourceRect.width())), qCeil(qAbs(sourceRect.height()))) : m_textureSize; @@ -869,13 +929,13 @@ QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaint while (textureSize.height() < minTextureSize.height()) textureSize.rheight() *= 2; - tex->setSize(textureSize); - tex->setRecursive(m_recursive); - tex->setFormat(GLenum(m_format)); - tex->setHasMipmaps(m_mipmap); + m_texture->setSize(textureSize); + m_texture->setRecursive(m_recursive); + m_texture->setFormat(GLenum(m_format)); + m_texture->setHasMipmaps(m_mipmap); if (m_grab) - tex->scheduleUpdate(); + m_texture->scheduleUpdate(); m_grab = false; QSGTexture::Filtering filtering = QQuickItemPrivate::get(this)->smooth @@ -924,12 +984,10 @@ void QQuickShaderEffectSource::itemChange(ItemChange change, const ItemChangeDat { if (change == QQuickItem::ItemSceneChange && m_sourceItem) { // See comment in QQuickShaderEffectSource::setSourceItem(). - QQuickItemPrivate *d = QQuickItemPrivate::get(m_sourceItem); - if (!d->parentItem && value.canvas != d->canvas) { - QQuickItemPrivate::InitializationState initState; - initState.clear(); - d->initCanvas(&initState, value.canvas); - } + if (value.canvas) + QQuickItemPrivate::get(m_sourceItem)->refCanvas(value.canvas); + else + QQuickItemPrivate::get(m_sourceItem)->derefCanvas(); } QQuickItem::itemChange(change, value); } |