diff --git a/src/quick/designer/designersupport.cpp b/src/quick/designer/designersupport.cpp
index 82f796361b3ef51357c0d11b0a9a314c1ae2256d..a57c1ae56958ab22b85f42e7fa740bb6239d31cd 100644
--- a/src/quick/designer/designersupport.cpp
+++ b/src/quick/designer/designersupport.cpp
@@ -65,10 +65,10 @@ DesignerSupport::DesignerSupport()
 
 DesignerSupport::~DesignerSupport()
 {
-    QHash<QQuickItem*, QQuickShaderEffectTexture*>::iterator iterator;
+    QHash<QQuickItem*, QSGLayer*>::iterator iterator;
 
     for (iterator = m_itemTextureHash.begin(); iterator != m_itemTextureHash.end(); ++iterator) {
-        QQuickShaderEffectTexture *texture = iterator.value();
+        QSGLayer *texture = iterator.value();
         QQuickItem *item = iterator.key();
         QQuickItemPrivate::get(item)->derefFromEffectItem(true);
         delete texture;
@@ -86,7 +86,8 @@ void DesignerSupport::refFromEffectItem(QQuickItem *referencedItem, bool hide)
     Q_ASSERT(QQuickItemPrivate::get(referencedItem)->rootNode());
 
     if (!m_itemTextureHash.contains(referencedItem)) {
-        QQuickShaderEffectTexture *texture = new QQuickShaderEffectTexture(referencedItem);
+        QSGRenderContext *rc = QQuickWindowPrivate::get(referencedItem->window())->context;
+        QSGLayer *texture = rc->sceneGraphContext()->createLayer(rc);
 
         texture->setLive(true);
         texture->setItem(QQuickItemPrivate::get(referencedItem)->rootNode());
@@ -123,7 +124,7 @@ QImage DesignerSupport::renderImageForItem(QQuickItem *referencedItem, const QRe
         return QImage();
     }
 
-    QQuickShaderEffectTexture *renderTexture = m_itemTextureHash.value(referencedItem);
+    QSGLayer *renderTexture = m_itemTextureHash.value(referencedItem);
 
     Q_ASSERT(renderTexture);
     if (renderTexture == 0)
diff --git a/src/quick/designer/designersupport.h b/src/quick/designer/designersupport.h
index 41458ae3d6d54b94a2a297c47c8295b94ccac243..8dfb4af1678c1dfa643dfcfadd398562d3f25191 100644
--- a/src/quick/designer/designersupport.h
+++ b/src/quick/designer/designersupport.h
@@ -62,7 +62,7 @@
 QT_BEGIN_NAMESPACE
 
 class QQuickItem;
-class QQuickShaderEffectTexture;
+class QSGLayer;
 class QImage;
 class QTransform;
 class QQmlContext;
@@ -154,7 +154,7 @@ public:
     static void polishItems(QQuickWindow *window);
 
 private:
-    QHash<QQuickItem*, QQuickShaderEffectTexture*> m_itemTextureHash;
+    QHash<QQuickItem*, QSGLayer*> m_itemTextureHash;
 };
 
 QT_END_NAMESPACE
diff --git a/src/quick/items/context2d/qquickcanvascontext_p.h b/src/quick/items/context2d/qquickcanvascontext_p.h
index 2d8fbb5f85757017af3a358a83ace226ef752e33..8988ea91059ef1d33492b19cf8e6ffe90ff58c39 100644
--- a/src/quick/items/context2d/qquickcanvascontext_p.h
+++ b/src/quick/items/context2d/qquickcanvascontext_p.h
@@ -49,7 +49,7 @@
 QT_BEGIN_NAMESPACE
 
 class QQuickCanvasItem;
-class QSGDynamicTexture;
+class QSGLayer;
 
 class QQuickCanvasContextPrivate;
 class QQuickCanvasContext : public QObject
diff --git a/src/quick/items/qquickitemgrabresult.cpp b/src/quick/items/qquickitemgrabresult.cpp
index 93b9261c440a7d85f6e9f31b9371da763fe49852..f5d72bbd3acb27ce1a2cb3de72d9f86c0eb2ff18 100644
--- a/src/quick/items/qquickitemgrabresult.cpp
+++ b/src/quick/items/qquickitemgrabresult.cpp
@@ -91,7 +91,7 @@ public:
 
     QPointer<QQuickItem> item;
     QPointer<QQuickWindow> window;
-    QQuickShaderEffectTexture *texture;
+    QSGLayer *texture;
     QSizeF itemSize;
     QSize textureSize;
 };
@@ -228,7 +228,8 @@ void QQuickItemGrabResult::setup()
         return;
     }
 
-    d->texture = new QQuickShaderEffectTexture(d->item);
+    QSGRenderContext *rc = QQuickWindowPrivate::get(d->window.data())->context;
+    d->texture = rc->sceneGraphContext()->createLayer(rc);
     d->texture->setItem(QQuickItemPrivate::get(d->item)->itemNode());
     d->itemSize = QSizeF(d->item->width(), d->item->height());
 }
diff --git a/src/quick/items/qquickshadereffectnode.cpp b/src/quick/items/qquickshadereffectnode.cpp
index cefb006648be0905d773e8ce33f5429fbfa5b1a8..3f7938c386c7654487b226a14360628c55304ff2 100644
--- a/src/quick/items/qquickshadereffectnode.cpp
+++ b/src/quick/items/qquickshadereffectnode.cpp
@@ -418,7 +418,7 @@ void QQuickShaderEffectMaterial::updateTextures() const
 {
     for (int i = 0; i < textureProviders.size(); ++i) {
         if (QSGTextureProvider *provider = textureProviders.at(i)) {
-            if (QSGDynamicTexture *texture = qobject_cast<QSGDynamicTexture *>(provider->texture()))
+            if (QSGLayer *texture = qobject_cast<QSGLayer *>(provider->texture()))
                 texture->updateTexture();
         }
     }
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index 2b42a01fc152b1e12180fd44048d39c25f4c7bb7..f027e044e1c43c2b0df5fefc15e974f9a443ff8d 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -54,44 +54,6 @@
 
 QT_BEGIN_NAMESPACE
 
-DEFINE_BOOL_CONFIG_OPTION(qmlFboOverlay, QML_FBO_OVERLAY)
-DEFINE_BOOL_CONFIG_OPTION(qmlFboFlushBeforeDetach, QML_FBO_FLUSH_BEFORE_DETACH)
-
-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 (qmlFboFlushBeforeDetach())
-            QOpenGLContext::currentContext()->functions()->glFlush();
-        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
@@ -113,7 +75,7 @@ public:
         return sourceTexture;
     }
 
-    QQuickShaderEffectTexture *sourceTexture;
+    QSGLayer *sourceTexture;
 
     QSGTexture::Filtering mipmapFiltering;
     QSGTexture::Filtering filtering;
@@ -122,379 +84,10 @@ public:
 };
 #include "qquickshadereffectsource.moc"
 
-QQuickShaderEffectTexture::QQuickShaderEffectTexture(QQuickItem *shaderSource)
-    : QSGDynamicTexture()
-    , m_item(0)
-    , m_shaderSourceNode(0)
-    , m_device_pixel_ratio(1)
-    , m_format(GL_RGBA)
-    , m_renderer(0)
-    , m_fbo(0)
-    , m_secondaryFbo(0)
-    , m_transparentTexture(0)
-#ifdef QSG_DEBUG_FBO_OVERLAY
-    , m_debugOverlay(0)
-#endif
-    , m_context(QQuickItemPrivate::get(shaderSource)->sceneGraphRenderContext())
-    , m_mipmap(false)
-    , m_live(true)
-    , m_recursive(false)
-    , m_dirtyTexture(true)
-    , m_multisamplingChecked(false)
-    , m_multisampling(false)
-    , m_grab(false)
-{
-}
-
-QQuickShaderEffectTexture::~QQuickShaderEffectTexture()
-{
-    invalidated();
-}
-
-void QQuickShaderEffectTexture::invalidated()
-{
-    delete m_renderer;
-    m_renderer = 0;
-    delete m_fbo;
-    delete m_secondaryFbo;
-    m_fbo = m_secondaryFbo = 0;
-#ifdef QSG_DEBUG_FBO_OVERLAY
-    delete m_debugOverlay;
-    m_debugOverlay = 0;
-#endif
-    if (m_transparentTexture) {
-        QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_transparentTexture);
-        m_transparentTexture = 0;
-    }
-}
-
-void QQuickShaderEffectTexture::markDirtyTextureLater()
-{
-    QCoreApplication::postEvent(this, new QEvent(QEvent::User));
-}
-
-void QQuickShaderEffectTexture::customEvent(QEvent *)
-{
-    markDirtyTexture();
-}
-
-int QQuickShaderEffectTexture::textureId() const
-{
-    return m_fbo ? m_fbo->texture() : 0;
-}
-
-bool QQuickShaderEffectTexture::hasAlphaChannel() const
-{
-    return m_format != GL_RGB;
-}
-
-bool QQuickShaderEffectTexture::hasMipmaps() const
-{
-    return m_mipmap;
-}
-
-
-void QQuickShaderEffectTexture::bind()
-{
-#ifndef QT_NO_DEBUG
-    if (!m_recursive && m_fbo && ((m_multisampling && m_secondaryFbo->isBound()) || m_fbo->isBound()))
-        qWarning("ShaderEffectSource: \'recursive\' must be set to true when rendering recursively.");
-#endif
-    QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
-    if (!m_fbo && m_format == GL_RGBA) {
-        if (m_transparentTexture == 0) {
-            funcs->glGenTextures(1, &m_transparentTexture);
-            funcs->glBindTexture(GL_TEXTURE_2D, m_transparentTexture);
-            const uint zero = 0;
-            funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &zero);
-        } else {
-            funcs->glBindTexture(GL_TEXTURE_2D, m_transparentTexture);
-        }
-    } else {
-        funcs->glBindTexture(GL_TEXTURE_2D, m_fbo ? m_fbo->texture() : 0);
-        updateBindOptions();
-    }
-}
-
-bool QQuickShaderEffectTexture::updateTexture()
-{
-    bool doGrab = (m_live || m_grab) && m_dirtyTexture;
-    if (doGrab)
-        grab();
-    if (m_grab)
-        emit scheduledUpdateCompleted();
-    m_grab = false;
-    return doGrab;
-}
-
-void QQuickShaderEffectTexture::setHasMipmaps(bool mipmap)
-{
-    if (mipmap == m_mipmap)
-        return;
-    m_mipmap = mipmap;
-    if (m_mipmap && m_fbo && !m_fbo->format().mipmap())
-        markDirtyTexture();
-}
-
-
-void QQuickShaderEffectTexture::setItem(QSGNode *item)
-{
-    if (item == m_item)
-        return;
-    m_item = item;
-
-    if (m_live && !m_item) {
-        delete m_fbo;
-        delete m_secondaryFbo;
-        m_fbo = m_secondaryFbo = 0;
-        m_depthStencilBuffer.clear();
-    }
-
-    markDirtyTexture();
-}
-
-void QQuickShaderEffectTexture::setRect(const QRectF &rect)
-{
-    if (rect == m_rect)
-        return;
-    m_rect = rect;
-    markDirtyTexture();
-}
-
-void QQuickShaderEffectTexture::setSize(const QSize &size)
-{
-    if (size == m_size)
-        return;
-    m_size = size;
-
-    if (m_live && m_size.isNull()) {
-        delete m_fbo;
-        delete m_secondaryFbo;
-        m_fbo = m_secondaryFbo = 0;
-        m_depthStencilBuffer.clear();
-    }
-
-    markDirtyTexture();
-}
-
-void QQuickShaderEffectTexture::setFormat(GLenum format)
-{
-    if (format == m_format)
-        return;
-    m_format = format;
-    markDirtyTexture();
-}
-
-void QQuickShaderEffectTexture::setLive(bool live)
-{
-    if (live == m_live)
-        return;
-    m_live = live;
-
-    if (m_live && (!m_item || m_size.isNull())) {
-        delete m_fbo;
-        delete m_secondaryFbo;
-        m_fbo = m_secondaryFbo = 0;
-        m_depthStencilBuffer.clear();
-    }
-
-    markDirtyTexture();
-}
-
-void QQuickShaderEffectTexture::scheduleUpdate()
-{
-    if (m_grab)
-        return;
-    m_grab = true;
-    if (m_dirtyTexture) {
-        emit updateRequested();
-        if (m_shaderSourceNode)
-            m_shaderSourceNode->markDirty(QSGNode::DirtyMaterial);
-    }
-}
-
-void QQuickShaderEffectTexture::setRecursive(bool recursive)
-{
-    m_recursive = recursive;
-}
-
-void QQuickShaderEffectTexture::markDirtyTexture()
-{
-    m_dirtyTexture = true;
-    if (m_live || m_grab) {
-        emit updateRequested();
-        if (m_shaderSourceNode)
-            m_shaderSourceNode->markDirty(QSGNode::DirtyMaterial);
-    }
-}
-
-void QQuickShaderEffectTexture::grab()
-{
-    if (!m_item || m_size.isNull()) {
-        delete m_fbo;
-        delete m_secondaryFbo;
-        m_fbo = m_secondaryFbo = 0;
-        m_depthStencilBuffer.clear();
-        m_dirtyTexture = false;
-        return;
-    }
-    QSGNode *root = m_item;
-    while (root->firstChild() && root->type() != QSGNode::RootNodeType)
-        root = root->firstChild();
-    if (root->type() != QSGNode::RootNodeType)
-        return;
-
-    if (!m_renderer) {
-        m_renderer = m_context->createRenderer();
-        connect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTextureLater()));
-    }
-    m_renderer->setDevicePixelRatio(m_device_pixel_ratio);
-    m_renderer->setRootNode(static_cast<QSGRootNode *>(root));
-
-    QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
-    bool deleteFboLater = false;
-    if (!m_fbo || m_fbo->size() != m_size || m_fbo->format().internalTextureFormat() != m_format
-        || (!m_fbo->format().mipmap() && m_mipmap))
-    {
-        if (!m_multisamplingChecked) {
-            if (m_context->openglContext()->format().samples() <= 1) {
-                m_multisampling = false;
-            } else {
-                const QSet<QByteArray> extensions = m_context->openglContext()->extensions();
-                m_multisampling = extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_multisample"))
-                    && extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_blit"));
-            }
-            m_multisamplingChecked = true;
-        }
-        if (m_multisampling) {
-            // Don't delete the FBO right away in case it is used recursively.
-            deleteFboLater = true;
-            delete m_secondaryFbo;
-            QOpenGLFramebufferObjectFormat format;
-
-            format.setInternalTextureFormat(m_format);
-            format.setSamples(m_context->openglContext()->format().samples());
-            m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format);
-            m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo);
-        } else {
-            QOpenGLFramebufferObjectFormat format;
-            format.setInternalTextureFormat(m_format);
-            format.setMipmap(m_mipmap);
-            if (m_recursive) {
-                deleteFboLater = true;
-                delete m_secondaryFbo;
-                m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format);
-                funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture());
-                updateBindOptions(true);
-                m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo);
-            } else {
-                delete m_fbo;
-                delete m_secondaryFbo;
-                m_fbo = new QOpenGLFramebufferObject(m_size, format);
-                m_secondaryFbo = 0;
-                funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
-                updateBindOptions(true);
-                m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_fbo);
-            }
-        }
-    }
-
-    if (m_recursive && !m_secondaryFbo) {
-        // m_fbo already created, m_recursive was just set.
-        Q_ASSERT(m_fbo);
-        Q_ASSERT(!m_multisampling);
-
-        m_secondaryFbo = new QOpenGLFramebufferObject(m_size, m_fbo->format());
-        funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture());
-        updateBindOptions(true);
-    }
-
-    // Render texture.
-    root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip and opacity update.
-    m_renderer->nodeChanged(root, QSGNode::DirtyForceUpdate); // Force render list update.
-
-#ifdef QSG_DEBUG_FBO_OVERLAY
-    if (qmlFboOverlay()) {
-        if (!m_debugOverlay)
-            m_debugOverlay = new QSGSimpleRectNode();
-        m_debugOverlay->setRect(QRectF(0, 0, m_size.width(), m_size.height()));
-        m_debugOverlay->setColor(QColor(0xff, 0x00, 0x80, 0x40));
-        root->appendChildNode(m_debugOverlay);
-    }
-#endif
-
-    m_dirtyTexture = false;
-
-    m_renderer->setDeviceRect(m_size);
-    m_renderer->setViewportRect(m_size);
-    QRectF mirrored(m_rect.left(), m_rect.bottom(), m_rect.width(), -m_rect.height());
-    m_renderer->setProjectionMatrixToRect(mirrored);
-    m_renderer->setClearColor(Qt::transparent);
-
-    if (m_multisampling) {
-        m_renderer->renderScene(BindableFbo(m_secondaryFbo, m_depthStencilBuffer.data()));
-
-        if (deleteFboLater) {
-            delete m_fbo;
-            QOpenGLFramebufferObjectFormat format;
-            format.setInternalTextureFormat(m_format);
-            format.setAttachment(QOpenGLFramebufferObject::NoAttachment);
-            format.setMipmap(m_mipmap);
-            format.setSamples(0);
-            m_fbo = new QOpenGLFramebufferObject(m_size, format);
-            funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
-            updateBindOptions(true);
-        }
-
-        QRect r(QPoint(), m_size);
-        QOpenGLFramebufferObject::blitFramebuffer(m_fbo, r, m_secondaryFbo, r);
-    } else {
-        if (m_recursive) {
-            m_renderer->renderScene(BindableFbo(m_secondaryFbo, m_depthStencilBuffer.data()));
-
-            if (deleteFboLater) {
-                delete m_fbo;
-                QOpenGLFramebufferObjectFormat format;
-                format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
-                format.setInternalTextureFormat(m_format);
-                format.setMipmap(m_mipmap);
-                m_fbo = new QOpenGLFramebufferObject(m_size, format);
-                funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
-                updateBindOptions(true);
-            }
-            qSwap(m_fbo, m_secondaryFbo);
-        } else {
-            m_renderer->renderScene(BindableFbo(m_fbo, m_depthStencilBuffer.data()));
-        }
-    }
-
-    if (m_mipmap) {
-        funcs->glBindTexture(GL_TEXTURE_2D, textureId());
-        funcs->glGenerateMipmap(GL_TEXTURE_2D);
-    }
-
-    root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip, opacity and render list update.
-
-#ifdef QSG_DEBUG_FBO_OVERLAY
-    if (qmlFboOverlay())
-        root->removeChildNode(m_debugOverlay);
-#endif
-    if (m_recursive)
-        markDirtyTexture(); // Continuously update if 'live' and 'recursive'.
-}
-
-QImage QQuickShaderEffectTexture::toImage() const
-{
-    if (m_fbo)
-        return m_fbo->toImage();
-
-    return QImage();
-}
-
 class QQuickShaderEffectSourceCleanup : public QRunnable
 {
 public:
-    QQuickShaderEffectSourceCleanup(QQuickShaderEffectTexture *t, QQuickShaderEffectSourceTextureProvider *p)
+    QQuickShaderEffectSourceCleanup(QSGLayer *t, QQuickShaderEffectSourceTextureProvider *p)
         : texture(t)
         , provider(p)
     {}
@@ -502,7 +95,7 @@ public:
         delete texture;
         delete provider;
     }
-    QQuickShaderEffectTexture *texture;
+    QSGLayer *texture;
     QQuickShaderEffectSourceTextureProvider *provider;
 };
 
@@ -642,7 +235,8 @@ void QQuickShaderEffectSource::ensureTexture()
                "QQuickShaderEffectSource::ensureTexture",
                "Cannot be used outside the rendering thread");
 
-    m_texture = new QQuickShaderEffectTexture(this);
+    QSGRenderContext *rc = QQuickItemPrivate::get(this)->sceneGraphRenderContext();
+    m_texture = rc->sceneGraphContext()->createLayer(rc);
     connect(QQuickItemPrivate::get(this)->window, SIGNAL(sceneGraphInvalidated()), m_texture, SLOT(invalidated()), Qt::DirectConnection);
     connect(m_texture, SIGNAL(updateRequested()), this, SLOT(update()));
     connect(m_texture, SIGNAL(scheduledUpdateCompleted()), this, SIGNAL(scheduledUpdateCompleted()));
diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h
index 4caeaab52c8ad2ffd437969b7770be8f09c19dfe..35899339ceecd8f24fdab9f709b01217eb7bf971 100644
--- a/src/quick/items/qquickshadereffectsource_p.h
+++ b/src/quick/items/qquickshadereffectsource_p.h
@@ -53,8 +53,6 @@
 #include "qsize.h"
 #include "qrect.h"
 
-#define QSG_DEBUG_FBO_OVERLAY
-
 QT_BEGIN_NAMESPACE
 
 class QSGNode;
@@ -64,95 +62,6 @@ class QSGSimpleRectNode;
 
 class QQuickShaderEffectSourceTextureProvider;
 
-class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectTexture : public QSGDynamicTexture
-{
-    Q_OBJECT
-public:
-    QQuickShaderEffectTexture(QQuickItem *shaderSource);
-    ~QQuickShaderEffectTexture();
-
-    virtual bool updateTexture();
-
-    // The item's "paint node", not effect node.
-    QSGNode *item() const { return m_item; }
-    void setItem(QSGNode *item);
-
-    void setShaderSourceNode(QSGNode *node) { m_shaderSourceNode = node; }
-
-    QRectF rect() const { return m_rect; }
-    void setRect(const QRectF &rect);
-
-    QSize size() const { return m_size; }
-    void setSize(const QSize &size);
-
-    void setHasMipmaps(bool mipmap);
-
-    void bind();
-
-    bool hasAlphaChannel() const;
-    bool hasMipmaps() const;
-    int textureId() const;
-    QSize textureSize() const { return m_size; }
-
-    GLenum format() const { return m_format; }
-    void setFormat(GLenum format);
-
-    bool live() const { return bool(m_live); }
-    void setLive(bool live);
-
-    bool recursive() const { return bool(m_recursive); }
-    void setRecursive(bool recursive);
-
-    void setDevicePixelRatio(qreal ratio) { m_device_pixel_ratio = ratio; }
-
-    void scheduleUpdate();
-
-    QImage toImage() const;
-
-Q_SIGNALS:
-    void updateRequested();
-    void scheduledUpdateCompleted();
-
-public Q_SLOTS:
-    void markDirtyTexture();
-    void invalidated();
-    void markDirtyTextureLater();
-
-protected:
-    virtual void customEvent(QEvent *);
-
-private:
-    void grab();
-
-    QSGNode *m_item;
-    QSGNode *m_shaderSourceNode;
-    QRectF m_rect;
-    QSize m_size;
-    qreal m_device_pixel_ratio;
-    GLenum m_format;
-
-    QSGRenderer *m_renderer;
-    QOpenGLFramebufferObject *m_fbo;
-    QOpenGLFramebufferObject *m_secondaryFbo;
-    QSharedPointer<QSGDepthStencilBuffer> m_depthStencilBuffer;
-
-    GLuint m_transparentTexture;
-
-#ifdef QSG_DEBUG_FBO_OVERLAY
-    QSGSimpleRectNode *m_debugOverlay;
-#endif
-
-    QSGRenderContext *m_context;
-
-    uint m_mipmap : 1;
-    uint m_live : 1;
-    uint m_recursive : 1;
-    uint m_dirtyTexture : 1;
-    uint m_multisamplingChecked : 1;
-    uint m_multisampling : 1;
-    uint m_grab : 1;
-};
-
 class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffectSource : public QQuickItem, public QQuickItemChangeListener
 {
     Q_OBJECT
@@ -244,7 +153,7 @@ private:
     void ensureTexture();
 
     QQuickShaderEffectSourceTextureProvider *m_provider;
-    QQuickShaderEffectTexture *m_texture;
+    QSGLayer *m_texture;
     WrapMode m_wrapMode;
     QQuickItem *m_sourceItem;
     QRectF m_sourceRect;
diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp
index ee077dbaf1108b8536949c40a36fea736a651714..68b1882c3fcc621a50b1505b63c2e8dcb547da95 100644
--- a/src/quick/scenegraph/qsgadaptationlayer.cpp
+++ b/src/quick/scenegraph/qsgadaptationlayer.cpp
@@ -328,6 +328,7 @@ void QSGNodeVisitorEx::visitChildren(QSGNode *node)
             }
             break;
         }
+        case QSGNode::RootNodeType: // fall through
         case QSGNode::BasicNodeType: {
             visitChildren(child);
             break;
@@ -339,4 +340,25 @@ void QSGNodeVisitorEx::visitChildren(QSGNode *node)
     }
 }
 
+void QSGLayer::markDirtyTextureLater()
+{
+    QCoreApplication::postEvent(this, new QEvent(static_cast<QEvent::Type>(markDirtyEventType())));
+}
+
+void QSGLayer::customEvent(QEvent *event)
+{
+    if (event->type() == markDirtyEventType())
+        markDirtyTexture();
+    else
+        QObject::customEvent(event);
+}
+
+int QSGLayer::markDirtyEventType()
+{
+    static int type = QEvent::None;
+    if (type == QEvent::None)
+        type = QEvent::registerEventType();
+    return type;
+}
+
 QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index cc998a9cef2c8aadcbff10ea14fd6678f4be7091..2e17cfdf40eb8642a4dfc87208ff7f34360a16f7 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -158,6 +158,37 @@ public:
     virtual void accept(QSGNodeVisitorEx *visitor) { visitor->visit(this); visitor->visitChildren(this); visitor->endVisit(this); }
 };
 
+class Q_QUICK_EXPORT QSGLayer : public QSGDynamicTexture
+{
+    Q_OBJECT
+public:
+    virtual void setItem(QSGNode *item) = 0;
+    virtual void setShaderSourceNode(QSGNode *node) = 0;
+    virtual void setRect(const QRectF &rect) = 0;
+    virtual void setSize(const QSize &size) = 0;
+    virtual void scheduleUpdate() = 0;
+    virtual QImage toImage() const = 0;
+    virtual void setLive(bool live) = 0;
+    virtual void setRecursive(bool recursive) = 0;
+    virtual void setFormat(GLenum format) = 0;
+    virtual void setHasMipmaps(bool mipmap) = 0;
+    virtual void setDevicePixelRatio(qreal ratio) = 0;
+    Q_SLOT virtual void markDirtyTexture() = 0;
+    Q_SLOT virtual void invalidated() = 0;
+
+    Q_SLOT void markDirtyTextureLater();
+
+Q_SIGNALS:
+    void updateRequested();
+    void scheduledUpdateCompleted();
+
+protected:
+    virtual void customEvent(QEvent *);
+
+private:
+    int markDirtyEventType();
+};
+
 class Q_QUICK_PRIVATE_EXPORT QSGGlyphNode : public QSGVisitableNode
 {
 public:
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index f69dd7addead279882bb09781263be1f18b6eb0c..6ebc479ec5f1fc6921db8ad115763cb94698315f 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -51,6 +51,7 @@
 #include <QtQuick/private/qsgshareddistancefieldglyphcache_p.h>
 #include <QtQuick/private/qsgatlastexture_p.h>
 #include <QtQuick/private/qsgrenderloop_p.h>
+#include <QtQuick/private/qsgdefaultlayer_p.h>
 
 #include <QtQuick/private/qsgtexture_p.h>
 #include <QtQuick/private/qquickpixmapcache_p.h>
@@ -321,6 +322,14 @@ QSGNinePatchNode *QSGContext::createNinePatchNode()
     return 0;
 }
 
+/*!
+    Factory function for scene graph backends of layers.
+ */
+QSGLayer *QSGContext::createLayer(QSGRenderContext *renderContext)
+{
+    return new QSGDefaultLayer(renderContext);
+}
+
 QSurfaceFormat QSGContext::defaultSurfaceFormat() const
 {
     QSurfaceFormat format = QSurfaceFormat::defaultFormat();
diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h
index abf1abd4c019a325152513d14690e31f1715ed96..b5271f9f372cbc7b473ae72ff212ec5367eab514 100644
--- a/src/quick/scenegraph/qsgcontext_p.h
+++ b/src/quick/scenegraph/qsgcontext_p.h
@@ -72,6 +72,7 @@ class QSGTexture;
 class QSGMaterial;
 class QSGMaterialShader;
 class QSGRenderLoop;
+class QSGLayer;
 
 class QOpenGLContext;
 class QOpenGLFramebufferObject;
@@ -177,6 +178,7 @@ public:
     virtual QSGImageNode *createImageNode();
     virtual QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode);
     virtual QSGNinePatchNode *createNinePatchNode();
+    virtual QSGLayer *createLayer(QSGRenderContext *renderContext);
     virtual QAnimationDriver *createAnimationDriver(QObject *parent);
 
     virtual QSize minimumFBOSize() const;
diff --git a/src/quick/scenegraph/qsgdefaultimagenode.cpp b/src/quick/scenegraph/qsgdefaultimagenode.cpp
index d925b1c7c4b3d64e3f80cd48c0f37fdd78d5f8b3..7c70a259aa2fe6e7b34cba22b0dac9c76c06642a 100644
--- a/src/quick/scenegraph/qsgdefaultimagenode.cpp
+++ b/src/quick/scenegraph/qsgdefaultimagenode.cpp
@@ -292,7 +292,7 @@ void QSGDefaultImageNode::update()
 void QSGDefaultImageNode::preprocess()
 {
     bool doDirty = false;
-    QSGDynamicTexture *t = qobject_cast<QSGDynamicTexture *>(m_material.texture());
+    QSGLayer *t = qobject_cast<QSGLayer *>(m_material.texture());
     if (t) {
         doDirty = t->updateTexture();
         updateGeometry();
diff --git a/src/quick/scenegraph/qsgdefaultlayer.cpp b/src/quick/scenegraph/qsgdefaultlayer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c93517fe3f2ff44082892c13f7a2c6716cfa95f5
--- /dev/null
+++ b/src/quick/scenegraph/qsgdefaultlayer.cpp
@@ -0,0 +1,445 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qsgdefaultlayer_p.h"
+
+#include <private/qqmlglobal_p.h>
+#include <private/qsgrenderer_p.h>
+
+#include <QOpenGLFramebufferObject>
+
+#ifdef QSG_DEBUG_FBO_OVERLAY
+DEFINE_BOOL_CONFIG_OPTION(qmlFboOverlay, QML_FBO_OVERLAY)
+#endif
+DEFINE_BOOL_CONFIG_OPTION(qmlFboFlushBeforeDetach, QML_FBO_FLUSH_BEFORE_DETACH)
+
+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 (qmlFboFlushBeforeDetach())
+            QOpenGLContext::currentContext()->functions()->glFlush();
+        if (m_depthStencil)
+            m_depthStencil->detach();
+    }
+
+    void BindableFbo::bind() const
+    {
+        m_fbo->bind();
+        if (m_depthStencil)
+            m_depthStencil->attach();
+    }
+}
+
+QSGDefaultLayer::QSGDefaultLayer(QSGRenderContext *context)
+    : QSGLayer()
+    , m_item(0)
+    , m_shaderSourceNode(0)
+    , m_device_pixel_ratio(1)
+    , m_format(GL_RGBA)
+    , m_renderer(0)
+    , m_fbo(0)
+    , m_secondaryFbo(0)
+    , m_transparentTexture(0)
+#ifdef QSG_DEBUG_FBO_OVERLAY
+    , m_debugOverlay(0)
+#endif
+    , m_context(context)
+    , m_mipmap(false)
+    , m_live(true)
+    , m_recursive(false)
+    , m_dirtyTexture(true)
+    , m_multisamplingChecked(false)
+    , m_multisampling(false)
+    , m_grab(false)
+{
+}
+
+QSGDefaultLayer::~QSGDefaultLayer()
+{
+    invalidated();
+}
+
+void QSGDefaultLayer::invalidated()
+{
+    delete m_renderer;
+    m_renderer = 0;
+    delete m_fbo;
+    delete m_secondaryFbo;
+    m_fbo = m_secondaryFbo = 0;
+#ifdef QSG_DEBUG_FBO_OVERLAY
+    delete m_debugOverlay;
+    m_debugOverlay = 0;
+#endif
+    if (m_transparentTexture) {
+        QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &m_transparentTexture);
+        m_transparentTexture = 0;
+    }
+}
+
+int QSGDefaultLayer::textureId() const
+{
+    return m_fbo ? m_fbo->texture() : 0;
+}
+
+bool QSGDefaultLayer::hasAlphaChannel() const
+{
+    return m_format != GL_RGB;
+}
+
+bool QSGDefaultLayer::hasMipmaps() const
+{
+    return m_mipmap;
+}
+
+
+void QSGDefaultLayer::bind()
+{
+#ifndef QT_NO_DEBUG
+    if (!m_recursive && m_fbo && ((m_multisampling && m_secondaryFbo->isBound()) || m_fbo->isBound()))
+        qWarning("ShaderEffectSource: \'recursive\' must be set to true when rendering recursively.");
+#endif
+    QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
+    if (!m_fbo && m_format == GL_RGBA) {
+        if (m_transparentTexture == 0) {
+            funcs->glGenTextures(1, &m_transparentTexture);
+            funcs->glBindTexture(GL_TEXTURE_2D, m_transparentTexture);
+            const uint zero = 0;
+            funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &zero);
+        } else {
+            funcs->glBindTexture(GL_TEXTURE_2D, m_transparentTexture);
+        }
+    } else {
+        funcs->glBindTexture(GL_TEXTURE_2D, m_fbo ? m_fbo->texture() : 0);
+        updateBindOptions();
+    }
+}
+
+bool QSGDefaultLayer::updateTexture()
+{
+    bool doGrab = (m_live || m_grab) && m_dirtyTexture;
+    if (doGrab)
+        grab();
+    if (m_grab)
+        emit scheduledUpdateCompleted();
+    m_grab = false;
+    return doGrab;
+}
+
+void QSGDefaultLayer::setHasMipmaps(bool mipmap)
+{
+    if (mipmap == m_mipmap)
+        return;
+    m_mipmap = mipmap;
+    if (m_mipmap && m_fbo && !m_fbo->format().mipmap())
+        markDirtyTexture();
+}
+
+
+void QSGDefaultLayer::setItem(QSGNode *item)
+{
+    if (item == m_item)
+        return;
+    m_item = item;
+
+    if (m_live && !m_item) {
+        delete m_fbo;
+        delete m_secondaryFbo;
+        m_fbo = m_secondaryFbo = 0;
+        m_depthStencilBuffer.clear();
+    }
+
+    markDirtyTexture();
+}
+
+void QSGDefaultLayer::setRect(const QRectF &rect)
+{
+    if (rect == m_rect)
+        return;
+    m_rect = rect;
+    markDirtyTexture();
+}
+
+void QSGDefaultLayer::setSize(const QSize &size)
+{
+    if (size == m_size)
+        return;
+    m_size = size;
+
+    if (m_live && m_size.isNull()) {
+        delete m_fbo;
+        delete m_secondaryFbo;
+        m_fbo = m_secondaryFbo = 0;
+        m_depthStencilBuffer.clear();
+    }
+
+    markDirtyTexture();
+}
+
+void QSGDefaultLayer::setFormat(GLenum format)
+{
+    if (format == m_format)
+        return;
+    m_format = format;
+    markDirtyTexture();
+}
+
+void QSGDefaultLayer::setLive(bool live)
+{
+    if (live == m_live)
+        return;
+    m_live = live;
+
+    if (m_live && (!m_item || m_size.isNull())) {
+        delete m_fbo;
+        delete m_secondaryFbo;
+        m_fbo = m_secondaryFbo = 0;
+        m_depthStencilBuffer.clear();
+    }
+
+    markDirtyTexture();
+}
+
+void QSGDefaultLayer::scheduleUpdate()
+{
+    if (m_grab)
+        return;
+    m_grab = true;
+    if (m_dirtyTexture) {
+        emit updateRequested();
+        if (m_shaderSourceNode)
+            m_shaderSourceNode->markDirty(QSGNode::DirtyMaterial);
+    }
+}
+
+void QSGDefaultLayer::setRecursive(bool recursive)
+{
+    m_recursive = recursive;
+}
+
+void QSGDefaultLayer::markDirtyTexture()
+{
+    m_dirtyTexture = true;
+    if (m_live || m_grab) {
+        emit updateRequested();
+        if (m_shaderSourceNode)
+            m_shaderSourceNode->markDirty(QSGNode::DirtyMaterial);
+    }
+}
+
+void QSGDefaultLayer::grab()
+{
+    if (!m_item || m_size.isNull()) {
+        delete m_fbo;
+        delete m_secondaryFbo;
+        m_fbo = m_secondaryFbo = 0;
+        m_depthStencilBuffer.clear();
+        m_dirtyTexture = false;
+        return;
+    }
+    QSGNode *root = m_item;
+    while (root->firstChild() && root->type() != QSGNode::RootNodeType)
+        root = root->firstChild();
+    if (root->type() != QSGNode::RootNodeType)
+        return;
+
+    if (!m_renderer) {
+        m_renderer = m_context->createRenderer();
+        connect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTextureLater()));
+    }
+    m_renderer->setDevicePixelRatio(m_device_pixel_ratio);
+    m_renderer->setRootNode(static_cast<QSGRootNode *>(root));
+
+    QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
+    bool deleteFboLater = false;
+    if (!m_fbo || m_fbo->size() != m_size || m_fbo->format().internalTextureFormat() != m_format
+        || (!m_fbo->format().mipmap() && m_mipmap))
+    {
+        if (!m_multisamplingChecked) {
+            if (m_context->openglContext()->format().samples() <= 1) {
+                m_multisampling = false;
+            } else {
+                const QSet<QByteArray> extensions = m_context->openglContext()->extensions();
+                m_multisampling = extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_multisample"))
+                    && extensions.contains(QByteArrayLiteral("GL_EXT_framebuffer_blit"));
+            }
+            m_multisamplingChecked = true;
+        }
+        if (m_multisampling) {
+            // Don't delete the FBO right away in case it is used recursively.
+            deleteFboLater = true;
+            delete m_secondaryFbo;
+            QOpenGLFramebufferObjectFormat format;
+
+            format.setInternalTextureFormat(m_format);
+            format.setSamples(m_context->openglContext()->format().samples());
+            m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format);
+            m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo);
+        } else {
+            QOpenGLFramebufferObjectFormat format;
+            format.setInternalTextureFormat(m_format);
+            format.setMipmap(m_mipmap);
+            if (m_recursive) {
+                deleteFboLater = true;
+                delete m_secondaryFbo;
+                m_secondaryFbo = new QOpenGLFramebufferObject(m_size, format);
+                funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture());
+                updateBindOptions(true);
+                m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_secondaryFbo);
+            } else {
+                delete m_fbo;
+                delete m_secondaryFbo;
+                m_fbo = new QOpenGLFramebufferObject(m_size, format);
+                m_secondaryFbo = 0;
+                funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
+                updateBindOptions(true);
+                m_depthStencilBuffer = m_context->depthStencilBufferForFbo(m_fbo);
+            }
+        }
+    }
+
+    if (m_recursive && !m_secondaryFbo) {
+        // m_fbo already created, m_recursive was just set.
+        Q_ASSERT(m_fbo);
+        Q_ASSERT(!m_multisampling);
+
+        m_secondaryFbo = new QOpenGLFramebufferObject(m_size, m_fbo->format());
+        funcs->glBindTexture(GL_TEXTURE_2D, m_secondaryFbo->texture());
+        updateBindOptions(true);
+    }
+
+    // Render texture.
+    root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip and opacity update.
+    m_renderer->nodeChanged(root, QSGNode::DirtyForceUpdate); // Force render list update.
+
+#ifdef QSG_DEBUG_FBO_OVERLAY
+    if (qmlFboOverlay()) {
+        if (!m_debugOverlay)
+            m_debugOverlay = new QSGSimpleRectNode();
+        m_debugOverlay->setRect(QRectF(0, 0, m_size.width(), m_size.height()));
+        m_debugOverlay->setColor(QColor(0xff, 0x00, 0x80, 0x40));
+        root->appendChildNode(m_debugOverlay);
+    }
+#endif
+
+    m_dirtyTexture = false;
+
+    m_renderer->setDeviceRect(m_size);
+    m_renderer->setViewportRect(m_size);
+    QRectF mirrored(m_rect.left(), m_rect.bottom(), m_rect.width(), -m_rect.height());
+    m_renderer->setProjectionMatrixToRect(mirrored);
+    m_renderer->setClearColor(Qt::transparent);
+
+    if (m_multisampling) {
+        m_renderer->renderScene(BindableFbo(m_secondaryFbo, m_depthStencilBuffer.data()));
+
+        if (deleteFboLater) {
+            delete m_fbo;
+            QOpenGLFramebufferObjectFormat format;
+            format.setInternalTextureFormat(m_format);
+            format.setAttachment(QOpenGLFramebufferObject::NoAttachment);
+            format.setMipmap(m_mipmap);
+            format.setSamples(0);
+            m_fbo = new QOpenGLFramebufferObject(m_size, format);
+            funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
+            updateBindOptions(true);
+        }
+
+        QRect r(QPoint(), m_size);
+        QOpenGLFramebufferObject::blitFramebuffer(m_fbo, r, m_secondaryFbo, r);
+    } else {
+        if (m_recursive) {
+            m_renderer->renderScene(BindableFbo(m_secondaryFbo, m_depthStencilBuffer.data()));
+
+            if (deleteFboLater) {
+                delete m_fbo;
+                QOpenGLFramebufferObjectFormat format;
+                format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+                format.setInternalTextureFormat(m_format);
+                format.setMipmap(m_mipmap);
+                m_fbo = new QOpenGLFramebufferObject(m_size, format);
+                funcs->glBindTexture(GL_TEXTURE_2D, m_fbo->texture());
+                updateBindOptions(true);
+            }
+            qSwap(m_fbo, m_secondaryFbo);
+        } else {
+            m_renderer->renderScene(BindableFbo(m_fbo, m_depthStencilBuffer.data()));
+        }
+    }
+
+    if (m_mipmap) {
+        funcs->glBindTexture(GL_TEXTURE_2D, textureId());
+        funcs->glGenerateMipmap(GL_TEXTURE_2D);
+    }
+
+    root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip, opacity and render list update.
+
+#ifdef QSG_DEBUG_FBO_OVERLAY
+    if (qmlFboOverlay())
+        root->removeChildNode(m_debugOverlay);
+#endif
+    if (m_recursive)
+        markDirtyTexture(); // Continuously update if 'live' and 'recursive'.
+}
+
+QImage QSGDefaultLayer::toImage() const
+{
+    if (m_fbo)
+        return m_fbo->toImage();
+
+    return QImage();
+}
diff --git a/src/quick/scenegraph/qsgdefaultlayer_p.h b/src/quick/scenegraph/qsgdefaultlayer_p.h
new file mode 100644
index 0000000000000000000000000000000000000000..47a0448846b056420b421911f327f5f9036cce67
--- /dev/null
+++ b/src/quick/scenegraph/qsgdefaultlayer_p.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QSGDEFAULTLAYER_P_H
+#define QSGDEFAULTLAYER_P_H
+
+#include <private/qsgadaptationlayer_p.h>
+#include <private/qsgcontext_p.h>
+#include <qsgsimplerectnode.h>
+
+#define QSG_DEBUG_FBO_OVERLAY
+
+class Q_QUICK_PRIVATE_EXPORT QSGDefaultLayer : public QSGLayer
+{
+    Q_OBJECT
+public:
+    QSGDefaultLayer(QSGRenderContext *context);
+    ~QSGDefaultLayer();
+
+    virtual bool updateTexture();
+
+    // The item's "paint node", not effect node.
+    QSGNode *item() const { return m_item; }
+    void setItem(QSGNode *item);
+
+    void setShaderSourceNode(QSGNode *node) { m_shaderSourceNode = node; }
+
+    QRectF rect() const { return m_rect; }
+    void setRect(const QRectF &rect);
+
+    QSize size() const { return m_size; }
+    void setSize(const QSize &size);
+
+    void setHasMipmaps(bool mipmap);
+
+    void bind();
+
+    bool hasAlphaChannel() const;
+    bool hasMipmaps() const;
+    int textureId() const;
+    QSize textureSize() const { return m_size; }
+
+    GLenum format() const { return m_format; }
+    void setFormat(GLenum format);
+
+    bool live() const { return bool(m_live); }
+    void setLive(bool live);
+
+    bool recursive() const { return bool(m_recursive); }
+    void setRecursive(bool recursive);
+
+    void setDevicePixelRatio(qreal ratio) { m_device_pixel_ratio = ratio; }
+
+    void scheduleUpdate();
+
+    QImage toImage() const;
+
+public Q_SLOTS:
+    void markDirtyTexture();
+    void invalidated();
+
+private:
+    void grab();
+
+    QSGNode *m_item;
+    QSGNode *m_shaderSourceNode;
+    QRectF m_rect;
+    QSize m_size;
+    qreal m_device_pixel_ratio;
+    GLenum m_format;
+
+    QSGRenderer *m_renderer;
+    QOpenGLFramebufferObject *m_fbo;
+    QOpenGLFramebufferObject *m_secondaryFbo;
+    QSharedPointer<QSGDepthStencilBuffer> m_depthStencilBuffer;
+
+    GLuint m_transparentTexture;
+
+#ifdef QSG_DEBUG_FBO_OVERLAY
+    QSGSimpleRectNode *m_debugOverlay;
+#endif
+
+    QSGRenderContext *m_context;
+
+    uint m_mipmap : 1;
+    uint m_live : 1;
+    uint m_recursive : 1;
+    uint m_dirtyTexture : 1;
+    uint m_multisamplingChecked : 1;
+    uint m_multisampling : 1;
+    uint m_grab : 1;
+};
+
+#endif // QSGDEFAULTLAYER_P_H
diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri
index d08fce03362a776d57f70fb7b99944cb16d87ca1..4d9d7444b374524409031e063f323a27bbc358bd 100644
--- a/src/quick/scenegraph/scenegraph.pri
+++ b/src/quick/scenegraph/scenegraph.pri
@@ -81,7 +81,8 @@ HEADERS += \
     $$PWD/qsgshareddistancefieldglyphcache_p.h \
     $$PWD/qsgrenderloop_p.h \
     $$PWD/qsgthreadedrenderloop_p.h \
-    $$PWD/qsgwindowsrenderloop_p.h
+    $$PWD/qsgwindowsrenderloop_p.h \
+    $$PWD/qsgdefaultlayer_p.h
 
 SOURCES += \
     $$PWD/qsgadaptationlayer.cpp \
@@ -97,7 +98,8 @@ SOURCES += \
     $$PWD/qsgshareddistancefieldglyphcache.cpp \
     $$PWD/qsgrenderloop.cpp \
     $$PWD/qsgthreadedrenderloop.cpp \
-    $$PWD/qsgwindowsrenderloop.cpp
+    $$PWD/qsgwindowsrenderloop.cpp \
+    $$PWD/qsgdefaultlayer.cpp
 
 RESOURCES += \
     $$PWD/scenegraph.qrc