// Copyright (C) 2019 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef QSSGSCENEMANAGER_P_H #define QSSGSCENEMANAGER_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include #include #include #include #include "qquick3dnode_p.h" #include QT_BEGIN_NAMESPACE class QSGDynamicTexture; class QQuickWindow; class QSSGBufferManager; class QSSGRenderContextInterface; class QSSGRenderRoot; struct QSSGRenderLayer; class Q_QUICK3D_EXPORT QQuick3DWindowAttachment : public QObject { Q_OBJECT public: enum SyncResultFlag : quint32 { None, SharedResourcesDirty = 0x1, ExtensionsDiry = 0x2, }; using SyncResult = std::underlying_type_t; explicit QQuick3DWindowAttachment(QQuickWindow *window); ~QQuick3DWindowAttachment() override; Q_INVOKABLE void preSync(); Q_INVOKABLE void cleanupResources(); Q_INVOKABLE SyncResult synchronize(QSet &resourceLoaders); Q_INVOKABLE void requestUpdate(); Q_INVOKABLE void evaluateEol(); QQuickWindow *window() const; QSSGRenderRoot *rootNode() const { return m_rootNode; } const std::shared_ptr &rci() const { return m_rci; } void setRci(const std::shared_ptr &rciptr); void registerSceneManager(QQuick3DSceneManager &manager); void unregisterSceneManager(QQuick3DSceneManager &manager); void queueForCleanup(QSSGRenderGraphObject *obj); void queueForCleanup(QQuick3DSceneManager *manager); void queueForCleanup(QSSGRenderLayer *layer); Q_SIGNALS: void releaseCachedResources(); void renderContextInterfaceChanged(); private: Q_INVOKABLE void onReleaseCachedResources(); Q_INVOKABLE void onInvalidated(); QPointer m_window; QSSGRenderRoot *m_rootNode = nullptr; std::shared_ptr m_rci; QList sceneManagers; QList sceneManagerCleanupQueue; QList pendingResourceCleanupQueue; QSet resourceCleanupQueue; QList pendingLayerCleanupQueue; }; class Q_QUICK3D_EXPORT QQuick3DSceneManager : public QObject { Q_OBJECT public: using SyncResultFlag = QQuick3DWindowAttachment::SyncResultFlag; using SyncResult = QQuick3DWindowAttachment::SyncResult; explicit QQuick3DSceneManager(QObject *parent = nullptr); ~QQuick3DSceneManager() override; void setWindow(QQuickWindow *window); QQuickWindow *window(); void dirtyItem(QQuick3DObject *item); void requestUpdate(); void cleanup(QSSGRenderGraphObject *item); void polishItems(); void forcePolish(); void sync(); void preSync(); SyncResult cleanupNodes(); SyncResult updateDirtyResourceNodes(); void updateDirtySpatialNodes(); SyncResult updateDiryExtensions(); SyncResult updateDirtyResourceSecondPass(); void updateDirtyResource(QQuick3DObject *resourceObject); void updateDirtySpatialNode(QQuick3DNode *spatialNode); void updateBoundingBoxes(QSSGBufferManager &mgr); QQuick3DObject *lookUpNode(const QSSGRenderGraphObject *node) const; // Where the enumerator is placed will decide the priority it gets. // NOTE: Place new list types before 'Count'. // NOTE: InstanceNodes are nodes that have an instance root set, we'll process these // after the other nodes but before light nodes; this implies that lights are not good candidates // for being instance roots... enum class NodePriority { Skeleton, Other, ModelWithInstanceRoot, Lights, Count }; enum class ResourcePriority { TextureData, Texture, Other, Count }; enum class ExtensionPriority { RenderExtension, Count }; static inline size_t resourceListIndex(QSSGRenderGraphObject::Type type) { Q_ASSERT(!QSSGRenderGraphObject::isNodeType(type)); if (QSSGRenderGraphObject::isTexture(type)) return size_t(ResourcePriority::Texture); if (type == QSSGRenderGraphObject::Type::TextureData) return size_t(ResourcePriority::TextureData); return size_t(ResourcePriority::Other); } static inline size_t nodeListIndex(QSSGRenderGraphObject::Type type) { Q_ASSERT(QSSGRenderGraphObject::isNodeType(type)); if (QSSGRenderGraphObject::isLight(type)) return size_t(NodePriority::Lights); if (type == QSSGRenderGraphObject::Type::Skeleton) return size_t(NodePriority::Skeleton); return size_t(NodePriority::Other); } static constexpr size_t extensionListIndex(QSSGRenderGraphObject::Type type) { Q_ASSERT(QSSGRenderGraphObject::isExtension(type)); return size_t(ExtensionPriority::RenderExtension); } static QQuick3DWindowAttachment *getOrSetWindowAttachment(QQuickWindow &window); QQuick3DObject *dirtyResources[size_t(ResourcePriority::Count)] {}; QQuick3DObject *dirtyNodes[size_t(NodePriority::Count)] {}; QQuick3DObject *dirtyExtensions[size_t(ExtensionPriority::Count)] {}; // For exceptions to the norm we create a list of resources that // we get a second update. // In the case of the render extensions the resources are update first and for the // first time the extensions have not been run and therefore have no backend node, which // we'll need to use connect the render result from the extension with the texture. QSet dirtySecondPassResources; QList dirtyBoundingBoxList; QSet cleanupNodeList; QList resourceCleanupQueue; QSet parentlessItems; QVector qsgDynamicTextures; QHash m_nodeMap; QSet resourceLoaders; QQuickWindow *m_window = nullptr; QPointer wattached; int inputHandlingEnabled = 0; // Holds the count of active item2Ds, input disabled if zero. bool sharedResourceRemoved = false; friend QQuick3DObject; Q_SIGNALS: void needsUpdate(); void windowChanged(); private Q_SLOTS: SyncResult updateResources(QQuick3DObject **listHead); void updateNodes(QQuick3DObject **listHead); SyncResult updateExtensions(QQuick3DObject **listHead); }; class QSSGCleanupObject : public QObject { Q_OBJECT public: QSSGCleanupObject(std::shared_ptr rci, QList resourceCleanupQueue, QQuickWindow *window); ~QSSGCleanupObject() override; Q_INVOKABLE void cleanupResources(); private: std::shared_ptr m_rci; QPointer m_window; QList m_resourceCleanupQueue; }; QT_END_NAMESPACE QML_DECLARE_TYPE(QQuick3DSceneManager) #endif // QSSGSCENEMANAGER_P_H