diff options
Diffstat (limited to 'src/declarative/items/qsgshadereffectsource.cpp')
-rw-r--r-- | src/declarative/items/qsgshadereffectsource.cpp | 157 |
1 files changed, 109 insertions, 48 deletions
diff --git a/src/declarative/items/qsgshadereffectsource.cpp b/src/declarative/items/qsgshadereffectsource.cpp index e05d20ed69..bb55af524b 100644 --- a/src/declarative/items/qsgshadereffectsource.cpp +++ b/src/declarative/items/qsgshadereffectsource.cpp @@ -46,7 +46,7 @@ #include <private/qsgadaptationlayer_p.h> #include <private/qsgrenderer_p.h> -#include "qglframebufferobject.h" +#include "qopenglframebufferobject.h" #include "qmath.h" #include <private/qsgtexture_p.h> @@ -54,6 +54,33 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(qmlFboOverlay, QML_FBO_OVERLAY) +class QSGShaderEffectSourceTextureProvider : public QSGTextureProvider +{ + Q_OBJECT +public: + QSGShaderEffectSourceTextureProvider() + : sourceTexture(0) + { + } + + QSGTexture *texture() const { + sourceTexture->setMipmapFiltering(mipmapFiltering); + sourceTexture->setFiltering(filtering); + sourceTexture->setHorizontalWrapMode(horizontalWrap); + sourceTexture->setVerticalWrapMode(verticalWrap); + return sourceTexture; + } + + QSGShaderEffectTexture *sourceTexture; + + QSGTexture::Filtering mipmapFiltering; + QSGTexture::Filtering filtering; + QSGTexture::WrapMode horizontalWrap; + QSGTexture::WrapMode verticalWrap; +}; +#include "qsgshadereffectsource.moc" + + QSGShaderEffectSourceNode::QSGShaderEffectSourceNode() { setFlag(UsePreprocess, true); @@ -76,6 +103,7 @@ QSGShaderEffectTexture::QSGShaderEffectTexture(QSGItem *shaderSource) #ifdef QSG_DEBUG_FBO_OVERLAY , m_debugOverlay(0) #endif + , m_context(0) , m_mipmap(false) , m_live(true) , m_recursive(false) @@ -96,6 +124,17 @@ QSGShaderEffectTexture::~QSGShaderEffectTexture() #endif } +void QSGShaderEffectTexture::scheduleForCleanup() +{ + if (m_context) + m_context->scheduleTextureForCleanup(this); + else { + // Never really been used, hence we can delete it right away.. + Q_ASSERT(!m_fbo); + delete this; + } +} + int QSGShaderEffectTexture::textureId() const { @@ -226,10 +265,12 @@ void QSGShaderEffectTexture::grab() return; } - QSGContext *context = QSGItemPrivate::get(m_shaderSource)->sceneGraphContext(); + if (!m_context) + m_context = QSGItemPrivate::get(m_shaderSource)->sceneGraphContext(); + Q_ASSERT(QSGItemPrivate::get(m_shaderSource)->sceneGraphContext() == m_context); if (!m_renderer) { - m_renderer = context->createRenderer(); + m_renderer = m_context->createRenderer(); connect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTexture()), Qt::DirectConnection); } m_renderer->setRootNode(static_cast<QSGRootNode *>(root)); @@ -248,27 +289,27 @@ void QSGShaderEffectTexture::grab() // Don't delete the FBO right away in case it is used recursively. deleteFboLater = true; delete m_secondaryFbo; - QGLFramebufferObjectFormat format; + QOpenGLFramebufferObjectFormat format; - format.setAttachment(QGLFramebufferObject::CombinedDepthStencil); + format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); format.setInternalTextureFormat(m_format); format.setSamples(8); - m_secondaryFbo = new QGLFramebufferObject(m_size, format); + m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); } else { - QGLFramebufferObjectFormat format; - format.setAttachment(QGLFramebufferObject::CombinedDepthStencil); + QOpenGLFramebufferObjectFormat format; + format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); format.setInternalTextureFormat(m_format); format.setMipmap(m_mipmap); if (m_recursive) { deleteFboLater = true; delete m_secondaryFbo; - m_secondaryFbo = new QGLFramebufferObject(m_size, format); + m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format); glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture()); updateBindOptions(true); } else { delete m_fbo; delete m_secondaryFbo; - m_fbo = new QGLFramebufferObject(m_size, format); + m_fbo = new QOpenGLFramebufferObject(m_size, format); m_secondaryFbo = 0; glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); updateBindOptions(true); @@ -281,7 +322,7 @@ void QSGShaderEffectTexture::grab() Q_ASSERT(m_fbo); Q_ASSERT(!m_multisampling); - m_secondaryFbo = new QGLFramebufferObject(m_size, m_fbo->format()); + m_secondaryFbo = new QOpenGLFramebufferObject(m_size, m_fbo->format()); glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture()); updateBindOptions(true); } @@ -293,7 +334,7 @@ void QSGShaderEffectTexture::grab() #ifdef QSG_DEBUG_FBO_OVERLAY if (qmlFboOverlay()) { if (!m_debugOverlay) - m_debugOverlay = context->createRectangleNode(); + m_debugOverlay = m_context->createRectangleNode(); m_debugOverlay->setRect(QRectF(0, 0, m_size.width(), m_size.height())); m_debugOverlay->setColor(QColor(0xff, 0x00, 0x80, 0x40)); m_debugOverlay->setPenColor(QColor()); @@ -306,7 +347,7 @@ void QSGShaderEffectTexture::grab() m_dirtyTexture = false; - const QGLContext *ctx = QGLContext::currentContext(); + QOpenGLContext *ctx = m_context->glContext(); m_renderer->setDeviceRect(m_size); m_renderer->setViewportRect(m_size); QRectF mirrored(m_rect.left(), m_rect.bottom(), m_rect.width(), -m_rect.height()); @@ -318,29 +359,29 @@ void QSGShaderEffectTexture::grab() if (deleteFboLater) { delete m_fbo; - QGLFramebufferObjectFormat format; + QOpenGLFramebufferObjectFormat format; format.setInternalTextureFormat(m_format); - format.setAttachment(QGLFramebufferObject::NoAttachment); + format.setAttachment(QOpenGLFramebufferObject::NoAttachment); format.setMipmap(m_mipmap); format.setSamples(0); - m_fbo = new QGLFramebufferObject(m_size, format); + m_fbo = new QOpenGLFramebufferObject(m_size, format); glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); updateBindOptions(true); } QRect r(QPoint(), m_size); - QGLFramebufferObject::blitFramebuffer(m_fbo, r, m_secondaryFbo, r); + QOpenGLFramebufferObject::blitFramebuffer(m_fbo, r, m_secondaryFbo, r); } else { if (m_recursive) { m_renderer->renderScene(QSGBindableFbo(m_secondaryFbo)); if (deleteFboLater) { delete m_fbo; - QGLFramebufferObjectFormat format; - format.setAttachment(QGLFramebufferObject::CombinedDepthStencil); + QOpenGLFramebufferObjectFormat format; + format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); format.setInternalTextureFormat(m_format); format.setMipmap(m_mipmap); - m_fbo = new QGLFramebufferObject(m_size, format); + m_fbo = new QOpenGLFramebufferObject(m_size, format); glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); updateBindOptions(true); } @@ -452,6 +493,7 @@ QImage QSGShaderEffectTexture::toImage() const QSGShaderEffectSource::QSGShaderEffectSource(QSGItem *parent) : QSGItem(parent) + , m_provider(0) , m_wrapMode(ClampToEdge) , m_sourceItem(0) , m_textureSize(0, 0) @@ -464,17 +506,36 @@ QSGShaderEffectSource::QSGShaderEffectSource(QSGItem *parent) { setFlag(ItemHasContents); m_texture = new QSGShaderEffectTexture(this); - connect(m_texture, SIGNAL(textureChanged()), this, SIGNAL(textureChanged()), Qt::DirectConnection); connect(m_texture, SIGNAL(textureChanged()), this, SLOT(update())); } QSGShaderEffectSource::~QSGShaderEffectSource() { - delete m_texture; + m_texture->scheduleForCleanup(); + + if (m_provider) + m_provider->deleteLater(); + if (m_sourceItem) QSGItemPrivate::get(m_sourceItem)->derefFromEffectItem(m_hideSource); } +QSGTextureProvider *QSGShaderEffectSource::textureProvider() const +{ + if (!m_provider) { + // Make sure it gets thread affinity on the rendering thread so deletion works properly.. + Q_ASSERT_X(QSGItemPrivate::get(this)->canvas + && QSGItemPrivate::get(this)->sceneGraphContext() + && QThread::currentThread() == QSGItemPrivate::get(this)->sceneGraphContext()->thread(), + "QSGShaderEffectSource::textureProvider", + "Cannot be used outside the GUI thread"); + const_cast<QSGShaderEffectSource *>(this)->m_provider = new QSGShaderEffectSourceTextureProvider(); + connect(m_texture, SIGNAL(textureChanged()), m_provider, SIGNAL(textureChanged()), Qt::DirectConnection); + m_provider->sourceTexture = m_texture; + } + return m_provider; +} + /*! \qmlproperty enumeration ShaderEffectSource::wrapMode @@ -761,17 +822,6 @@ static void get_wrap_mode(QSGShaderEffectSource::WrapMode mode, QSGTexture::Wrap } -QSGTexture *QSGShaderEffectSource::texture() const -{ - m_texture->setMipmapFiltering(m_mipmap ? QSGTexture::Linear : QSGTexture::None); - m_texture->setFiltering(QSGItemPrivate::get(this)->smooth ? QSGTexture::Linear : QSGTexture::Nearest); - QSGTexture::WrapMode h, v; - get_wrap_mode(m_wrapMode, &h, &v); - m_texture->setHorizontalWrapMode(h); - m_texture->setVerticalWrapMode(v); - return m_texture; -} - QSGNode *QSGShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) { if (!m_sourceItem || m_sourceItem->width() == 0 || m_sourceItem->height() == 0) { @@ -779,19 +829,7 @@ QSGNode *QSGShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaintNod return 0; } - QSGShaderEffectSourceNode *node = static_cast<QSGShaderEffectSourceNode *>(oldNode); - if (!node) { - node = new QSGShaderEffectSourceNode; - node->setTexture(m_texture); - connect(m_texture, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()), Qt::DirectConnection); - } - - // If live and recursive, update continuously. - if (m_live && m_recursive) - node->markDirty(QSGNode::DirtyMaterial); - QSGShaderEffectTexture *tex = qobject_cast<QSGShaderEffectTexture *>(m_texture); - tex->setLive(m_live); tex->setItem(QSGItemPrivate::get(m_sourceItem)->itemNode()); QRectF sourceRect = m_sourceRect.width() == 0 || m_sourceRect.height() == 0 @@ -823,12 +861,35 @@ QSGNode *QSGShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaintNod ? QSGTexture::Linear : QSGTexture::Nearest; QSGTexture::Filtering mmFiltering = m_mipmap ? filtering : QSGTexture::None; - node->setMipmapFiltering(mmFiltering); - node->setFiltering(filtering); - QSGTexture::WrapMode hWrap, vWrap; get_wrap_mode(m_wrapMode, &hWrap, &vWrap); + if (m_provider) { + m_provider->mipmapFiltering = mmFiltering; + m_provider->filtering = filtering; + m_provider->horizontalWrap = hWrap; + m_provider->verticalWrap = vWrap; + } + + // Don't create the paint node if we're not spanning any area + if (width() == 0 || height() == 0) { + delete oldNode; + return 0; + } + + QSGShaderEffectSourceNode *node = static_cast<QSGShaderEffectSourceNode *>(oldNode); + if (!node) { + node = new QSGShaderEffectSourceNode; + node->setTexture(m_texture); + connect(m_texture, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()), Qt::DirectConnection); + } + + // If live and recursive, update continuously. + if (m_live && m_recursive) + node->markDirty(QSGNode::DirtyMaterial); + + node->setMipmapFiltering(mmFiltering); + node->setFiltering(filtering); node->setHorizontalWrapMode(hWrap); node->setVerticalWrapMode(vWrap); node->setTargetRect(QRectF(0, 0, width(), height())); |