diff options
Diffstat (limited to 'src/quick3d/imports')
-rw-r--r-- | src/quick3d/imports/scene3d/importsscene3d.pro | 2 | ||||
-rw-r--r-- | src/quick3d/imports/scene3d/scene3dcleaner.cpp | 75 | ||||
-rw-r--r-- | src/quick3d/imports/scene3d/scene3dcleaner_p.h | 82 | ||||
-rw-r--r-- | src/quick3d/imports/scene3d/scene3ditem.cpp | 106 | ||||
-rw-r--r-- | src/quick3d/imports/scene3d/scene3ditem_p.h | 10 | ||||
-rw-r--r-- | src/quick3d/imports/scene3d/scene3drenderer.cpp | 44 | ||||
-rw-r--r-- | src/quick3d/imports/scene3d/scene3drenderer_p.h | 15 |
7 files changed, 123 insertions, 211 deletions
diff --git a/src/quick3d/imports/scene3d/importsscene3d.pro b/src/quick3d/imports/scene3d/importsscene3d.pro index a8ad8f417..6244f4b5b 100644 --- a/src/quick3d/imports/scene3d/importsscene3d.pro +++ b/src/quick3d/imports/scene3d/importsscene3d.pro @@ -16,7 +16,6 @@ HEADERS += \ qtquickscene3dplugin.h \ scene3dlogging_p.h \ scene3ditem_p.h \ - scene3dcleaner_p.h \ scene3drenderer_p.h \ scene3dsgnode_p.h \ scene3dsgmaterialshader_p.h \ @@ -26,7 +25,6 @@ SOURCES += \ qtquickscene3dplugin.cpp \ scene3ditem.cpp \ scene3dlogging.cpp \ - scene3dcleaner.cpp \ scene3drenderer.cpp \ scene3dsgnode.cpp \ scene3dsgmaterialshader.cpp \ diff --git a/src/quick3d/imports/scene3d/scene3dcleaner.cpp b/src/quick3d/imports/scene3d/scene3dcleaner.cpp deleted file mode 100644 index ec371410d..000000000 --- a/src/quick3d/imports/scene3d/scene3dcleaner.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/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 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "scene3dcleaner_p.h" - -#include <Qt3DCore/qaspectengine.h> -#include <QtCore/qthread.h> - -#include <scene3dlogging_p.h> -#include <scene3drenderer_p.h> - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -Scene3DCleaner::Scene3DCleaner(QObject *parent) - : QObject(parent) - , m_renderer(nullptr) -{ -} - -Scene3DCleaner::~Scene3DCleaner() -{ - qCDebug(Scene3D) << Q_FUNC_INFO << QThread::currentThread(); -} - -void Scene3DCleaner::cleanup() -{ - Q_ASSERT(m_renderer); - delete m_renderer->m_aspectEngine; // also deletes m_renderer->m_renderAspect - m_renderer->m_aspectEngine = nullptr; - m_renderer->m_renderAspect = nullptr; - m_renderer->deleteLater(); - deleteLater(); -} - -} // namespace Qt3DRender - -QT_END_NAMESPACE diff --git a/src/quick3d/imports/scene3d/scene3dcleaner_p.h b/src/quick3d/imports/scene3d/scene3dcleaner_p.h deleted file mode 100644 index a246cbde7..000000000 --- a/src/quick3d/imports/scene3d/scene3dcleaner_p.h +++ /dev/null @@ -1,82 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt3D 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 The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/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 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QT3DRENDER_SCENE3DCLEANER_P_H -#define QT3DRENDER_SCENE3DCLEANER_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 <QtCore/QObject> - -QT_BEGIN_NAMESPACE - -namespace Qt3DRender { - -class Scene3DRenderer; - -class Scene3DCleaner : public QObject -{ - Q_OBJECT -public: - explicit Scene3DCleaner(QObject *parent = 0); - ~Scene3DCleaner(); - - void setRenderer(Scene3DRenderer *renderer) { m_renderer = renderer; } - -public Q_SLOTS: - void cleanup(); - -private: - Scene3DRenderer *m_renderer; -}; - -} // namespace Qt3DRender - -QT_END_NAMESPACE - -#endif // QT3DRENDER_SCENE3DCLEANER_H diff --git a/src/quick3d/imports/scene3d/scene3ditem.cpp b/src/quick3d/imports/scene3d/scene3ditem.cpp index eb8c6ffd9..1444eb0a0 100644 --- a/src/quick3d/imports/scene3d/scene3ditem.cpp +++ b/src/quick3d/imports/scene3d/scene3ditem.cpp @@ -67,7 +67,6 @@ #include <Qt3DRender/private/qrendersurfaceselector_p.h> #include <Qt3DRender/private/qrenderaspect_p.h> -#include <scene3dcleaner_p.h> #include <scene3dlogging_p.h> #include <scene3drenderer_p.h> #include <scene3dsgnode_p.h> @@ -123,8 +122,8 @@ Scene3DItem::Scene3DItem(QQuickItem *parent) , m_entity(nullptr) , m_aspectEngine(new Qt3DCore::QAspectEngine()) , m_renderAspect(nullptr) + , m_aspectToDelete(nullptr) , m_renderer(nullptr) - , m_rendererCleaner(new Scene3DCleaner()) , m_multisample(true) , m_cameraAspectRatioMode(AutomaticAspectRatio) { @@ -138,6 +137,8 @@ Scene3DItem::~Scene3DItem() // When the window is closed, it first destroys all of its children. At // this point, Scene3DItem is destroyed but the Renderer, AspectEngine and // Scene3DSGNode still exist and will perform their cleanup on their own. + m_aspectEngine->deleteLater(); + m_renderer->deleteLater(); } /*! @@ -163,18 +164,15 @@ QStringList Scene3DItem::aspects() const */ Qt3DCore::QEntity *Scene3DItem::entity() const { - return m_entity; + return m_entity.data(); } -void Scene3DItem::setAspects(const QStringList &aspects) +void Scene3DItem::applyAspects() { if (!m_aspects.isEmpty()) { qWarning() << "Aspects already set on the Scene3D, ignoring"; return; } - - m_aspects = aspects; - // Aspects are owned by the aspect engine for (const QString &aspect : qAsConst(m_aspects)) { if (aspect == QLatin1String("render")) // This one is hardwired anyway @@ -205,16 +203,27 @@ void Scene3DItem::setAspects(const QStringList &aspects) } m_aspectEngine->registerAspect(aspect); } +} + +void Scene3DItem::setAspects(const QStringList &aspects) +{ + if (!m_aspects.isEmpty()) { + qWarning() << "Aspects already set on the Scene3D, ignoring"; + return; + } + + m_aspects = aspects; + applyAspects(); emit aspectsChanged(); } void Scene3DItem::setEntity(Qt3DCore::QEntity *entity) { - if (entity == m_entity) + if (entity == m_entity.data()) return; - m_entity = entity; + m_entity.reset(entity); emit entityChanged(); } @@ -253,14 +262,21 @@ Scene3DItem::CameraAspectRatioMode Scene3DItem::cameraAspectRatioMode() const void Scene3DItem::applyRootEntityChange() { - if (m_aspectEngine->rootEntity() != m_entity) { - m_aspectEngine->setRootEntity(Qt3DCore::QEntityPtr(m_entity)); + if (m_aspectEngine->rootEntity() != m_entity.data()) { + m_aspectEngine->setRootEntity(m_entity); + + /* If we changed window, the old aspect engine must be deleted only after we have set + the root entity for the new one so that it doesn't delete the root node. */ + if (m_aspectToDelete) { + delete m_aspectToDelete; + m_aspectToDelete = nullptr; + } // Set the render surface if (!m_entity) return; - setWindowSurface(m_entity); + setWindowSurface(entity()); if (m_cameraAspectRatioMode == AutomaticAspectRatio) { // Set aspect ratio of first camera to match the window @@ -286,6 +302,20 @@ void Scene3DItem::applyRootEntityChange() } } +void Scene3DItem::updateWindowSurface() +{ + if (!m_entity || !m_dummySurface) + return; + Qt3DRender::QRenderSurfaceSelector *surfaceSelector = + Qt3DRender::QRenderSurfaceSelectorPrivate::find(entity()); + if (surfaceSelector) { + if (QWindow *rw = QQuickRenderControl::renderWindowFor(this->window())) { + m_dummySurface->deleteLater(); + createDummySurface(rw, surfaceSelector); + } + } +} + void Scene3DItem::setWindowSurface(QObject *rootObject) { Qt3DRender::QRenderSurfaceSelector *surfaceSelector = Qt3DRender::QRenderSurfaceSelectorPrivate::find(rootObject); @@ -296,20 +326,25 @@ void Scene3DItem::setWindowSurface(QObject *rootObject) // We may not have a real, exposed QQuickWindow when the Quick rendering // is redirected via QQuickRenderControl (f.ex. QQuickWidget). if (QWindow *rw = QQuickRenderControl::renderWindowFor(this->window())) { - // rw is the top-level window that is backed by a native window. Do - // not use that though since we must not clash with e.g. the widget - // backingstore compositor in the gui thread. - m_dummySurface = new QOffscreenSurface; - m_dummySurface->setParent(qGuiApp); // parent to something suitably long-living - m_dummySurface->setFormat(rw->format()); - m_dummySurface->setScreen(rw->screen()); - m_dummySurface->create(); - surfaceSelector->setSurface(m_dummySurface); + createDummySurface(rw, surfaceSelector); } else { surfaceSelector->setSurface(this->window()); } } } + +void Scene3DItem::createDummySurface(QWindow *rw, Qt3DRender::QRenderSurfaceSelector *surfaceSelector) +{ + // rw is the top-level window that is backed by a native window. Do + // not use that though since we must not clash with e.g. the widget + // backingstore compositor in the gui thread. + m_dummySurface = new QOffscreenSurface; + m_dummySurface->setParent(qGuiApp); // parent to something suitably long-living + m_dummySurface->setFormat(rw->format()); + m_dummySurface->setScreen(rw->screen()); + m_dummySurface->create(); + surfaceSelector->setSurface(m_dummySurface); +} /*! \qmlmethod void Scene3D::setItemAreaAndDevicePixelRatio(size area, real devicePixelRatio) @@ -317,7 +352,8 @@ void Scene3DItem::setWindowSurface(QObject *rootObject) */ void Scene3DItem::setItemAreaAndDevicePixelRatio(QSize area, qreal devicePixelRatio) { - Qt3DRender::QRenderSurfaceSelector *surfaceSelector = Qt3DRender::QRenderSurfaceSelectorPrivate::find(m_entity); + Qt3DRender::QRenderSurfaceSelector *surfaceSelector + = Qt3DRender::QRenderSurfaceSelectorPrivate::find(entity()); if (surfaceSelector) { surfaceSelector->setExternalRenderTargetSize(area); surfaceSelector->setSurfacePixelRatio(devicePixelRatio); @@ -387,6 +423,20 @@ void Scene3DItem::setMultisample(bool enable) QSGNode *Scene3DItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *) { + // m_resetRequested is set to true by Scene3DRenderer::shutdown() + if (m_renderer && m_renderer->m_resetRequested) { + qCWarning(Scene3D) << "Renderer for Scene3DItem has requested a reset due to the item " + "moving to another window"; + m_aspectEngine->unregisterAspect(m_renderAspect); // Deletes the renderAspect + m_renderAspect = nullptr; + m_aspectToDelete = m_aspectEngine; + m_aspectEngine = new Qt3DCore::QAspectEngine(); + applyAspects(); + // Needs to belong in the same thread as the item which is the same as the original + // QAspectEngine + m_aspectEngine->moveToThread(thread()); + m_renderer->m_resetRequested = false; + } // If the render aspect wasn't created yet, do so now if (m_renderAspect == nullptr) { m_renderAspect = new QRenderAspect(QRenderAspect::Synchronous); @@ -397,8 +447,16 @@ QSGNode *Scene3DItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNode } if (m_renderer == nullptr) { - m_renderer = new Scene3DRenderer(this, m_aspectEngine, m_renderAspect); - m_renderer->setCleanerHelper(m_rendererCleaner); + m_renderer = new Scene3DRenderer(); + m_renderer->init(this, m_aspectEngine, m_renderAspect); + } else if (m_renderer->renderAspect() != m_renderAspect) { + // If the renderer's renderAspect is not equal to the aspect used + // by the item, then it means that we have created a new one due to + // the fact that shutdown() was called on the renderer previously. + // This is a typical situation when the window the item is in has + // moved from one screen to another. + updateWindowSurface(); + m_renderer->init(this, m_aspectEngine, m_renderAspect); } Scene3DSGNode *fboNode = static_cast<Scene3DSGNode *>(node); diff --git a/src/quick3d/imports/scene3d/scene3ditem_p.h b/src/quick3d/imports/scene3d/scene3ditem_p.h index 4106ff459..ddb462011 100644 --- a/src/quick3d/imports/scene3d/scene3ditem_p.h +++ b/src/quick3d/imports/scene3d/scene3ditem_p.h @@ -68,7 +68,7 @@ namespace Qt3DRender { class QCamera; class QRenderAspect; class Scene3DRenderer; -class Scene3DCleaner; +class QRenderSurfaceSelector; class Scene3DItem : public QQuickItem { @@ -120,14 +120,18 @@ private: void setCameraAspectModeHelper(); void updateCameraAspectRatio(); void mousePressEvent(QMouseEvent *event) override; + void updateWindowSurface(); + void createDummySurface(QWindow *window, QRenderSurfaceSelector *surfaceSelector); + void applyAspects(); QStringList m_aspects; - Qt3DCore::QEntity *m_entity; + // Store as shared pointer so that aspect engine doesn't delete it. + QSharedPointer<Qt3DCore::QEntity> m_entity; Qt3DCore::QAspectEngine *m_aspectEngine; + Qt3DCore::QAspectEngine *m_aspectToDelete; QRenderAspect *m_renderAspect; Scene3DRenderer *m_renderer; - Scene3DCleaner *m_rendererCleaner; bool m_multisample; diff --git a/src/quick3d/imports/scene3d/scene3drenderer.cpp b/src/quick3d/imports/scene3d/scene3drenderer.cpp index b96fc516d..7ca658316 100644 --- a/src/quick3d/imports/scene3d/scene3drenderer.cpp +++ b/src/quick3d/imports/scene3d/scene3drenderer.cpp @@ -48,7 +48,7 @@ #include <Qt3DRender/private/qrenderaspect_p.h> #include <Qt3DCore/private/qaspectengine_p.h> -#include <scene3dcleaner_p.h> + #include <scene3ditem_p.h> #include <scene3dlogging_p.h> #include <scene3dsgnode_p.h> @@ -123,16 +123,15 @@ private: signal of the window is not called. Therefore the cleanup method is invoked to properly destroy the aspect engine. */ -Scene3DRenderer::Scene3DRenderer(Scene3DItem *item, Qt3DCore::QAspectEngine *aspectEngine, QRenderAspect *renderAspect) +Scene3DRenderer::Scene3DRenderer() : QObject() - , m_item(item) - , m_aspectEngine(aspectEngine) - , m_renderAspect(renderAspect) + , m_item(nullptr) + , m_aspectEngine(nullptr) + , m_renderAspect(nullptr) , m_multisampledFBO(nullptr) , m_finalFBO(nullptr) , m_texture(nullptr) , m_node(nullptr) - , m_cleaner(nullptr) , m_window(nullptr) , m_multisample(false) // this value is not used, will be synced from the Scene3DItem instead , m_lastMultisample(false) @@ -140,6 +139,17 @@ Scene3DRenderer::Scene3DRenderer(Scene3DItem *item, Qt3DCore::QAspectEngine *asp , m_blocking(false) , m_forceRecreate(false) { +} + +void Scene3DRenderer::init(Scene3DItem *item, Qt3DCore::QAspectEngine *aspectEngine, + QRenderAspect *renderAspect) +{ + m_item = item; + m_window = m_item->window(); + m_aspectEngine = aspectEngine; + m_renderAspect = renderAspect; + m_needsShutdown = true; + Q_CHECK_PTR(m_item); Q_CHECK_PTR(m_item->window()); @@ -192,21 +202,14 @@ void Scene3DRenderer::scheduleRootEntityChange() QMetaObject::invokeMethod(m_item, "applyRootEntityChange", Qt::QueuedConnection); } -void Scene3DRenderer::setCleanerHelper(Scene3DCleaner *cleaner) -{ - m_cleaner = cleaner; - if (m_cleaner) { - // Window closed case - QObject::connect(m_item->window(), &QQuickWindow::destroyed, m_cleaner, &Scene3DCleaner::cleanup); - m_cleaner->setRenderer(this); - } -} - // Executed in the QtQuick render thread (which may even be the gui/main with QQuickWidget / RenderControl). void Scene3DRenderer::shutdown() { qCDebug(Scene3D) << Q_FUNC_INFO << QThread::currentThread(); + // In case the same item is rendered on another window reset it + m_resetRequested = true; + // Set to null so that subsequent calls to render // would return early m_item = nullptr; @@ -220,8 +223,13 @@ void Scene3DRenderer::shutdown() // Shutdown the Renderer Aspect while the OpenGL context // is still valid - if (m_renderAspect) + if (m_renderAspect) { static_cast<QRenderAspectPrivate*>(QRenderAspectPrivate::get(m_renderAspect))->renderShutdown(); + m_renderAspect = nullptr; + } + m_aspectEngine = nullptr; + m_finalFBO.reset(); + m_multisampledFBO.reset(); } // QtQuick render thread (which may also be the gui/main thread with QQuickWidget / RenderControl) @@ -231,7 +239,6 @@ void Scene3DRenderer::onSceneGraphInvalidated() if (m_needsShutdown) { m_needsShutdown = false; shutdown(); - QMetaObject::invokeMethod(m_cleaner, "cleanup"); } } @@ -242,7 +249,6 @@ void Scene3DRenderer::onWindowChanged(QQuickWindow *w) if (m_needsShutdown) { m_needsShutdown = false; shutdown(); - QMetaObject::invokeMethod(m_cleaner, "cleanup"); } } } diff --git a/src/quick3d/imports/scene3d/scene3drenderer_p.h b/src/quick3d/imports/scene3d/scene3drenderer_p.h index e28ecbe6e..c3a83e6f9 100644 --- a/src/quick3d/imports/scene3d/scene3drenderer_p.h +++ b/src/quick3d/imports/scene3d/scene3drenderer_p.h @@ -76,9 +76,7 @@ class Scene3DRenderer : public QObject { Q_OBJECT public: - Scene3DRenderer(Scene3DItem *item, - Qt3DCore::QAspectEngine *aspectEngine, - QRenderAspect *renderAspect); + Scene3DRenderer(); ~Scene3DRenderer(); QOpenGLFramebufferObject *createMultisampledFramebufferObject(const QSize &size); @@ -87,7 +85,12 @@ public: void setSGNode(Scene3DSGNode *node); void setCleanerHelper(Scene3DCleaner *cleaner); void synchronize(); + void init(Scene3DItem *item, Qt3DCore::QAspectEngine *aspectEngine, QRenderAspect *renderAspect); + QRenderAspect *renderAspect() const + { + return m_renderAspect; + } public Q_SLOTS: void render(); void shutdown(); @@ -96,13 +99,12 @@ public Q_SLOTS: private: Scene3DItem *m_item; // Will be released by the QQuickWindow/QML Engine - Qt3DCore::QAspectEngine *m_aspectEngine; // Will be released by the Scene3DRendererCleaner + Qt3DCore::QAspectEngine *m_aspectEngine; // Will be released by the Scene3DItem QRenderAspect *m_renderAspect; // Will be released by the aspectEngine QScopedPointer<QOpenGLFramebufferObject> m_multisampledFBO; QScopedPointer<QOpenGLFramebufferObject> m_finalFBO; QScopedPointer<QSGTexture> m_texture; Scene3DSGNode *m_node; // Will be released by the QtQuick SceneGraph - Scene3DCleaner *m_cleaner; QQuickWindow *m_window; QMutex m_windowMutex; QSize m_lastSize; @@ -111,8 +113,9 @@ private: bool m_needsShutdown; bool m_blocking; bool m_forceRecreate; + bool m_resetRequested = false; - friend class Scene3DCleaner; + friend class Scene3DItem; }; } // namespace Qt3DRender |