diff --git a/src/quick3d/qquick3dtexture.cpp b/src/quick3d/qquick3dtexture.cpp
index a1694ca71bc3c88b7c435c219a99affdc7e4ab9f..53a1b626c535db81f423b684744bb98883013c9c 100644
--- a/src/quick3d/qquick3dtexture.cpp
+++ b/src/quick3d/qquick3dtexture.cpp
@@ -57,8 +57,10 @@ QQuick3DTexture::QQuick3DTexture(QQuick3DObject *parent)
 
 QQuick3DTexture::~QQuick3DTexture()
 {
-    if (m_layer)
-        delete m_layer;
+    if (m_layer && m_sceneManagerForLayer) {
+        m_sceneManagerForLayer->qsgDynamicTextures.removeAll(m_layer);
+        m_layer->deleteLater();
+    }
 
     if (m_sourceItem) {
         QQuickItemPrivate *sourcePrivate = QQuickItemPrivate::get(m_sourceItem);
@@ -546,7 +548,7 @@ QSSGRenderGraphObject *QQuick3DTexture::updateSpatialNode(QSSGRenderGraphObject
         if (!window) {
             // Do a hack to set the window
             const auto &manager = QQuick3DObjectPrivate::get(this)->sceneManager;
-            auto *window = manager->window();
+            window = manager->window();
             if (!window) {
                 qWarning() << "Unable to get window, this will probably not work";
             } else {
@@ -571,7 +573,17 @@ QSSGRenderGraphObject *QQuick3DTexture::updateSpatialNode(QSSGRenderGraphObject
             // TODO: handle dynamic textures
             // TODO: handle textureProvider property changed
         } else {
-            ensureTexture();
+            if (!m_initialized) {
+                m_initialized = true;
+                // When scene has been rendered for the first time, create layer texture.
+                connect(window, &QQuickWindow::afterRendering, this, [this, window]() {
+                    disconnect(window, &QQuickWindow::afterRendering, this, nullptr);
+                    createLayerTexture();
+                });
+            }
+
+            if (!m_layer)
+                return node;
 
             m_layer->setItem(QQuickItemPrivate::get(m_sourceItem)->itemNode());
             QRectF sourceRect = QRectF(0, 0, m_sourceItem->width(), m_sourceItem->height());
@@ -655,11 +667,9 @@ void QQuick3DTexture::sourceItemDestroyed(QObject *item)
     update();
 }
 
-void QQuick3DTexture::ensureTexture()
+// Create layer and update once valid layer texture exists
+void QQuick3DTexture::createLayerTexture()
 {
-    if (m_layer)
-        return;
-
     auto *sourcePrivate = QQuickItemPrivate::get(m_sourceItem);
 //    Q_ASSERT_X(sourcePrivate->window && sourcePrivate->sceneGraphRenderContext()
 //               && QThread::currentThread() == sourcePrivate->sceneGraphRenderContext()->thread(),
@@ -668,8 +678,6 @@ void QQuick3DTexture::ensureTexture()
     QSGRenderContext *rc = sourcePrivate->sceneGraphRenderContext();
     auto *layer = rc->sceneGraphContext()->createLayer(rc);
     connect(sourcePrivate->window, SIGNAL(sceneGraphInvalidated()), layer, SLOT(invalidated()), Qt::DirectConnection);
-    connect(layer, SIGNAL(updateRequested()), this, SLOT(update()));
-    //connect(layer, SIGNAL(scheduledUpdateCompleted()), this, SIGNAL(scheduledUpdateCompleted()));
 
     const auto &manager = QQuick3DObjectPrivate::get(this)->sceneManager;
     manager->qsgDynamicTextures << layer;
@@ -677,9 +685,29 @@ void QQuick3DTexture::ensureTexture()
     connect(layer, &QObject::destroyed, manager.data(), [this, manager, layer]() {
         manager->qsgDynamicTextures.removeAll(layer);
         m_sceneManagerForLayer = nullptr;
+        m_initialized = false;
     }, Qt::DirectConnection);
 
-    m_layer = layer;
+    // When layer has been updated, take it into use.
+    connect(layer, &QSGLayer::scheduledUpdateCompleted, this, [this, layer]() {
+        delete m_layer;
+        m_layer = layer;
+        update();
+    });
+
+    // With every frame (even when QQuickWindow isn't dirty so doesn't render),
+    // try to update the texture. If updateTexture() returns false, content hasn't changed.
+    connect(sourcePrivate->window, &QQuickWindow::beforeSynchronizing, [this]() {
+        if (m_layer) {
+            bool textureUpdated = m_layer->updateTexture();
+            if (textureUpdated)
+                update();
+        }
+    });
+
+    layer->markDirtyTexture();
+    layer->scheduleUpdate();
+    update();
 }
 
 QSSGRenderImage *QQuick3DTexture::getRenderImage()
diff --git a/src/quick3d/qquick3dtexture_p.h b/src/quick3d/qquick3dtexture_p.h
index e414720ea5f89a8c3f2e0f0a58497b3c2d66d192..aea113cd24740772ab8692de3579d209642d79a4 100644
--- a/src/quick3d/qquick3dtexture_p.h
+++ b/src/quick3d/qquick3dtexture_p.h
@@ -188,7 +188,7 @@ private Q_SLOTS:
     void sourceItemDestroyed(QObject *item);
 
 private:
-    void ensureTexture();
+    void createLayerTexture();
 
     enum class DirtyFlag {
         TransformDirty = (1 << 0),
@@ -217,6 +217,7 @@ private:
                               | DirtyFlags(DirtyFlag::SourceDirty);
     QMetaObject::Connection m_textureProviderConnection;
     QSharedPointer<QQuick3DSceneManager> m_sceneManagerForLayer;
+    bool m_initialized = false;
     void trySetSourceParent();
 };