1 /****************************************************************************
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquickshadereffectsource_p.h"
44 #include "qquickitem_p.h"
45 #include "qquickcanvas_p.h"
46 #include <private/qsgadaptationlayer_p.h>
47 #include <private/qsgrenderer_p.h>
49 #include "qopenglframebufferobject.h"
51 #include <private/qsgtexture_p.h>
55 DEFINE_BOOL_CONFIG_OPTION(qmlFboOverlay, QML_FBO_OVERLAY)
57 class QQuickShaderEffectSourceTextureProvider : public QSGTextureProvider
61 QQuickShaderEffectSourceTextureProvider()
66 QSGTexture *texture() const {
67 sourceTexture->setMipmapFiltering(mipmapFiltering);
68 sourceTexture->setFiltering(filtering);
69 sourceTexture->setHorizontalWrapMode(horizontalWrap);
70 sourceTexture->setVerticalWrapMode(verticalWrap);
74 QQuickShaderEffectTexture *sourceTexture;
76 QSGTexture::Filtering mipmapFiltering;
77 QSGTexture::Filtering filtering;
78 QSGTexture::WrapMode horizontalWrap;
79 QSGTexture::WrapMode verticalWrap;
81 #include "qquickshadereffectsource.moc"
84 QQuickShaderEffectSourceNode::QQuickShaderEffectSourceNode()
86 setFlag(UsePreprocess, true);
89 void QQuickShaderEffectSourceNode::markDirtyTexture()
91 markDirty(DirtyMaterial);
95 QQuickShaderEffectTexture::QQuickShaderEffectTexture(QQuickItem *shaderSource)
99 , m_shaderSource(shaderSource)
103 #ifdef QSG_DEBUG_FBO_OVERLAY
106 , m_context(QQuickItemPrivate::get(shaderSource)->sceneGraphContext())
110 , m_dirtyTexture(true)
111 , m_multisamplingSupportChecked(false)
112 , m_multisampling(false)
117 QQuickShaderEffectTexture::~QQuickShaderEffectTexture()
121 delete m_secondaryFbo;
122 #ifdef QSG_DEBUG_FBO_OVERLAY
123 delete m_debugOverlay;
127 int QQuickShaderEffectTexture::textureId() const
129 return m_fbo ? m_fbo->texture() : 0;
132 bool QQuickShaderEffectTexture::hasAlphaChannel() const
134 return m_format != GL_RGB;
137 bool QQuickShaderEffectTexture::hasMipmaps() const
143 void QQuickShaderEffectTexture::bind()
146 if (!m_recursive && m_fbo && ((m_multisampling && m_secondaryFbo->isBound()) || m_fbo->isBound()))
147 qWarning("ShaderEffectSource: \'recursive\' must be set to true when rendering recursively.");
149 glBindTexture(GL_TEXTURE_2D, m_fbo ? m_fbo->texture() : 0);
153 bool QQuickShaderEffectTexture::updateTexture()
155 if ((m_live || m_grab) && m_dirtyTexture) {
163 void QQuickShaderEffectTexture::setHasMipmaps(bool mipmap)
165 if (mipmap == m_mipmap)
168 if (m_mipmap && m_fbo && !m_fbo->format().mipmap())
173 void QQuickShaderEffectTexture::setItem(QSGNode *item)
181 void QQuickShaderEffectTexture::setRect(const QRectF &rect)
189 void QQuickShaderEffectTexture::setSize(const QSize &size)
197 void QQuickShaderEffectTexture::setFormat(GLenum format)
199 if (format == m_format)
205 void QQuickShaderEffectTexture::setLive(bool live)
213 void QQuickShaderEffectTexture::scheduleUpdate()
219 emit textureChanged();
222 void QQuickShaderEffectTexture::setRecursive(bool recursive)
224 m_recursive = recursive;
227 void QQuickShaderEffectTexture::markDirtyTexture()
229 m_dirtyTexture = true;
230 if (m_live || m_grab)
231 emit textureChanged();
234 void QQuickShaderEffectTexture::grab()
236 if (!m_item || m_size.isNull()) {
238 delete m_secondaryFbo;
239 m_fbo = m_secondaryFbo = 0;
240 m_dirtyTexture = false;
243 QSGNode *root = m_item;
244 while (root->firstChild() && root->type() != QSGNode::RootNodeType)
245 root = root->firstChild();
246 if (root->type() != QSGNode::RootNodeType)
249 if (m_size.isEmpty()) {
251 delete m_secondaryFbo;
252 m_secondaryFbo = m_fbo = 0;
257 m_renderer = m_context->createRenderer();
258 connect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTexture()), Qt::DirectConnection);
260 m_renderer->setRootNode(static_cast<QSGRootNode *>(root));
262 bool deleteFboLater = false;
263 if (!m_fbo || m_fbo->size() != m_size || m_fbo->format().internalTextureFormat() != m_format
264 || (!m_fbo->format().mipmap() && m_mipmap))
266 if (!m_multisamplingSupportChecked) {
267 QList<QByteArray> extensions = QByteArray((const char *)glGetString(GL_EXTENSIONS)).split(' ');
268 m_multisampling = extensions.contains("GL_EXT_framebuffer_multisample")
269 && extensions.contains("GL_EXT_framebuffer_blit");
270 m_multisamplingSupportChecked = true;
272 if (m_multisampling) {
273 // Don't delete the FBO right away in case it is used recursively.
274 deleteFboLater = true;
275 delete m_secondaryFbo;
276 QOpenGLFramebufferObjectFormat format;
278 format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
279 format.setInternalTextureFormat(m_format);
280 format.setSamples(8);
281 m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format);
283 QOpenGLFramebufferObjectFormat format;
284 format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
285 format.setInternalTextureFormat(m_format);
286 format.setMipmap(m_mipmap);
288 deleteFboLater = true;
289 delete m_secondaryFbo;
290 m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format);
291 glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture());
292 updateBindOptions(true);
295 delete m_secondaryFbo;
296 m_fbo = new QOpenGLFramebufferObject(m_size, format);
298 glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
299 updateBindOptions(true);
304 if (m_recursive && !m_secondaryFbo) {
305 // m_fbo already created, m_recursive was just set.
307 Q_ASSERT(!m_multisampling);
309 m_secondaryFbo = new QOpenGLFramebufferObject(m_size, m_fbo->format());
310 glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture());
311 updateBindOptions(true);
315 root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip and opacity update.
316 m_renderer->nodeChanged(root, QSGNode::DirtyForceUpdate); // Force render list update.
318 #ifdef QSG_DEBUG_FBO_OVERLAY
319 if (qmlFboOverlay()) {
321 m_debugOverlay = m_context->createRectangleNode();
322 m_debugOverlay->setRect(QRectF(0, 0, m_size.width(), m_size.height()));
323 m_debugOverlay->setColor(QColor(0xff, 0x00, 0x80, 0x40));
324 m_debugOverlay->setPenColor(QColor());
325 m_debugOverlay->setPenWidth(0);
326 m_debugOverlay->setRadius(0);
327 m_debugOverlay->update();
328 root->appendChildNode(m_debugOverlay);
332 m_dirtyTexture = false;
334 QOpenGLContext *ctx = m_context->glContext();
335 m_renderer->setDeviceRect(m_size);
336 m_renderer->setViewportRect(m_size);
337 QRectF mirrored(m_rect.left(), m_rect.bottom(), m_rect.width(), -m_rect.height());
338 m_renderer->setProjectionMatrixToRect(mirrored);
339 m_renderer->setClearColor(Qt::transparent);
341 if (m_multisampling) {
342 m_renderer->renderScene(QSGBindableFbo(m_secondaryFbo));
344 if (deleteFboLater) {
346 QOpenGLFramebufferObjectFormat format;
347 format.setInternalTextureFormat(m_format);
348 format.setAttachment(QOpenGLFramebufferObject::NoAttachment);
349 format.setMipmap(m_mipmap);
350 format.setSamples(0);
351 m_fbo = new QOpenGLFramebufferObject(m_size, format);
352 glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
353 updateBindOptions(true);
356 QRect r(QPoint(), m_size);
357 QOpenGLFramebufferObject::blitFramebuffer(m_fbo, r, m_secondaryFbo, r);
360 m_renderer->renderScene(QSGBindableFbo(m_secondaryFbo));
362 if (deleteFboLater) {
364 QOpenGLFramebufferObjectFormat format;
365 format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
366 format.setInternalTextureFormat(m_format);
367 format.setMipmap(m_mipmap);
368 m_fbo = new QOpenGLFramebufferObject(m_size, format);
369 glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
370 updateBindOptions(true);
372 qSwap(m_fbo, m_secondaryFbo);
374 m_renderer->renderScene(QSGBindableFbo(m_fbo));
379 glBindTexture(GL_TEXTURE_2D, textureId());
380 ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D);
383 root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip, opacity and render list update.
385 #ifdef QSG_DEBUG_FBO_OVERLAY
387 root->removeChildNode(m_debugOverlay);
390 markDirtyTexture(); // Continuously update if 'live' and 'recursive'.
393 QImage QQuickShaderEffectTexture::toImage() const
396 return m_fbo->toImage();
402 \qmlclass ShaderEffectSource QQuickShaderEffectSource
404 \ingroup qml-basic-visual-elements
405 \brief The ShaderEffectSource element renders a QML element into a texture
409 The ShaderEffectSource element renders \l sourceItem into a texture and
410 displays it in the scene. \l sourceItem is drawn into the texture as though
411 it was a fully opaque root element. Thus \l sourceItem itself can be
412 invisible, but still appear in the texture.
414 ShaderEffectSource can be used as:
416 \o a texture source in a \l ShaderEffect.
417 This allows you to apply custom shader effects to any QML element.
418 \o a cache for a complex element.
419 The complex element can be rendered once into the texture, which can
420 then be animated freely without the need to render the complex element
423 ShaderEffectSource allows you to apply an opacity to elements as a group
424 rather than each element individually.
429 \o \image declarative-shadereffectsource.png
437 GradientStop { position: 0; color: "white" }
438 GradientStop { position: 1; color: "black" }
444 width: 100; height: 100
445 Rectangle { x: 5; y: 5; width: 60; height: 60; color: "red" }
446 Rectangle { x: 20; y: 20; width: 60; height: 60; color: "orange" }
447 Rectangle { x: 35; y: 35; width: 60; height: 60; color: "yellow" }
450 width: 100; height: 100
459 The ShaderEffectSource element does not redirect any mouse or keyboard
460 input to \l sourceItem. If you hide the \l sourceItem by setting
461 \l{Item::visible}{visible} to false or \l{Item::opacity}{opacity} to zero,
462 it will no longer react to input. In cases where the ShaderEffectSource is
463 meant to replace the \l sourceItem, you typically want to hide the
464 \l sourceItem while still handling input. For this, you can use
465 the \l hideSource property.
467 \note If \l sourceItem is a \l Rectangle with border, by default half the
468 border width falls outside the texture. To get the whole border, you can
469 extend the \l sourceRect.
471 \warning In most cases, using a ShaderEffectSource will decrease
472 performance, and in all cases, it will increase video memory usage.
473 Rendering through a ShaderEffectSource might also lead to lower quality
474 since some OpenGL implementations support multisampled backbuffer,
475 but not multisampled framebuffer objects.
478 QQuickShaderEffectSource::QQuickShaderEffectSource(QQuickItem *parent)
482 , m_wrapMode(ClampToEdge)
484 , m_textureSize(0, 0)
487 , m_hideSource(false)
492 setFlag(ItemHasContents);
495 QQuickShaderEffectSource::~QQuickShaderEffectSource()
498 m_texture->deleteLater();
501 m_provider->deleteLater();
504 QQuickItemPrivate::get(m_sourceItem)->derefFromEffectItem(m_hideSource);
507 void QQuickShaderEffectSource::ensureTexture()
512 Q_ASSERT_X(QQuickItemPrivate::get(this)->canvas
513 && QQuickItemPrivate::get(this)->sceneGraphContext()
514 && QThread::currentThread() == QQuickItemPrivate::get(this)->sceneGraphContext()->thread(),
515 "QQuickShaderEffectSource::ensureTexture",
516 "Cannot be used outside the rendering thread");
518 m_texture = new QQuickShaderEffectTexture(this);
519 connect(m_texture, SIGNAL(textureChanged()), this, SLOT(update()));
522 QSGTextureProvider *QQuickShaderEffectSource::textureProvider() const
525 // Make sure it gets thread affinity on the rendering thread so deletion works properly..
526 Q_ASSERT_X(QQuickItemPrivate::get(this)->canvas
527 && QQuickItemPrivate::get(this)->sceneGraphContext()
528 && QThread::currentThread() == QQuickItemPrivate::get(this)->sceneGraphContext()->thread(),
529 "QQuickShaderEffectSource::textureProvider",
530 "Cannot be used outside the rendering thread");
531 const_cast<QQuickShaderEffectSource *>(this)->m_provider = new QQuickShaderEffectSourceTextureProvider();
533 const_cast<QQuickShaderEffectSource *>(this)->ensureTexture();
534 connect(m_texture, SIGNAL(textureChanged()), m_provider, SIGNAL(textureChanged()), Qt::DirectConnection);
535 m_provider->sourceTexture = m_texture;
541 \qmlproperty enumeration ShaderEffectSource::wrapMode
543 This property defines the OpenGL wrap modes associated with the texture.
544 Modifying this property makes most sense when the element is used as a
545 source texture of a \l ShaderEffect.
548 \o ShaderEffectSource.ClampToEdge - GL_CLAMP_TO_EDGE both horizontally and vertically
549 \o ShaderEffectSource.RepeatHorizontally - GL_REPEAT horizontally, GL_CLAMP_TO_EDGE vertically
550 \o ShaderEffectSource.RepeatVertically - GL_CLAMP_TO_EDGE horizontally, GL_REPEAT vertically
551 \o ShaderEffectSource.Repeat - GL_REPEAT both horizontally and vertically
554 \note Some OpenGL ES 2 implementations do not support the GL_REPEAT
555 wrap mode with non-power-of-two textures.
558 QQuickShaderEffectSource::WrapMode QQuickShaderEffectSource::wrapMode() const
563 void QQuickShaderEffectSource::setWrapMode(WrapMode mode)
565 if (mode == m_wrapMode)
569 emit wrapModeChanged();
573 \qmlproperty Item ShaderEffectSource::sourceItem
575 This property holds the element to be rendered into the texture.
578 QQuickItem *QQuickShaderEffectSource::sourceItem() const
583 void QQuickShaderEffectSource::setSourceItem(QQuickItem *item)
585 if (item == m_sourceItem)
588 QQuickItemPrivate::get(m_sourceItem)->derefFromEffectItem(m_hideSource);
591 // TODO: Find better solution.
592 // 'm_sourceItem' needs a canvas to get a scenegraph node.
593 // The easiest way to make sure it gets a canvas is to
594 // make it a part of the same item tree as 'this'.
595 if (m_sourceItem->parentItem() == 0) {
596 m_sourceItem->setParentItem(this);
597 m_sourceItem->setVisible(false);
599 QQuickItemPrivate::get(m_sourceItem)->refFromEffectItem(m_hideSource);
602 emit sourceItemChanged();
606 \qmlproperty rect ShaderEffectSource::sourceRect
608 This property defines which rectangular area of the \l sourceItem to
609 render into the texture. The source rectangle can be larger than
610 \l sourceItem itself. If the rectangle is null, which is the default,
611 the whole \l sourceItem is rendered to texture.
614 QRectF QQuickShaderEffectSource::sourceRect() const
619 void QQuickShaderEffectSource::setSourceRect(const QRectF &rect)
621 if (rect == m_sourceRect)
625 emit sourceRectChanged();
629 \qmlproperty size ShaderEffectSource::textureSize
631 This property holds the requested size of the texture. If it is empty,
632 which is the default, the size of the source rectangle is used.
634 \note Some platforms have a limit on how small framebuffer objects can be,
635 which means the actual texture size might be larger than the requested
639 QSize QQuickShaderEffectSource::textureSize() const
641 return m_textureSize;
644 void QQuickShaderEffectSource::setTextureSize(const QSize &size)
646 if (size == m_textureSize)
648 m_textureSize = size;
650 emit textureSizeChanged();
654 \qmlproperty enumeration ShaderEffectSource::format
656 This property defines the internal OpenGL format of the texture.
657 Modifying this property makes most sense when the element is used as a
658 source texture of a \l ShaderEffect. Depending on the OpenGL
659 implementation, this property might allow you to save some texture memory.
662 \o ShaderEffectSource.Alpha - GL_ALPHA
663 \o ShaderEffectSource.RGB - GL_RGB
664 \o ShaderEffectSource.RGBA - GL_RGBA
667 \note Some OpenGL implementations do not support the GL_ALPHA format.
670 QQuickShaderEffectSource::Format QQuickShaderEffectSource::format() const
675 void QQuickShaderEffectSource::setFormat(QQuickShaderEffectSource::Format format)
677 if (format == m_format)
681 emit formatChanged();
685 \qmlproperty bool ShaderEffectSource::live
687 If this property is true, the texture is updated whenever the
688 \l sourceItem changes. Otherwise, it will be a frozen image of the
689 \l sourceItem. The property is true by default.
692 bool QQuickShaderEffectSource::live() const
697 void QQuickShaderEffectSource::setLive(bool live)
707 \qmlproperty bool ShaderEffectSource::hideSource
709 If this property is true, the \l sourceItem is hidden, though it will still
710 be rendered into the texture. As opposed to hiding the \l sourceItem by
711 setting \l{Item::visible}{visible} to false, setting this property to true
712 will not prevent mouse or keyboard input from reaching \l sourceItem.
713 The property is useful when the ShaderEffectSource is anchored on top of,
714 and meant to replace the \l sourceItem.
717 bool QQuickShaderEffectSource::hideSource() const
722 void QQuickShaderEffectSource::setHideSource(bool hide)
724 if (hide == m_hideSource)
727 QQuickItemPrivate::get(m_sourceItem)->refFromEffectItem(hide);
728 QQuickItemPrivate::get(m_sourceItem)->derefFromEffectItem(m_hideSource);
732 emit hideSourceChanged();
736 \qmlproperty bool ShaderEffectSource::mipmap
738 If this property is true, mipmaps are generated for the texture.
740 \note Some OpenGL ES 2 implementations do not support mipmapping of
741 non-power-of-two textures.
744 bool QQuickShaderEffectSource::mipmap() const
749 void QQuickShaderEffectSource::setMipmap(bool enabled)
751 if (enabled == m_mipmap)
755 emit mipmapChanged();
759 \qmlproperty bool ShaderEffectSource::recursive
761 Set this property to true if the ShaderEffectSource has a dependency on
762 itself. ShaderEffectSources form a dependency chain, where one
763 ShaderEffectSource can be part of the \l sourceItem of another.
764 If there is a loop in this chain, a ShaderEffectSource could end up trying
765 to render into the same texture it is using as source, which is not allowed
766 by OpenGL. When this property is set to true, an extra texture is allocated
767 so that ShaderEffectSource can keep a copy of the texture from the previous
768 frame. It can then render into one texture and use the texture from the
769 previous frame as source.
771 Setting both this property and \l live to true will cause the scene graph
772 to render continuously. Since the ShaderEffectSource depends on itself,
773 updating it means that it immediately becomes dirty again.
776 bool QQuickShaderEffectSource::recursive() const
781 void QQuickShaderEffectSource::setRecursive(bool enabled)
783 if (enabled == m_recursive)
785 m_recursive = enabled;
786 emit recursiveChanged();
790 \qmlmethod ShaderEffectSource::scheduleUpdate()
792 Schedules a re-rendering of the texture for the next frame.
793 Use this to update the texture when \l live is false.
796 void QQuickShaderEffectSource::scheduleUpdate()
804 static void get_wrap_mode(QQuickShaderEffectSource::WrapMode mode, QSGTexture::WrapMode *hWrap, QSGTexture::WrapMode *vWrap)
807 case QQuickShaderEffectSource::RepeatHorizontally:
808 *hWrap = QSGTexture::Repeat;
809 *vWrap = QSGTexture::ClampToEdge;
811 case QQuickShaderEffectSource::RepeatVertically:
812 *vWrap = QSGTexture::Repeat;
813 *hWrap = QSGTexture::ClampToEdge;
815 case QQuickShaderEffectSource::Repeat:
816 *hWrap = *vWrap = QSGTexture::Repeat;
819 // QQuickShaderEffectSource::ClampToEdge
820 *hWrap = *vWrap = QSGTexture::ClampToEdge;
826 QSGNode *QQuickShaderEffectSource::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
828 if (!m_sourceItem || m_sourceItem->width() == 0 || m_sourceItem->height() == 0) {
835 QQuickShaderEffectTexture *tex = qobject_cast<QQuickShaderEffectTexture *>(m_texture);
836 tex->setLive(m_live);
837 tex->setItem(QQuickItemPrivate::get(m_sourceItem)->itemNode());
838 QRectF sourceRect = m_sourceRect.width() == 0 || m_sourceRect.height() == 0
839 ? QRectF(0, 0, m_sourceItem->width(), m_sourceItem->height())
841 tex->setRect(sourceRect);
842 QSize textureSize = m_textureSize.isEmpty()
843 ? QSize(qCeil(qAbs(sourceRect.width())), qCeil(qAbs(sourceRect.height())))
845 Q_ASSERT(!textureSize.isEmpty());
846 QQuickItemPrivate *d = static_cast<QQuickItemPrivate *>(QObjectPrivate::get(this));
847 const QSize minTextureSize = d->sceneGraphContext()->minimumFBOSize();
848 // Keep power-of-two by doubling the size.
849 while (textureSize.width() < minTextureSize.width())
850 textureSize.rwidth() *= 2;
851 while (textureSize.height() < minTextureSize.height())
852 textureSize.rheight() *= 2;
854 tex->setSize(textureSize);
855 tex->setRecursive(m_recursive);
856 tex->setFormat(GLenum(m_format));
857 tex->setHasMipmaps(m_mipmap);
860 tex->scheduleUpdate();
863 QSGTexture::Filtering filtering = QQuickItemPrivate::get(this)->smooth
865 : QSGTexture::Nearest;
866 QSGTexture::Filtering mmFiltering = m_mipmap ? filtering : QSGTexture::None;
867 QSGTexture::WrapMode hWrap, vWrap;
868 get_wrap_mode(m_wrapMode, &hWrap, &vWrap);
871 m_provider->mipmapFiltering = mmFiltering;
872 m_provider->filtering = filtering;
873 m_provider->horizontalWrap = hWrap;
874 m_provider->verticalWrap = vWrap;
877 // Don't create the paint node if we're not spanning any area
878 if (width() == 0 || height() == 0) {
883 QQuickShaderEffectSourceNode *node = static_cast<QQuickShaderEffectSourceNode *>(oldNode);
885 node = new QQuickShaderEffectSourceNode;
886 node->setTexture(m_texture);
887 connect(m_texture, SIGNAL(textureChanged()), node, SLOT(markDirtyTexture()), Qt::DirectConnection);
890 // If live and recursive, update continuously.
891 if (m_live && m_recursive)
892 node->markDirty(QSGNode::DirtyMaterial);
894 node->setMipmapFiltering(mmFiltering);
895 node->setFiltering(filtering);
896 node->setHorizontalWrapMode(hWrap);
897 node->setVerticalWrapMode(vWrap);
898 node->setTargetRect(QRectF(0, 0, width(), height()));
899 node->setSourceRect(QRectF(0, 0, 1, 1));