summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2018-01-22 09:24:26 +0100
committerLiang Qi <liang.qi@qt.io>2018-01-22 09:24:57 +0100
commit520b9823954628f66b256bcf6e0c96f30ed4f625 (patch)
treeaa8cb07880d8c96b1020bfd8dd43c9dc7bcd8df5
parentf91ee783c5704b0d55da0d96dacf6eca8933e748 (diff)
parent9409dd81287af75108023abbd66e49e07ba65de6 (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.427
-rw-r--r--src/core/nodes/qnode.cpp23
-rw-r--r--src/plugins/sceneparsers/assimp/assimpimporter.cpp1
-rw-r--r--src/quick3d/imports/scene3d/scene3drenderer.cpp6
-rw-r--r--src/quick3d/imports/scene3d/scene3drenderer_p.h1
-rw-r--r--src/render/backend/abstractrenderer_p.h2
-rw-r--r--src/render/backend/renderer.cpp17
-rw-r--r--src/render/backend/renderer_p.h2
-rw-r--r--src/render/frontend/qrenderaspect.cpp4
-rw-r--r--src/render/frontend/qrenderaspect_p.h2
-rw-r--r--src/render/graphicshelpers/graphicscontext.cpp3
-rw-r--r--tests/auto/core/nodes/tst_nodes.cpp74
-rw-r--r--tests/auto/render/commons/testrenderer.h2
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; }