diff options
author | Liang Qi <liang.qi@qt.io> | 2018-01-22 09:24:26 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2018-01-22 09:24:57 +0100 |
commit | 520b9823954628f66b256bcf6e0c96f30ed4f625 (patch) | |
tree | aa8cb07880d8c96b1020bfd8dd43c9dc7bcd8df5 | |
parent | f91ee783c5704b0d55da0d96dacf6eca8933e748 (diff) | |
parent | 9409dd81287af75108023abbd66e49e07ba65de6 (diff) |
Merge remote-tracking branch 'origin/5.9' into 5.10
Conflicts:
src/render/backend/renderer.cpp
Change-Id: I691f54cd6daef8a966df37d447164c94badce34c
-rw-r--r-- | dist/changes-5.9.4 | 27 | ||||
-rw-r--r-- | src/core/nodes/qnode.cpp | 23 | ||||
-rw-r--r-- | src/plugins/sceneparsers/assimp/assimpimporter.cpp | 1 | ||||
-rw-r--r-- | src/quick3d/imports/scene3d/scene3drenderer.cpp | 6 | ||||
-rw-r--r-- | src/quick3d/imports/scene3d/scene3drenderer_p.h | 1 | ||||
-rw-r--r-- | src/render/backend/abstractrenderer_p.h | 2 | ||||
-rw-r--r-- | src/render/backend/renderer.cpp | 17 | ||||
-rw-r--r-- | src/render/backend/renderer_p.h | 2 | ||||
-rw-r--r-- | src/render/frontend/qrenderaspect.cpp | 4 | ||||
-rw-r--r-- | src/render/frontend/qrenderaspect_p.h | 2 | ||||
-rw-r--r-- | src/render/graphicshelpers/graphicscontext.cpp | 3 | ||||
-rw-r--r-- | tests/auto/core/nodes/tst_nodes.cpp | 74 | ||||
-rw-r--r-- | tests/auto/render/commons/testrenderer.h | 2 |
13 files changed, 153 insertions, 11 deletions
diff --git a/dist/changes-5.9.4 b/dist/changes-5.9.4 new file mode 100644 index 000000000..361215783 --- /dev/null +++ b/dist/changes-5.9.4 @@ -0,0 +1,27 @@ +Qt 5.9.4 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.9.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +The Qt version 5.9 series is binary compatible with the 5.8.x series. +Applications compiled for 5.8 will continue to run with 5.9. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Qt 5.9.4 Changes * +**************************************************************************** + + - [QTBUG-62235] Fix viewport scaling in Scene3D on hidpi displays + - [QTBUG-63537] Fix handling of uniform arrays values in some drivers + - [QTBUG-63897][QTBUG-65407] Fix crash when deleting Scene3D items + diff --git a/src/core/nodes/qnode.cpp b/src/core/nodes/qnode.cpp index 58e016cda..dbe3fd102 100644 --- a/src/core/nodes/qnode.cpp +++ b/src/core/nodes/qnode.cpp @@ -173,11 +173,21 @@ void QNodePrivate::_q_postConstructorInit() { Q_Q(QNode); + // If we've already done the work then bail out. This can happen if the + // user creates a QNode subclass with an explicit parent, then immediately + // sets the new QNode as a property on another node. In this case, the + // property setter will call this function directly, but as we can't + // un-schedule a deferred invocation, this function will be called again + // the next time the event loop spins. So, catch this case and abort. + if (m_hasBackendNode) + return; + // Check that the parent hasn't been unset since this call was enqueued auto parentNode = q->parentNode(); if (!parentNode) return; + if (m_scene) m_scene->addObservable(q); // Sets the m_changeArbiter to that of the scene @@ -369,7 +379,18 @@ void QNodePrivate::propertyChanged(int propertyIndex) const QVariant data = property.read(q); if (data.canConvert<QNode*>()) { - const QNode * const node = data.value<QNode*>(); + QNode *node = data.value<QNode*>(); + + // Ensure the node has issued a node creation change. We can end + // up here if a newly created node with a parent is immediately set + // as a property on another node. In this case the deferred call to + // _q_postConstructorInit() will not have happened yet as the event + // loop will still be blocked. So force it here and we catch this + // eventuality in the _q_postConstructorInit() function so that we + // do not repeat the creation and new child scene change events. + if (node) + QNodePrivate::get(node)->_q_postConstructorInit(); + const QNodeId id = node ? node->id() : QNodeId(); notifyPropertyChange(property.name(), QVariant::fromValue(id)); } else { diff --git a/src/plugins/sceneparsers/assimp/assimpimporter.cpp b/src/plugins/sceneparsers/assimp/assimpimporter.cpp index 5af2104c5..a2264964c 100644 --- a/src/plugins/sceneparsers/assimp/assimpimporter.cpp +++ b/src/plugins/sceneparsers/assimp/assimpimporter.cpp @@ -1290,6 +1290,7 @@ void AssimpImporter::copyMaterialTextures(QMaterial *material, aiMaterial *assim QAbstractTexture *tex = QAbstractNodeFactory::createNode<QTexture2D>("QTexture2D"); QTextureImage *texImage = QAbstractNodeFactory::createNode<QTextureImage>("QTextureImage"); texImage->setSource(QUrl::fromLocalFile(fullPath)); + texImage->setMirrored(false); tex->addTextureImage(texImage); // Set proper wrapping mode diff --git a/src/quick3d/imports/scene3d/scene3drenderer.cpp b/src/quick3d/imports/scene3d/scene3drenderer.cpp index 37ae8e48b..1c9fec4d2 100644 --- a/src/quick3d/imports/scene3d/scene3drenderer.cpp +++ b/src/quick3d/imports/scene3d/scene3drenderer.cpp @@ -135,6 +135,7 @@ Scene3DRenderer::Scene3DRenderer(Scene3DItem *item, Qt3DCore::QAspectEngine *asp , m_multisample(false) // this value is not used, will be synced from the Scene3DItem instead , m_lastMultisample(false) , m_needsShutdown(true) + , m_blocking(false) { Q_CHECK_PTR(m_item); Q_CHECK_PTR(m_item->window()); @@ -154,6 +155,9 @@ Scene3DRenderer::Scene3DRenderer(Scene3DItem *item, Qt3DCore::QAspectEngine *asp ContextSaver saver; static_cast<QRenderAspectPrivate*>(QRenderAspectPrivate::get(m_renderAspect))->renderInitialize(saver.context()); scheduleRootEntityChange(); + + const bool blockingRendermode = !qgetenv("SCENE3D_BLOCKING_RENDERMODE").isEmpty(); + m_blocking = blockingRendermode; } Scene3DRenderer::~Scene3DRenderer() @@ -307,7 +311,7 @@ void Scene3DRenderer::render() m_finalFBO->bind(); // Render Qt3D Scene - static_cast<QRenderAspectPrivate*>(QRenderAspectPrivate::get(m_renderAspect))->renderSynchronous(); + static_cast<QRenderAspectPrivate*>(QRenderAspectPrivate::get(m_renderAspect))->renderSynchronous(m_blocking); // We may have called doneCurrent() so restore the context if the rendering surface was changed // Note: keep in mind that the ContextSave also restores the surface when destroyed diff --git a/src/quick3d/imports/scene3d/scene3drenderer_p.h b/src/quick3d/imports/scene3d/scene3drenderer_p.h index 7a85bc774..eb2b930ef 100644 --- a/src/quick3d/imports/scene3d/scene3drenderer_p.h +++ b/src/quick3d/imports/scene3d/scene3drenderer_p.h @@ -109,6 +109,7 @@ private: bool m_multisample; bool m_lastMultisample; bool m_needsShutdown; + bool m_blocking; friend class Scene3DCleaner; }; diff --git a/src/render/backend/abstractrenderer_p.h b/src/render/backend/abstractrenderer_p.h index 4d80ec87d..c934dbfae 100644 --- a/src/render/backend/abstractrenderer_p.h +++ b/src/render/backend/abstractrenderer_p.h @@ -133,7 +133,7 @@ public: // Threaded renderer virtual void render() = 0; // Synchronous renderer - virtual void doRender() = 0; + virtual void doRender(bool scene3dBlocking = false) = 0; virtual void cleanGraphicsResources() = 0; diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index 53f4fa20a..20aeaf2df 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -556,7 +556,7 @@ void Renderer::render() } } -void Renderer::doRender() +void Renderer::doRender(bool scene3dBlocking) { Renderer::ViewSubmissionResultData submissionData; bool hasCleanedQueueAndProceeded = false; @@ -566,9 +566,22 @@ void Renderer::doRender() // Lock the mutex to protect access to the renderQueue while we look for its state QMutexLocker locker(m_renderQueue->mutex()); - const bool queueIsComplete = m_renderQueue->isFrameQueueComplete(); + bool queueIsComplete = m_renderQueue->isFrameQueueComplete(); const bool queueIsEmpty = m_renderQueue->targetRenderViewCount() == 0; + // Scene3D Blocking Mode + if (scene3dBlocking && !queueIsComplete && !queueIsEmpty) { + int i = 0; + // We wait at most 10ms to avoid a case we could never recover from + while (!queueIsComplete && i++ < 10) { + QThread::msleep(1); + qCDebug(Backend) << Q_FUNC_INFO << "Waiting for ready queue (try:" << i << "/ 10)"; + locker.unlock(); + queueIsComplete = m_renderQueue->isFrameQueueComplete(); + locker.relock(); + } + } + // When using synchronous rendering (QtQuick) // We are not sure that the frame queue is actually complete // Since a call to render may not be synched with the completions diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h index 28e8711a8..d4917e28c 100644 --- a/src/render/backend/renderer_p.h +++ b/src/render/backend/renderer_p.h @@ -170,7 +170,7 @@ public: void releaseGraphicsResources() Q_DECL_OVERRIDE; void render() Q_DECL_OVERRIDE; - void doRender() Q_DECL_OVERRIDE; + void doRender(bool scene3dBlocking = false) Q_DECL_OVERRIDE; void cleanGraphicsResources() Q_DECL_OVERRIDE; bool isRunning() const Q_DECL_OVERRIDE { return m_running.load(); } diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp index ba9fd4451..53adf96a9 100644 --- a/src/render/frontend/qrenderaspect.cpp +++ b/src/render/frontend/qrenderaspect.cpp @@ -405,9 +405,9 @@ void QRenderAspectPrivate::renderInitialize(QOpenGLContext *context) } /*! \internal */ -void QRenderAspectPrivate::renderSynchronous() +void QRenderAspectPrivate::renderSynchronous(bool blocking) { - m_renderer->doRender(); + m_renderer->doRender(blocking); } /*! diff --git a/src/render/frontend/qrenderaspect_p.h b/src/render/frontend/qrenderaspect_p.h index b8c8538ee..26ca091f6 100644 --- a/src/render/frontend/qrenderaspect_p.h +++ b/src/render/frontend/qrenderaspect_p.h @@ -90,7 +90,7 @@ public: void loadSceneParsers(); void loadRenderPlugin(const QString &pluginName); void renderInitialize(QOpenGLContext *context); - void renderSynchronous(); + void renderSynchronous(bool blocking = false); void renderShutdown(); void registerBackendType(const QMetaObject &, const Qt3DCore::QBackendNodeMapperPtr &functor); QVector<Qt3DCore::QAspectJobPtr> createGeometryRendererJobs(); diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp index d33aca825..9e8e3d610 100644 --- a/src/render/graphicshelpers/graphicscontext.cpp +++ b/src/render/graphicshelpers/graphicscontext.cpp @@ -515,7 +515,8 @@ void GraphicsContext::loadShader(Shader *shader, ShaderManager *manager) shaderProgram = createShaderProgram(shader); // Store in cache - m_shaderCache.insert(shader->dna(), shader->peerId(), shaderProgram); + if (shaderProgram) + m_shaderCache.insert(shader->dna(), shader->peerId(), shaderProgram); } // Ensure the Shader node knows about the program interface diff --git a/tests/auto/core/nodes/tst_nodes.cpp b/tests/auto/core/nodes/tst_nodes.cpp index 25c2a6dba..49618821c 100644 --- a/tests/auto/core/nodes/tst_nodes.cpp +++ b/tests/auto/core/nodes/tst_nodes.cpp @@ -80,6 +80,7 @@ private slots: void removingChildEntitiesFromNode(); void checkConstructionSetParentMix(); // QTBUG-60612 + void checkConstructionWithParent(); void appendingComponentToEntity(); void appendingParentlessComponentToEntity(); @@ -169,13 +170,17 @@ void SimplePostman::notifyBackend(const Qt3DCore::QSceneChangePtr &change) m_spy->sceneChangeEventWithLock(change); } + + class MyQNode : public Qt3DCore::QNode { Q_OBJECT Q_PROPERTY(QString customProperty READ customProperty WRITE setCustomProperty NOTIFY customPropertyChanged) + Q_PROPERTY(MyQNode *nodeProperty READ nodeProperty WRITE setNodeProperty NOTIFY nodePropertyChanged) public: explicit MyQNode(Qt3DCore::QNode *parent = 0) : QNode(parent) + , m_nodeProperty(nullptr) {} ~MyQNode() @@ -211,11 +216,37 @@ public: Qt3DCore::QNodePrivate::get(this)->m_hasBackendNode = created; } + MyQNode *nodeProperty() const { return m_nodeProperty; } + +public slots: + void setNodeProperty(MyQNode *node) + { + Qt3DCore::QNodePrivate *d = Qt3DCore::QNodePrivate::get(this); + if (m_nodeProperty == node) + return; + + if (m_nodeProperty) + d->unregisterDestructionHelper(m_nodeProperty); + + if (node && !node->parent()) + node->setParent(this); + + m_nodeProperty = node; + + // Ensures proper bookkeeping + if (m_nodeProperty) + d->registerDestructionHelper(m_nodeProperty, &MyQNode::setNodeProperty, m_nodeProperty); + + emit nodePropertyChanged(node); + } + signals: void customPropertyChanged(); + void nodePropertyChanged(MyQNode *node); protected: QString m_customProperty; + MyQNode *m_nodeProperty; }; class MyQEntity : public Qt3DCore::QEntity @@ -847,6 +878,49 @@ void tst_Nodes::checkConstructionSetParentMix() QCOMPARE(lastEvent->addedNodeId(), subTreeRoot->id()); } +void tst_Nodes::checkConstructionWithParent() +{ + // GIVEN + ObserverSpy spy; + Qt3DCore::QScene scene; + QScopedPointer<MyQNode> root(new MyQNode()); + + // WHEN + root->setArbiterAndScene(&spy, &scene); + root->setSimulateBackendCreated(true); + + // THEN + QVERIFY(Qt3DCore::QNodePrivate::get(root.data())->scene() != nullptr); + + // WHEN we create a child and then set it as a Node* property + auto *node = new MyQNode(root.data()); + root->setNodeProperty(node); + + // THEN we should get one creation change, one child added change + // and one property change event, in that order. + QCoreApplication::processEvents(); + QCOMPARE(root->children().count(), 1); + QCOMPARE(spy.events.size(), 3); // 1 creation change, 1 child added change, 1 property change + + // Ensure first event is child node's creation change + const auto creationEvent = spy.events.takeFirst().change().dynamicCast<Qt3DCore::QNodeCreatedChangeBase>(); + QVERIFY(!creationEvent.isNull()); + QCOMPARE(creationEvent->subjectId(), node->id()); + + const auto newChildEvent = spy.events.takeFirst().change().dynamicCast<Qt3DCore::QPropertyNodeAddedChange>(); + QVERIFY(!newChildEvent.isNull()); + QCOMPARE(newChildEvent->subjectId(), root->id()); + QCOMPARE(newChildEvent->propertyName(), "children"); + QCOMPARE(newChildEvent->addedNodeId(), node->id()); + + // Ensure second and last event is property set change + const auto propertyEvent = spy.events.takeFirst().change().dynamicCast<Qt3DCore::QPropertyUpdatedChange>(); + QVERIFY(!propertyEvent.isNull()); + QCOMPARE(propertyEvent->subjectId(), root->id()); + QCOMPARE(propertyEvent->propertyName(), "nodeProperty"); + QCOMPARE(propertyEvent->value().value<Qt3DCore::QNodeId>(), node->id()); +} + void tst_Nodes::appendingParentlessComponentToEntity() { // GIVEN diff --git a/tests/auto/render/commons/testrenderer.h b/tests/auto/render/commons/testrenderer.h index 031ca214b..20ab032b1 100644 --- a/tests/auto/render/commons/testrenderer.h +++ b/tests/auto/render/commons/testrenderer.h @@ -52,7 +52,7 @@ public: void shutdown() Q_DECL_OVERRIDE {} void releaseGraphicsResources() Q_DECL_OVERRIDE {} void render() Q_DECL_OVERRIDE {} - void doRender() Q_DECL_OVERRIDE {} + void doRender(bool scene3dBlocking = false) Q_DECL_OVERRIDE { Q_UNUSED(scene3dBlocking); } void cleanGraphicsResources() Q_DECL_OVERRIDE {} bool isRunning() const Q_DECL_OVERRIDE { return true; } bool shouldRender() Q_DECL_OVERRIDE { return true; } |