11#include <QtQuick/QQuickWindow>
13#include <QtQuick3DRuntimeRender/private/qssgrenderlayer_p.h>
14#include <ssg/qssgrendercontextcore.h>
15#include <QtQuick3DRuntimeRender/private/qssgrendermodel_p.h>
16#include <QtQuick3DRuntimeRender/private/qssgrenderer_p.h>
17#include <QtQuick3DRuntimeRender/private/qssgrenderimage_p.h>
18#include <QtQuick3DRuntimeRender/private/qssgrenderlayer_p.h>
19#include <QtQuick3DRuntimeRender/private/qssgrenderroot_p.h>
20#include <QtQuick3DRuntimeRender/ssg/qssgrenderextensions.h>
21#include <QtQuick3DRuntimeRender/private/qssgrenderuserpass_p.h>
23#include <QtQuick3DUtils/private/qssgassert_p.h>
30QSSGCleanupObject::QSSGCleanupObject(std::shared_ptr<QSSGRenderContextInterface> rci, QList<QSSGRenderGraphObject *> resourceCleanupQueue, QQuickWindow *window)
34 , m_resourceCleanupQueue(resourceCleanupQueue)
36 Q_ASSERT(window !=
nullptr && rci);
38 if (QSGRenderContext *rc = QQuickWindowPrivate::get(window)->context) {
39 connect(rc, &QSGRenderContext::releaseCachedResourcesRequested,
this, &QSSGCleanupObject::cleanupResources, Qt::DirectConnection);
40 connect(rc, &QSGRenderContext::invalidated,
this, &QSSGCleanupObject::cleanupResources, Qt::DirectConnection);
42 qWarning() <<
"No QSGRenderContext, cannot cleanup resources!";
48 QSSG_CHECK(QSSG_DEBUG_COND(m_resourceCleanupQueue.isEmpty()));
53 m_rci->renderer()->cleanupResources(m_resourceCleanupQueue);
61 for (size_t i = 0; i < count; ++i) {
62 QQuick3DObject *item = head[i];
64 QQuick3DObjectPrivate *p = QQuick3DObjectPrivate::get(item);
65 QQuick3DObject *next = p->nextDirtyItem;
66 p->prevDirtyItem =
nullptr;
67 p->nextDirtyItem =
nullptr;
74QQuick3DSceneManager::QQuick3DSceneManager(QObject *parent)
81QQuick3DSceneManager::~QQuick3DSceneManager()
85 wattached->unregisterSceneManager(*
this);
100 detachDirtyList(dirtyResources, std::size(dirtyResources));
101 detachDirtyList(dirtyNodes, std::size(dirtyNodes));
102 detachDirtyList(dirtyExtensions, std::size(dirtyExtensions));
105void QQuick3DSceneManager::setWindow(QQuickWindow *window)
107 if (window == m_window)
110 if (window != m_window) {
113 wattached->unregisterSceneManager(*
this);
118 wattached = getOrSetWindowAttachment(*m_window);
120 wattached->registerSceneManager(*
this);
123 emit windowChanged();
127QQuickWindow *QQuick3DSceneManager::window()
132void QQuick3DSceneManager::dirtyItem(QQuick3DObject *item)
138void QQuick3DSceneManager::requestUpdate()
143void QQuick3DSceneManager::cleanup(QSSGRenderGraphObject *item)
145 cleanupNodeList.insert(item);
147 if (
auto front = m_nodeMap[item]) {
148 auto *po = QQuick3DObjectPrivate::get(front);
149 sharedResourceRemoved |= po->sharedResource;
150 po->spatialNode =
nullptr;
154 m_nodeMap[item] =
nullptr;
158void QQuick3DSceneManager::polishItems()
163void QQuick3DSceneManager::forcePolish()
168void QQuick3DSceneManager::sync()
173void QQuick3DSceneManager::updateBoundingBoxes(QSSGBufferManager &mgr)
175 if (lightmapSourceTracker.isDirty) {
176 mgr.setLightmapSource(lightmapSourceTracker.lightmapSource);
177 lightmapSourceTracker.isDirty =
false;
180 for (
auto *object : std::as_const(dirtyBoundingBoxList)) {
181 QQuick3DObjectPrivate *itemPriv = QQuick3DObjectPrivate::get(object);
182 if (itemPriv->sceneManager ==
nullptr)
184 auto model =
static_cast<QSSGRenderModel *>(itemPriv->spatialNode);
186 QSSGBounds3 bounds = mgr.getModelBounds(model);
187 static_cast<QQuick3DModel *>(object)->setBounds(bounds.minimum, bounds.maximum);
191 dirtyBoundingBoxList.clear();
194QQuick3DSceneManager::SyncResult QQuick3DSceneManager::updateDirtyResourceNodes()
196 SyncResult ret = SyncResultFlag::None;
198 auto it = std::begin(dirtyResources);
199 const auto end = std::end(dirtyResources);
200 for (; it != end; ++it)
201 ret |= updateResources(it);
206void QQuick3DSceneManager::updateDirtySpatialNodes()
208 auto it = std::begin(dirtyNodes);
209 const auto end = std::end(dirtyNodes);
210 for (; it != end; ++it)
214QQuick3DSceneManager::SyncResult QQuick3DSceneManager::updateDiryExtensions()
216 SyncResult ret = SyncResultFlag::None;
218 auto it = std::begin(dirtyExtensions);
219 const auto end = std::end(dirtyExtensions);
220 for (; it != end; ++it)
221 ret |= updateExtensions(it);
226QQuick3DSceneManager::SyncResult QQuick3DSceneManager::updateDirtyResourceSecondPass()
228 const auto updateDirtyResourceNode = [
this](QQuick3DObject *resource) {
229 QQuick3DObjectPrivate *po = QQuick3DObjectPrivate::get(resource);
230 po->dirtyAttributes = 0;
231 po->secondaryUpdateRequested =
false;
232 QSSGRenderGraphObject *node = po->spatialNode;
233 po->spatialNode = resource->updateSpatialNode(node);
235 m_nodeMap.insert(po->spatialNode, resource);
236 return po->sharedResource ? SyncResultFlag::SharedResourcesDirty : SyncResultFlag::None;
239 SyncResult res = SyncResultFlag::None;
240 auto it = dirtySecondPassResources.constBegin();
241 const auto end = dirtySecondPassResources.constEnd();
242 for (; it != end; ++it)
243 res |= updateDirtyResourceNode(*it);
248 dirtySecondPassResources = {};
253void QQuick3DSceneManager::updateDirtyResource(QQuick3DObject *resourceObject)
255 QQuick3DObjectPrivate *itemPriv = QQuick3DObjectPrivate::get(resourceObject);
256 quint32 dirty = itemPriv->dirtyAttributes;
258 itemPriv->dirtyAttributes = 0;
259 QSSGRenderGraphObject *oldNode = itemPriv->spatialNode;
260 QSSGRenderGraphObject *newNode = resourceObject->updateSpatialNode(itemPriv->spatialNode);
262 const bool backendNodeChanged = oldNode != newNode;
265 if (oldNode && backendNodeChanged)
270 itemPriv->spatialNode = newNode;
272 if (itemPriv->spatialNode) {
273 m_nodeMap.insert(itemPriv->spatialNode, resourceObject);
274 if (itemPriv->spatialNode->type == QSSGRenderGraphObject::Type::ResourceLoader) {
275 resourceLoaders.insert(itemPriv->spatialNode);
276 }
else if (itemPriv->spatialNode->type == QQuick3DObjectPrivate::Type::Image2D && backendNodeChanged) {
277 ++inputHandlingEnabled;
278 }
else if (QSSGRenderGraphObjectUtils::isUserRenderPass(itemPriv->type) && itemPriv->spatialNode) {
279 auto *userRenderPass =
static_cast<QSSGRenderUserPass *>(itemPriv->spatialNode);
280 if (
const auto idx = userRenderPasses.indexOf(userRenderPass); idx == -1)
281 userRenderPasses.push_back(userRenderPass);
285 if (itemPriv->hasFlag(QQuick3DObjectPrivate::Flags::RequiresSecondaryUpdate) && itemPriv->secondaryUpdateRequested)
286 dirtySecondPassResources.insert(resourceObject);
291void QQuick3DSceneManager::updateDirtySpatialNode(QQuick3DNode *spatialNode)
293 const auto prepNewSpatialNode = [
this](QSSGRenderNode *node) {
295 node->rootNodeRef = wattached->rootNode()->rootNodeRef;
296 Q_ASSERT(QSSGRenderRoot::get(node->rootNodeRef) !=
nullptr);
300 QQuick3DObjectPrivate *itemPriv = QQuick3DObjectPrivate::get(spatialNode);
301 quint32 dirty = itemPriv->dirtyAttributes;
302 itemPriv->dirtyAttributes = 0;
303 QSSGRenderGraphObject *oldNode = itemPriv->spatialNode;
304 QSSGRenderGraphObject *newNode = spatialNode->updateSpatialNode(oldNode);
306 const bool backendNodeChanged = oldNode != newNode;
309 if (oldNode && backendNodeChanged)
314 itemPriv->spatialNode = newNode;
315 prepNewSpatialNode(
static_cast<QSSGRenderNode *>(itemPriv->spatialNode));
320 if (itemPriv->spatialNode) {
321 m_nodeMap.insert(itemPriv->spatialNode, spatialNode);
322 if (itemPriv->type == QQuick3DObjectPrivate::Type::Item2D && itemPriv->spatialNode != oldNode)
323 ++inputHandlingEnabled;
326 QSSGRenderNode *graphNode =
static_cast<QSSGRenderNode *>(itemPriv->spatialNode);
328 if (graphNode && graphNode->parent && dirty & QQuick3DObjectPrivate::ParentChanged) {
329 QQuick3DNode *nodeParent = qobject_cast<QQuick3DNode *>(spatialNode->parentItem());
331 QSSGRenderNode *parentGraphNode =
static_cast<QSSGRenderNode *>(
332 QQuick3DObjectPrivate::get(nodeParent)->spatialNode);
333 if (parentGraphNode) {
334 graphNode->parent->removeChild(*graphNode);
335 parentGraphNode->addChild(*graphNode);
340 if (graphNode && graphNode->parent ==
nullptr) {
341 QQuick3DNode *nodeParent = qobject_cast<QQuick3DNode *>(spatialNode->parentItem());
343 QSSGRenderNode *parentGraphNode =
static_cast<QSSGRenderNode *>(QQuick3DObjectPrivate::get(nodeParent)->spatialNode);
344 if (!parentGraphNode) {
346 auto parentNode = QQuick3DObjectPrivate::get(nodeParent);
347 parentNode->spatialNode = nodeParent->updateSpatialNode(parentNode->spatialNode);
348 if (parentNode->spatialNode)
349 m_nodeMap.insert(parentNode->spatialNode, nodeParent);
350 parentGraphNode =
static_cast<QSSGRenderNode *>(parentNode->spatialNode);
351 prepNewSpatialNode(parentGraphNode);
354 parentGraphNode->addChild(*graphNode);
356 QQuick3DViewport *viewParent = qobject_cast<QQuick3DViewport *>(spatialNode->parent());
358 auto sceneRoot = QQuick3DObjectPrivate::get(viewParent->scene());
359 if (!sceneRoot->spatialNode)
360 sceneRoot->spatialNode = viewParent->scene()->updateSpatialNode(sceneRoot->spatialNode);
361 if (sceneRoot->spatialNode) {
362 auto *sceneRootNode =
static_cast<QSSGRenderNode *>(sceneRoot->spatialNode);
363 prepNewSpatialNode(sceneRootNode);
364 m_nodeMap.insert(sceneRootNode, viewParent->scene());
365 sceneRootNode->addChild(*graphNode);
372QQuick3DObject *QQuick3DSceneManager::lookUpNode(
const QSSGRenderGraphObject *node)
const
374 return m_nodeMap[
const_cast<QSSGRenderGraphObject *>(node)];
377QQuick3DWindowAttachment *QQuick3DSceneManager::getOrSetWindowAttachment(QQuickWindow &window)
380 QQuick3DWindowAttachment *wa =
nullptr;
381 if (
auto aProperty = window.property(qtQQ3DWAPropName); aProperty.isValid())
382 wa = aProperty.value<QQuick3DWindowAttachment *>();
388 wa =
new QQuick3DWindowAttachment(&window);
389 window.setProperty(qtQQ3DWAPropName, QVariant::fromValue(wa));
395QQuick3DSceneManager::SyncResult QQuick3DSceneManager::cleanupNodes()
397 SyncResult res = sharedResourceRemoved ? SyncResultFlag::SharedResourcesDirty : SyncResultFlag::None;
399 sharedResourceRemoved =
false;
400 for (
auto node : std::as_const(cleanupNodeList)) {
402 if (QSSGRenderGraphObject::isNodeType(node->type)) {
403 QSSGRenderNode *spatialNode =
static_cast<QSSGRenderNode *>(node);
404 spatialNode->removeFromGraph();
407 if (node->type == QQuick3DObjectPrivate::Type::Item2D) {
408 --inputHandlingEnabled;
409 }
else if (node->type == QQuick3DObjectPrivate::Type::Image2D) {
410 auto image =
static_cast<QSSGRenderImage *>(node);
411 if (image && image->m_qsgTexture !=
nullptr ) {
412 --inputHandlingEnabled;
418 m_nodeMap.remove(node);
420 if (QSSGRenderGraphObjectUtils::hasInternalFlag(*node, QSSGRenderGraphObjectUtils::InternalFlags::AutoRegisterExtension)) {
421 autoRegisteredExtensions.removeAll(node);
422 autoRegisteredExtensionsDirty =
true;
425 if (QSSGRenderGraphObjectUtils::isUserRenderPass(node->type)) {
426 auto *userRenderPass =
static_cast<QSSGRenderUserPass *>(node);
427 if (qsizetype idx = userRenderPasses.indexOf(userRenderPass); idx != -1)
428 userRenderPasses.remove(idx);
434 if (node->hasGraphicsResources()) {
435 wattached->queueForCleanup(node);
436 if (node->type == QSSGRenderGraphObject::Type::ResourceLoader)
437 resourceLoaders.remove(node);
444 cleanupNodeList.clear();
449QQuick3DSceneManager::SyncResult QQuick3DSceneManager::updateResources(QQuick3DObject **listHead)
451 SyncResult res = SyncResultFlag::None;
456 bool hasSharedResources =
false;
457 QQuick3DObject *updateList = *listHead;
460 QQuick3DObjectPrivate::get(updateList)->prevDirtyItem = &updateList;
462 QQuick3DObject *item = updateList;
465 Q_ASSERT(!QSSGRenderGraphObject::isNodeType(QQuick3DObjectPrivate::get(item)->type) || !QSSGRenderGraphObject::isExtension(QQuick3DObjectPrivate::get(item)->type));
467 updateDirtyResource(item);
468 auto *po = QQuick3DObjectPrivate::get(item);
469 hasSharedResources |= po->sharedResource;
470 po->removeFromDirtyList();
474 if (hasSharedResources)
475 res |= SyncResultFlag::SharedResourcesDirty;
480void QQuick3DSceneManager::updateNodes(QQuick3DObject **listHead)
485 QQuick3DObject *updateList = *listHead;
488 QQuick3DObjectPrivate::get(updateList)->prevDirtyItem = &updateList;
490 QQuick3DObject *item = updateList;
493 Q_ASSERT(QSSGRenderGraphObject::isNodeType(QQuick3DObjectPrivate::get(item)->type));
495 updateDirtySpatialNode(
static_cast<QQuick3DNode *>(item));
496 QQuick3DObjectPrivate::get(item)->removeFromDirtyList();
501QQuick3DSceneManager::SyncResult QQuick3DSceneManager::updateExtensions(QQuick3DObject **listHead)
503 SyncResult ret = SyncResultFlag::None;
505 const auto updateDirtyExtensionNode = [
this, &ret](QQuick3DObject *extension) {
506 QQuick3DObjectPrivate *po = QQuick3DObjectPrivate::get(extension);
507 po->dirtyAttributes = 0;
508 QSSGRenderGraphObject *oldNode = po->spatialNode;
509 QSSGRenderGraphObject *newNode = extension->updateSpatialNode(oldNode);
511 const bool backendNodeChanged = oldNode != newNode;
513 if (backendNodeChanged)
514 ret |= SyncResultFlag::ExtensionsDiry;
517 if (oldNode && backendNodeChanged)
522 po->spatialNode = newNode;
525 m_nodeMap.insert(po->spatialNode, extension);
527 if (newNode && QSSGRenderGraphObjectUtils::hasInternalFlag(*newNode, QSSGRenderGraphObjectUtils::InternalFlags::AutoRegisterExtension)) {
528 const bool shouldInsert = autoRegisteredExtensions.indexOf(
static_cast<QSSGRenderExtension *>(newNode)) == -1;
530 autoRegisteredExtensions.push_back(
static_cast<QSSGRenderExtension *>(newNode));
531 autoRegisteredExtensionsDirty =
true;
539 QQuick3DObject *updateList = *listHead;
542 QQuick3DObjectPrivate::get(updateList)->prevDirtyItem = &updateList;
544 QQuick3DObject *item = updateList;
547 Q_ASSERT(QSSGRenderGraphObject::isExtension(QQuick3DObjectPrivate::get(item)->type));
549 updateDirtyExtensionNode(item);
550 QQuick3DObjectPrivate::get(item)->removeFromDirtyList();
557void QQuick3DSceneManager::preSync()
559 for (
auto it = std::begin(dirtyResources), end = std::end(dirtyResources); it != end; ++it) {
560 QQuick3DObject *next = *it;
563 next = QQuick3DObjectPrivate::get(next)->nextDirtyItem;
567 for (
auto it = std::begin(dirtyNodes), end = std::end(dirtyNodes); it != end; ++it) {
568 QQuick3DObject *next = *it;
571 next = QQuick3DObjectPrivate::get(next)->nextDirtyItem;
575 for (
auto it = std::begin(dirtyExtensions), end = std::end(dirtyExtensions); it != end; ++it) {
576 QQuick3DObject *next = *it;
579 next = QQuick3DObjectPrivate::get(next)->nextDirtyItem;
588QQuick3DWindowAttachment::QQuick3DWindowAttachment(QQuickWindow *window)
590 , m_rootNode(
new QSSGRenderRoot)
598 QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
599 QSGRenderContext *rc = wd->context;
600 if (QSSG_GUARD_X(rc,
"QQuickWindow has no QSGRenderContext, this should not happen")) {
602 connect(rc, &QSGRenderContext::releaseCachedResourcesRequested,
this, &QQuick3DWindowAttachment::onReleaseCachedResources, Qt::DirectConnection);
603 connect(rc, &QSGRenderContext::invalidated,
this, &QQuick3DWindowAttachment::onInvalidated, Qt::DirectConnection);
607 connect(window, &QQuickWindow::destroyed,
this, &QQuick3DWindowAttachment::evaluateEol);
609 connect(window, &QQuickWindow::afterAnimating,
this, &QQuick3DWindowAttachment::preSync);
611 connect(window, &QQuickWindow::afterFrameEnd,
this, &QQuick3DWindowAttachment::cleanupResources, Qt::DirectConnection);
615QQuick3DWindowAttachment::~QQuick3DWindowAttachment()
617 for (
auto *manager : std::as_const(sceneManagerCleanupQueue)) {
618 sceneManagers.removeOne(manager);
622 qDeleteAll(sceneManagers);
623 QSSG_CHECK(QSSG_DEBUG_COND(resourceCleanupQueue.isEmpty()));
625 if (!pendingResourceCleanupQueue.isEmpty()) {
631 if (m_rci && m_window) {
632 new QSSGCleanupObject(m_rci, std::move(pendingResourceCleanupQueue), m_window);
633 QMetaObject::invokeMethod(m_window, &QQuickWindow::releaseResources, Qt::QueuedConnection);
635 qWarning() <<
"Pending resource cleanup queue not empty, but no RCI or window to clean it up!";
640 m_window->setProperty(qtQQ3DWAPropName, QVariant());
645void QQuick3DWindowAttachment::preSync()
647 for (
auto &sceneManager : std::as_const(sceneManagers))
648 sceneManager->preSync();
652void QQuick3DWindowAttachment::cleanupResources()
667 if (resourceCleanupQueue.size() != 0)
668 m_rci->renderer()->cleanupResources(resourceCleanupQueue);
672void QQuick3DWindowAttachment::onReleaseCachedResources()
675 m_rci->releaseCachedResources();
676 Q_EMIT releaseCachedResources();
679void QQuick3DWindowAttachment::onInvalidated()
686 for (
auto &sceneManager : std::as_const(sceneManagers)) {
687 const auto objects = sceneManager->m_nodeMap.keys();
688 for (QSSGRenderGraphObject *obj : objects) {
689 if (obj->hasGraphicsResources())
690 sceneManager->cleanup(obj);
695 for (
auto &sceneManager : std::as_const(sceneManagers))
696 sceneManager->cleanupNodes();
698 for (QSSGRenderLayer *layers : std::as_const(pendingLayerCleanupQueue))
700 pendingLayerCleanupQueue.clear();
702 for (
const auto &pr : std::as_const(pendingResourceCleanupQueue))
703 resourceCleanupQueue.insert(pr);
704 pendingResourceCleanupQueue.clear();
710 onReleaseCachedResources();
718 if (m_rci.use_count() == 1) {
720 emit renderContextInterfaceChanged();
724QQuick3DWindowAttachment::SyncResult QQuick3DWindowAttachment::synchronize(QSet<QSSGRenderGraphObject *> &resourceLoaders)
727 for (
auto *manager : std::as_const(sceneManagerCleanupQueue)) {
728 sceneManagers.removeOne(manager);
732 sceneManagerCleanupQueue = {};
734 SyncResult syncResult = SyncResultFlag::None;
737 for (
auto &sceneManager : std::as_const(sceneManagers))
738 syncResult |= sceneManager->cleanupNodes();
740 for (QSSGRenderLayer *layers : std::as_const(pendingLayerCleanupQueue))
742 pendingLayerCleanupQueue.clear();
745 for (
auto &sceneManager : std::as_const(sceneManagers))
746 syncResult |= sceneManager->updateDirtyResourceNodes();
748 for (
auto &sceneManager : std::as_const(sceneManagers))
749 sceneManager->updateDirtySpatialNodes();
750 for (
auto &sceneManager : std::as_const(sceneManagers))
751 syncResult |= sceneManager->updateDiryExtensions();
752 for (
auto &sceneManager : std::as_const(sceneManagers))
753 syncResult |= sceneManager->updateDirtyResourceSecondPass();
755 for (
auto &sceneManager : std::as_const(sceneManagers))
756 sceneManager->updateBoundingBoxes(*m_rci->bufferManager());
758 for (
auto &sceneManager : std::as_const(sceneManagers))
759 resourceLoaders.unite(sceneManager->resourceLoaders);
761 if ((syncResult & SyncResultFlag::SharedResourcesDirty)) {
764 for (
auto &sceneManager : std::as_const(sceneManagers))
765 sceneManager->requestUpdate();
769 for (
const auto &pr : std::as_const(pendingResourceCleanupQueue))
770 resourceCleanupQueue.insert(pr);
771 pendingResourceCleanupQueue.clear();
776void QQuick3DWindowAttachment::requestUpdate()
778 for (
const auto &sm : std::as_const(sceneManagers))
782void QQuick3DWindowAttachment::evaluateEol()
786 for (QQuick3DSceneManager *manager : std::as_const(sceneManagerCleanupQueue))
787 sceneManagers.removeOne(manager);
796 if (sceneManagers.isEmpty() && m_window.isNull())
800QQuickWindow *QQuick3DWindowAttachment::window()
const {
return m_window; }
802void QQuick3DWindowAttachment::setRci(
const std::shared_ptr<QSSGRenderContextInterface> &rciptr)
804 QSSG_CHECK_X(m_rci ==
nullptr || m_rci.use_count() == 1,
"Old render context was not released!");
808 if (m_rci && m_window)
809 QSSGRendererPrivate::setSgRenderContext(*m_rci->renderer(), QQuickWindowPrivate::get(m_window)->context);
811 emit renderContextInterfaceChanged();
814void QQuick3DWindowAttachment::registerSceneManager(QQuick3DSceneManager &manager)
816 if (!sceneManagers.contains(&manager))
817 sceneManagers.push_back(&manager);
820void QQuick3DWindowAttachment::unregisterSceneManager(QQuick3DSceneManager &manager)
822 sceneManagers.removeOne(&manager);
825void QQuick3DWindowAttachment::queueForCleanup(QSSGRenderGraphObject *obj)
827 Q_ASSERT(obj->hasGraphicsResources());
828 pendingResourceCleanupQueue.push_back(obj);
831void QQuick3DWindowAttachment::queueForCleanup(QQuick3DSceneManager *manager)
833 if (!sceneManagerCleanupQueue.contains(manager))
834 sceneManagerCleanupQueue.push_back(manager);
837void QQuick3DWindowAttachment::queueForCleanup(QSSGRenderLayer *layer)
839 if (QSSGRenderRoot *lr = QSSGRenderRoot::get(layer->rootNodeRef); lr != m_rootNode) {
840 qWarning(
"Attempted to queue layer for cleanup that is not part of the current window!");
844 if (!pendingLayerCleanupQueue.contains(layer)) {
845 layer->removeFromGraph();
846 pendingLayerCleanupQueue.push_back(layer);
~QSSGCleanupObject() override
Q_INVOKABLE void cleanupResources()
Combined button and popup list for selecting options.
static void detachDirtyList(QQuick3DObject **head, size_t count)
static constexpr char qtQQ3DWAPropName[]