summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/animation/backend/animationutils_p.h3
-rw-r--r--src/core/changes/qpropertynodeaddedchange.cpp10
-rw-r--r--src/core/nodes/qnode.cpp17
-rw-r--r--src/core/nodes/qnode_p.h4
-rw-r--r--src/plugins/sceneparsers/assimp/assimpimporter.cpp1
-rw-r--r--src/quick3d/quick3dscene2d/items/scene2d.cpp13
-rw-r--r--src/render/backend/abstractrenderer_p.h3
-rw-r--r--src/render/backend/renderer.cpp279
-rw-r--r--src/render/backend/renderer_p.h13
-rw-r--r--src/render/jobs/filtercompatibletechniquejob.cpp13
-rw-r--r--src/render/jobs/loadscenejob.cpp103
-rw-r--r--src/render/jobs/loadscenejob_p.h8
-rw-r--r--src/render/materialsystem/technique.cpp26
-rw-r--r--src/render/renderlogging.cpp1
-rw-r--r--src/render/renderlogging_p.h1
15 files changed, 294 insertions, 201 deletions
diff --git a/src/animation/backend/animationutils_p.h b/src/animation/backend/animationutils_p.h
index 01816bda2..42402c5ec 100644
--- a/src/animation/backend/animationutils_p.h
+++ b/src/animation/backend/animationutils_p.h
@@ -145,6 +145,7 @@ struct ChannelNameAndType
, jointIndex(-1)
, mappingId()
, jointTransformComponent(NoTransformComponent)
+ , pad(0)
{}
ChannelNameAndType(const QString &_name,
@@ -157,6 +158,7 @@ struct ChannelNameAndType
, jointIndex(_jointIndex)
, mappingId(_mappingId)
, jointTransformComponent(NoTransformComponent)
+ , pad(0)
{}
ChannelNameAndType(const QString &_name,
@@ -168,6 +170,7 @@ struct ChannelNameAndType
, jointIndex(invalidIndex)
, mappingId()
, jointTransformComponent(_jointTransformComponent)
+ , pad(0)
{}
bool operator==(const ChannelNameAndType &rhs) const
diff --git a/src/core/changes/qpropertynodeaddedchange.cpp b/src/core/changes/qpropertynodeaddedchange.cpp
index 390a170b6..9f8e50872 100644
--- a/src/core/changes/qpropertynodeaddedchange.cpp
+++ b/src/core/changes/qpropertynodeaddedchange.cpp
@@ -76,6 +76,16 @@ QPropertyNodeAddedChange::QPropertyNodeAddedChange(QNodeId subjectId, QNode *nod
{
Q_D(QPropertyNodeAddedChange);
d->m_addedNodeIdTypePair = QNodeIdTypePair(node->id(), QNodePrivate::findStaticMetaObject(node->metaObject()));
+
+ // 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();
}
/*! \internal */
diff --git a/src/core/nodes/qnode.cpp b/src/core/nodes/qnode.cpp
index dbe3fd102..e5a3aca71 100644
--- a/src/core/nodes/qnode.cpp
+++ b/src/core/nodes/qnode.cpp
@@ -74,6 +74,7 @@ QNodePrivate::QNodePrivate()
, m_blockNotifications(false)
, m_hasBackendNode(false)
, m_enabled(true)
+ , m_notifiedParent(false)
, m_defaultPropertyTrackMode(QNode::TrackFinalValues)
, m_propertyChangesSetup(false)
, m_signals(this)
@@ -210,13 +211,19 @@ void QNodePrivate::_q_addChild(QNode *childNode)
Q_ASSERT(childNode);
Q_ASSERT_X(childNode->parent() == q_func(), Q_FUNC_INFO, "not a child of this node");
+ // Have we already notified the parent about its new child? If so, bail out
+ // early so that we do not send more than one new child event to the backend
+ QNodePrivate *childD = QNodePrivate::get(childNode);
+ if (childD->m_notifiedParent == true)
+ return;
+
// Store our id as the parentId in the child so that even if the child gets
// removed from the scene as part of the destruction of the parent, when the
// parent's children are deleted in the QObject dtor, we still have access to
// the parentId. If we didn't store this, we wouldn't have access at that time
// because the parent would then only be a QObject, the QNode part would have
// been destroyed already.
- QNodePrivate::get(childNode)->m_parentId = m_id;
+ childD->m_parentId = m_id;
if (!m_scene)
return;
@@ -224,6 +231,11 @@ void QNodePrivate::_q_addChild(QNode *childNode)
// We need to send a QPropertyNodeAddedChange to the backend
// to notify the backend that we have a new child
if (m_changeArbiter != nullptr) {
+ // Flag that we have notified the parent. We do this immediately before
+ // creating the change because that recurses back into this function and
+ // we need to catch that to avoid sending more than one new child event
+ // to the backend.
+ childD->m_notifiedParent = true;
const auto change = QPropertyNodeAddedChangePtr::create(m_id, childNode);
change->setPropertyName("children");
notifyObservers(change);
@@ -299,6 +311,9 @@ void QNodePrivate::_q_setParentHelper(QNode *parent)
notifyDestructionChangesAndRemoveFromScene();
}
+ // Flag that we need to notify any new parent
+ m_notifiedParent = false;
+
// Basically QObject::setParent but for QObjectPrivate
QObjectPrivate::setParent_helper(parent);
QNode *newParentNode = q->parentNode();
diff --git a/src/core/nodes/qnode_p.h b/src/core/nodes/qnode_p.h
index a122993fe..c203b342f 100644
--- a/src/core/nodes/qnode_p.h
+++ b/src/core/nodes/qnode_p.h
@@ -100,6 +100,7 @@ public:
bool m_blockNotifications;
bool m_hasBackendNode;
bool m_enabled;
+ bool m_notifiedParent;
QNode::PropertyTrackingMode m_defaultPropertyTrackMode;
QHash<QString, QNode::PropertyTrackingMode> m_trackedPropertiesOverrides;
@@ -137,10 +138,11 @@ public:
static const QMetaObject *findStaticMetaObject(const QMetaObject *metaObject);
+ void _q_postConstructorInit();
+
private:
void notifyCreationChange();
void notifyDestructionChangesAndRemoveFromScene();
- void _q_postConstructorInit();
void _q_addChild(QNode *childNode);
void _q_removeChild(QNode *childNode);
void _q_setParentHelper(QNode *parent);
diff --git a/src/plugins/sceneparsers/assimp/assimpimporter.cpp b/src/plugins/sceneparsers/assimp/assimpimporter.cpp
index e630ce657..219a75ce4 100644
--- a/src/plugins/sceneparsers/assimp/assimpimporter.cpp
+++ b/src/plugins/sceneparsers/assimp/assimpimporter.cpp
@@ -616,6 +616,7 @@ void AssimpImporter::readSceneFile(const QString &path)
*/
void AssimpImporter::readSceneData(const QByteArray& data, const QString &basePath)
{
+ Q_UNUSED(basePath);
cleanup();
m_scene = new SceneImporter();
diff --git a/src/quick3d/quick3dscene2d/items/scene2d.cpp b/src/quick3d/quick3dscene2d/items/scene2d.cpp
index 4abc7cf42..1147abf68 100644
--- a/src/quick3d/quick3dscene2d/items/scene2d.cpp
+++ b/src/quick3d/quick3dscene2d/items/scene2d.cpp
@@ -123,7 +123,7 @@ Scene2D::Scene2D()
, m_mouseEnabled(true)
, m_renderPolicy(Qt3DRender::Quick::QScene2D::Continuous)
{
- renderThreadClientCount->fetchAndAddAcquire(1);
+
}
Scene2D::~Scene2D()
@@ -146,6 +146,8 @@ void Scene2D::initializeSharedObject()
return;
}
+ renderThreadClientCount->fetchAndAddAcquire(1);
+
renderThread->setObjectName(QStringLiteral("Scene2D::renderThread"));
m_renderThread = renderThread;
m_sharedObject->m_renderThread = m_renderThread;
@@ -413,10 +415,11 @@ void Scene2D::cleanup()
m_sharedObject->wake();
m_sharedObject = nullptr;
}
-
- renderThreadClientCount->fetchAndSubAcquire(1);
- if (renderThreadClientCount->load() == 0)
- renderThread->quit();
+ if (m_renderThread) {
+ renderThreadClientCount->fetchAndSubAcquire(1);
+ if (renderThreadClientCount->load() == 0)
+ renderThread->quit();
+ }
}
diff --git a/src/render/backend/abstractrenderer_p.h b/src/render/backend/abstractrenderer_p.h
index a9d6f19a5..54f37ea21 100644
--- a/src/render/backend/abstractrenderer_p.h
+++ b/src/render/backend/abstractrenderer_p.h
@@ -108,6 +108,7 @@ public:
SkeletonDataDirty = 1 << 10,
JointDirty = 1 << 11,
LayersDirty = 1 << 12,
+ TechniquesDirty = 1 << 13,
AllDirty = 0xffffff
};
Q_DECLARE_FLAGS(BackendNodeDirtySet, BackendNodeDirtyFlag)
@@ -141,7 +142,9 @@ public:
virtual void markDirty(BackendNodeDirtySet changes, BackendNode *node) = 0;
virtual BackendNodeDirtySet dirtyBits() = 0;
+#if defined(QT_BUILD_INTERNAL)
virtual void clearDirtyBits(BackendNodeDirtySet changes) = 0;
+#endif
virtual bool shouldRender() = 0;
virtual void skipNextFrame() = 0;
diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp
index 70daa9904..bb0585e6f 100644
--- a/src/render/backend/renderer.cpp
+++ b/src/render/backend/renderer.cpp
@@ -162,7 +162,6 @@ Renderer::Renderer(QRenderAspect::RenderType type)
, m_waitForInitializationToBeCompleted(0)
, m_pickEventFilter(new PickEventFilter())
, m_exposed(0)
- , m_changeSet(0)
, m_lastFrameCorrect(0)
, m_glContext(nullptr)
, m_shareContext(nullptr)
@@ -207,6 +206,7 @@ Renderer::Renderer(QRenderAspect::RenderType type)
m_updateWorldBoundingVolumeJob->addDependency(m_calculateBoundingVolumeJob);
m_expandBoundingVolumeJob->addDependency(m_updateWorldBoundingVolumeJob);
m_updateShaderDataTransformJob->addDependency(m_worldTransformJob);
+ m_pickBoundingVolumeJob->addDependency(m_expandBoundingVolumeJob);
// Dirty texture gathering depends on m_syncTextureLoadingJob
// m_syncTextureLoadingJob will depend on the texture loading jobs
@@ -220,6 +220,8 @@ Renderer::Renderer(QRenderAspect::RenderType type)
m_pickBoundingVolumeJob->addDependency(m_updateMeshTriangleListJob);
m_rayCastingJob->addDependency(m_updateMeshTriangleListJob);
+ m_shaderGathererJob->addDependency(m_filterCompatibleTechniqueJob);
+
m_filterCompatibleTechniqueJob->setRenderer(this);
m_defaultRenderStateSet = new RenderStateSet;
@@ -308,7 +310,11 @@ NodeManagers *Renderer::nodeManagers() const
*/
QOpenGLContext *Renderer::shareContext() const
{
- return m_shareContext ? m_shareContext : m_graphicsContext->openGLContext()->shareContext();
+ QMutexLocker lock(&m_shareContextMutex);
+ return m_shareContext ? m_shareContext
+ : (m_graphicsContext->openGLContext()
+ ? m_graphicsContext->openGLContext()->shareContext()
+ : nullptr);
}
void Renderer::setOpenGLContext(QOpenGLContext *context)
@@ -326,45 +332,48 @@ void Renderer::initialize()
QOpenGLContext* ctx = m_glContext;
- // If we are using our own context (not provided by QtQuick),
- // we need to create it
- if (!m_glContext) {
- ctx = new QOpenGLContext;
- ctx->setShareContext(qt_gl_global_share_context());
-
- // TO DO: Shouldn't we use the highest context available and trust
- // QOpenGLContext to fall back on the best lowest supported ?
- const QByteArray debugLoggingMode = qgetenv("QT3DRENDER_DEBUG_LOGGING");
+ {
+ QMutexLocker lock(&m_shareContextMutex);
+ // If we are using our own context (not provided by QtQuick),
+ // we need to create it
+ if (!m_glContext) {
+ ctx = new QOpenGLContext;
+ ctx->setShareContext(qt_gl_global_share_context());
+
+ // TO DO: Shouldn't we use the highest context available and trust
+ // QOpenGLContext to fall back on the best lowest supported ?
+ const QByteArray debugLoggingMode = qgetenv("QT3DRENDER_DEBUG_LOGGING");
+
+ if (!debugLoggingMode.isEmpty()) {
+ QSurfaceFormat sf = ctx->format();
+ sf.setOption(QSurfaceFormat::DebugContext);
+ ctx->setFormat(sf);
+ }
- if (!debugLoggingMode.isEmpty()) {
- QSurfaceFormat sf = ctx->format();
- sf.setOption(QSurfaceFormat::DebugContext);
- ctx->setFormat(sf);
+ // Create OpenGL context
+ if (ctx->create())
+ qCDebug(Backend) << "OpenGL context created with actual format" << ctx->format();
+ else
+ qCWarning(Backend) << Q_FUNC_INFO << "OpenGL context creation failed";
+ m_ownedContext = true;
+ } else {
+ // Context is not owned by us, so we need to know if it gets destroyed
+ m_contextConnection = QObject::connect(m_glContext, &QOpenGLContext::aboutToBeDestroyed,
+ [this] { releaseGraphicsResources(); });
}
- // Create OpenGL context
- if (ctx->create())
- qCDebug(Backend) << "OpenGL context created with actual format" << ctx->format();
- else
- qCWarning(Backend) << Q_FUNC_INFO << "OpenGL context creation failed";
- m_ownedContext = true;
- } else {
- // Context is not owned by us, so we need to know if it gets destroyed
- m_contextConnection = QObject::connect(m_glContext, &QOpenGLContext::aboutToBeDestroyed,
- [this] { releaseGraphicsResources(); });
- }
+ if (!ctx->shareContext()) {
+ m_shareContext = new QOpenGLContext;
+ m_shareContext->setFormat(ctx->format());
+ m_shareContext->setShareContext(ctx);
+ m_shareContext->create();
+ }
- if (!ctx->shareContext()) {
- m_shareContext = new QOpenGLContext;
- m_shareContext->setFormat(ctx->format());
- m_shareContext->setShareContext(ctx);
- m_shareContext->create();
+ // Note: we don't have a surface at this point
+ // The context will be made current later on (at render time)
+ m_graphicsContext->setOpenGLContext(ctx);
}
- // Note: we don't have a surface at this point
- // The context will be made current later on (at render time)
- m_graphicsContext->setOpenGLContext(ctx);
-
// Store the format used by the context and queue up creating an
// offscreen surface in the main thread so that it is available
// for use when we want to shutdown the renderer. We need to create
@@ -518,7 +527,7 @@ void Renderer::setSceneRoot(QBackendNodeFactory *factory, Entity *sgRoot)
m_updateTreeEnabledJob->setRoot(m_renderSceneRoot);
// Set all flags to dirty
- m_changeSet |= AbstractRenderer::AllDirty;
+ m_dirtyBits.marked |= AbstractRenderer::AllDirty;
}
void Renderer::registerEventFilter(QEventFilterService *service)
@@ -1016,72 +1025,71 @@ void Renderer::lookForDirtyTextures()
// Executed in a job
void Renderer::lookForDirtyShaders()
{
- if (isRunning()) {
- const QVector<HTechnique> activeTechniques = m_nodesManager->techniqueManager()->activeHandles();
- const QVector<HShaderBuilder> activeBuilders = m_nodesManager->shaderBuilderManager()->activeHandles();
- for (const HTechnique &techniqueHandle : activeTechniques) {
- Technique *technique = m_nodesManager->techniqueManager()->data(techniqueHandle);
- // If api of the renderer matches the one from the technique
- if (technique->isCompatibleWithRenderer()) {
- const auto passIds = technique->renderPasses();
- for (const QNodeId passId : passIds) {
- RenderPass *renderPass = m_nodesManager->renderPassManager()->lookupResource(passId);
- HShader shaderHandle = m_nodesManager->shaderManager()->lookupHandle(renderPass->shaderProgram());
- Shader *shader = m_nodesManager->shaderManager()->data(shaderHandle);
-
- ShaderBuilder *shaderBuilder = nullptr;
- for (const HShaderBuilder &builderHandle : activeBuilders) {
- ShaderBuilder *builder = m_nodesManager->shaderBuilderManager()->data(builderHandle);
- if (builder->shaderProgramId() == shader->peerId()) {
- shaderBuilder = builder;
- break;
- }
+ Q_ASSERT(isRunning());
+ const QVector<HTechnique> activeTechniques = m_nodesManager->techniqueManager()->activeHandles();
+ const QVector<HShaderBuilder> activeBuilders = m_nodesManager->shaderBuilderManager()->activeHandles();
+ for (const HTechnique &techniqueHandle : activeTechniques) {
+ Technique *technique = m_nodesManager->techniqueManager()->data(techniqueHandle);
+ // If api of the renderer matches the one from the technique
+ if (technique->isCompatibleWithRenderer()) {
+ const auto passIds = technique->renderPasses();
+ for (const QNodeId passId : passIds) {
+ RenderPass *renderPass = m_nodesManager->renderPassManager()->lookupResource(passId);
+ HShader shaderHandle = m_nodesManager->shaderManager()->lookupHandle(renderPass->shaderProgram());
+ Shader *shader = m_nodesManager->shaderManager()->data(shaderHandle);
+
+ ShaderBuilder *shaderBuilder = nullptr;
+ for (const HShaderBuilder &builderHandle : activeBuilders) {
+ ShaderBuilder *builder = m_nodesManager->shaderBuilderManager()->data(builderHandle);
+ if (builder->shaderProgramId() == shader->peerId()) {
+ shaderBuilder = builder;
+ break;
}
+ }
+
+ if (shaderBuilder) {
+ shaderBuilder->setGraphicsApi(*technique->graphicsApiFilter());
+
+ for (int i = 0; i <= ShaderBuilder::Compute; i++) {
+ const auto builderType = static_cast<ShaderBuilder::ShaderType>(i);
+ if (!shaderBuilder->shaderGraph(builderType).isValid())
+ continue;
- if (shaderBuilder) {
- shaderBuilder->setGraphicsApi(*technique->graphicsApiFilter());
-
- for (int i = 0; i <= ShaderBuilder::Compute; i++) {
- const auto builderType = static_cast<ShaderBuilder::ShaderType>(i);
- if (!shaderBuilder->shaderGraph(builderType).isValid())
- continue;
-
- if (shaderBuilder->isShaderCodeDirty(builderType)) {
- shaderBuilder->generateCode(builderType);
- }
-
- QShaderProgram::ShaderType shaderType = QShaderProgram::Vertex;
- switch (builderType) {
- case ShaderBuilder::Vertex:
- shaderType = QShaderProgram::Vertex;
- break;
- case ShaderBuilder::TessellationControl:
- shaderType = QShaderProgram::TessellationControl;
- break;
- case ShaderBuilder::TessellationEvaluation:
- shaderType = QShaderProgram::TessellationEvaluation;
- break;
- case ShaderBuilder::Geometry:
- shaderType = QShaderProgram::Geometry;
- break;
- case ShaderBuilder::Fragment:
- shaderType = QShaderProgram::Fragment;
- break;
- case ShaderBuilder::Compute:
- shaderType = QShaderProgram::Compute;
- break;
- }
-
- const auto code = shaderBuilder->shaderCode(builderType);
- shader->setShaderCode(shaderType, code);
+ if (shaderBuilder->isShaderCodeDirty(builderType)) {
+ shaderBuilder->generateCode(builderType);
+ }
+
+ QShaderProgram::ShaderType shaderType = QShaderProgram::Vertex;
+ switch (builderType) {
+ case ShaderBuilder::Vertex:
+ shaderType = QShaderProgram::Vertex;
+ break;
+ case ShaderBuilder::TessellationControl:
+ shaderType = QShaderProgram::TessellationControl;
+ break;
+ case ShaderBuilder::TessellationEvaluation:
+ shaderType = QShaderProgram::TessellationEvaluation;
+ break;
+ case ShaderBuilder::Geometry:
+ shaderType = QShaderProgram::Geometry;
+ break;
+ case ShaderBuilder::Fragment:
+ shaderType = QShaderProgram::Fragment;
+ break;
+ case ShaderBuilder::Compute:
+ shaderType = QShaderProgram::Compute;
+ break;
}
- }
- if (Q_UNLIKELY(shader->hasPendingNotifications()))
- shader->submitPendingNotifications();
- if (shader != nullptr && !shader->isLoaded())
- m_dirtyShaders.push_back(shaderHandle);
+ const auto code = shaderBuilder->shaderCode(builderType);
+ shader->setShaderCode(shaderType, code);
+ }
}
+
+ if (Q_UNLIKELY(shader->hasPendingNotifications()))
+ shader->submitPendingNotifications();
+ if (shader != nullptr && !shader->isLoaded())
+ m_dirtyShaders.push_back(shaderHandle);
}
}
}
@@ -1449,25 +1457,29 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren
void Renderer::markDirty(BackendNodeDirtySet changes, BackendNode *node)
{
Q_UNUSED(node);
- m_changeSet |= changes;
+ m_dirtyBits.marked |= changes;
}
Renderer::BackendNodeDirtySet Renderer::dirtyBits()
{
- return m_changeSet;
+ return m_dirtyBits.marked;
}
+#if defined(QT_BUILD_INTERNAL)
void Renderer::clearDirtyBits(BackendNodeDirtySet changes)
{
- m_changeSet &= ~changes;
+ m_dirtyBits.remaining &= ~changes;
+ m_dirtyBits.marked &= ~changes;
}
+#endif
bool Renderer::shouldRender()
{
// Only render if something changed during the last frame, or the last frame
// was not rendered successfully (or render-on-demand is disabled)
return (m_settings->renderPolicy() == QRenderSettings::Always
- || m_changeSet != 0
+ || m_dirtyBits.marked != 0
+ || m_dirtyBits.remaining != 0
|| !m_lastFrameCorrect.load());
}
@@ -1501,28 +1513,31 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
m_updateLevelOfDetailJob->setFrameGraphRoot(frameGraphRoot());
- BackendNodeDirtySet changesToUnset = dirtyBits();
+ const BackendNodeDirtySet dirtyBitsForFrame = m_dirtyBits.marked | m_dirtyBits.remaining;
+ m_dirtyBits.marked = 0;
+ m_dirtyBits.remaining = 0;
+ BackendNodeDirtySet notCleared = 0;
// Add jobs
- const bool entitiesEnabledDirty = changesToUnset & AbstractRenderer::EntityEnabledDirty;
+ const bool entitiesEnabledDirty = dirtyBitsForFrame & AbstractRenderer::EntityEnabledDirty;
if (entitiesEnabledDirty) {
renderBinJobs.push_back(m_updateTreeEnabledJob);
m_calculateBoundingVolumeJob->addDependency(m_updateTreeEnabledJob);
}
- if (changesToUnset & AbstractRenderer::TransformDirty) {
+ if (dirtyBitsForFrame & AbstractRenderer::TransformDirty) {
renderBinJobs.push_back(m_worldTransformJob);
renderBinJobs.push_back(m_updateWorldBoundingVolumeJob);
renderBinJobs.push_back(m_updateShaderDataTransformJob);
}
- if (changesToUnset & AbstractRenderer::GeometryDirty) {
+ if (dirtyBitsForFrame & AbstractRenderer::GeometryDirty) {
renderBinJobs.push_back(m_calculateBoundingVolumeJob);
renderBinJobs.push_back(m_updateMeshTriangleListJob);
}
- if (changesToUnset & AbstractRenderer::GeometryDirty ||
- changesToUnset & AbstractRenderer::TransformDirty) {
+ if (dirtyBitsForFrame & AbstractRenderer::GeometryDirty ||
+ dirtyBitsForFrame & AbstractRenderer::TransformDirty) {
renderBinJobs.push_back(m_expandBoundingVolumeJob);
}
@@ -1532,19 +1547,15 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
renderBinJobs.push_back(m_cleanupJob);
renderBinJobs.push_back(m_sendRenderCaptureJob);
renderBinJobs.push_back(m_sendBufferCaptureJob);
- renderBinJobs.push_back(m_filterCompatibleTechniqueJob);
renderBinJobs.append(bufferJobs);
// Jobs to prepare GL Resource upload
renderBinJobs.push_back(m_vaoGathererJob);
- if (changesToUnset & AbstractRenderer::BuffersDirty)
+ if (dirtyBitsForFrame & AbstractRenderer::BuffersDirty)
renderBinJobs.push_back(m_bufferGathererJob);
- if (changesToUnset & AbstractRenderer::ShadersDirty)
- renderBinJobs.push_back(m_shaderGathererJob);
-
- if (changesToUnset & AbstractRenderer::TexturesDirty) {
+ if (dirtyBitsForFrame & AbstractRenderer::TexturesDirty) {
renderBinJobs.push_back(m_syncTextureLoadingJob);
renderBinJobs.push_back(m_textureGathererJob);
}
@@ -1552,12 +1563,10 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
// Layer cache is dependent on layers, layer filters and the enabled flag
// on entities
- const bool layersDirty = changesToUnset & AbstractRenderer::LayersDirty;
+ const bool layersDirty = dirtyBitsForFrame & AbstractRenderer::LayersDirty;
const bool layersCacheNeedsToBeRebuilt = layersDirty || entitiesEnabledDirty;
- bool layersCacheRebuilt = false;
- const bool materialDirty = changesToUnset & AbstractRenderer::MaterialDirty;
- bool materialGathererCacheRebuilt = false;
+ const bool materialDirty = dirtyBitsForFrame & AbstractRenderer::MaterialDirty;
QMutexLocker lock(m_renderQueue->mutex());
if (m_renderQueue->wasReset()) { // Have we rendered yet? (Scene3D case)
@@ -1584,30 +1593,28 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
builder.prepareJobs();
renderBinJobs.append(builder.buildJobHierachy());
}
- layersCacheRebuilt = true;
- materialGathererCacheRebuilt = true;
// Set target number of RenderViews
m_renderQueue->setTargetRenderViewCount(fgBranchCount);
+ } else {
+ // FilterLayerEntityJob is part of the RenderViewBuilder jobs and must be run later
+ // if none of those jobs are started this frame
+ notCleared |= AbstractRenderer::EntityEnabledDirty;
+ notCleared |= AbstractRenderer::LayersDirty;
}
- // Only reset dirty flags once we have really rebuilt the caches
- if (layersDirty && !layersCacheRebuilt)
- changesToUnset.setFlag(AbstractRenderer::LayersDirty, false);
- if (entitiesEnabledDirty && !layersCacheRebuilt)
- changesToUnset.setFlag(AbstractRenderer::EntityEnabledDirty, false);
- if (materialDirty && !materialGathererCacheRebuilt)
- changesToUnset.setFlag(AbstractRenderer::MaterialDirty, false);
-
- // Clear dirty bits
- // TO DO: When secondary GL thread is integrated, the following line can be removed
- changesToUnset.setFlag(AbstractRenderer::ShadersDirty, false);
+ if (isRunning() && m_graphicsContext->isInitialized()) {
+ if (dirtyBitsForFrame & AbstractRenderer::TechniquesDirty )
+ renderBinJobs.push_back(m_filterCompatibleTechniqueJob);
+ if (dirtyBitsForFrame & AbstractRenderer::ShadersDirty)
+ renderBinJobs.push_back(m_shaderGathererJob);
+ } else {
+ notCleared |= AbstractRenderer::TechniquesDirty;
+ notCleared |= AbstractRenderer::ShadersDirty;
+ notCleared |= AbstractRenderer::MaterialDirty;
+ }
- // Clear all dirty flags but Compute so that
- // we still render every frame when a compute shader is used in a scene
- if (changesToUnset.testFlag(Renderer::ComputeDirty))
- changesToUnset.setFlag(Renderer::ComputeDirty, false);
- clearDirtyBits(changesToUnset);
+ m_dirtyBits.remaining = dirtyBitsForFrame & notCleared;
return renderBinJobs;
}
@@ -1745,7 +1752,7 @@ void Renderer::performCompute(const RenderView *, RenderCommand *command)
command->m_workGroups[2]);
}
// HACK: Reset the compute flag to dirty
- m_changeSet |= AbstractRenderer::ComputeDirty;
+ m_dirtyBits.marked |= AbstractRenderer::ComputeDirty;
#if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG)
int err = m_graphicsContext->openGLContext()->functions()->glGetError();
diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h
index f996ebfe1..521d17e80 100644
--- a/src/render/backend/renderer_p.h
+++ b/src/render/backend/renderer_p.h
@@ -183,8 +183,10 @@ public:
void markDirty(BackendNodeDirtySet changes, BackendNode *node) override;
BackendNodeDirtySet dirtyBits() override;
- void clearDirtyBits(BackendNodeDirtySet changes) override;
+#if defined(QT_BUILD_INTERNAL)
+ void clearDirtyBits(BackendNodeDirtySet changes) override;
+#endif
bool shouldRender() override;
void skipNextFrame() override;
@@ -309,10 +311,17 @@ private:
QVector<Attribute *> m_dirtyAttributes;
QVector<Geometry *> m_dirtyGeometry;
QAtomicInt m_exposed;
- BackendNodeDirtySet m_changeSet;
+
+ struct DirtyBits {
+ BackendNodeDirtySet marked = 0; // marked dirty since last job build
+ BackendNodeDirtySet remaining = 0; // remaining dirty after jobs have finished
+ };
+ DirtyBits m_dirtyBits;
+
QAtomicInt m_lastFrameCorrect;
QOpenGLContext *m_glContext;
QOpenGLContext *m_shareContext;
+ mutable QMutex m_shareContextMutex;
PickBoundingVolumeJobPtr m_pickBoundingVolumeJob;
RayCastingJobPtr m_rayCastingJob;
diff --git a/src/render/jobs/filtercompatibletechniquejob.cpp b/src/render/jobs/filtercompatibletechniquejob.cpp
index 362e4088f..080ccd306 100644
--- a/src/render/jobs/filtercompatibletechniquejob.cpp
+++ b/src/render/jobs/filtercompatibletechniquejob.cpp
@@ -79,14 +79,13 @@ Renderer *FilterCompatibleTechniqueJob::renderer() const
void FilterCompatibleTechniqueJob::run()
{
Q_ASSERT(m_manager != nullptr && m_renderer != nullptr);
+ Q_ASSERT(m_renderer->isRunning() && m_renderer->graphicsContext()->isInitialized());
- if (m_renderer->isRunning() && m_renderer->graphicsContext()->isInitialized()) {
- const QVector<Qt3DCore::QNodeId> dirtyTechniqueIds = m_manager->takeDirtyTechniques();
- for (const Qt3DCore::QNodeId techniqueId : dirtyTechniqueIds) {
- Technique *technique = m_manager->lookupResource(techniqueId);
- if (Q_LIKELY(technique != nullptr))
- technique->setCompatibleWithRenderer((*m_renderer->contextInfo() == *technique->graphicsApiFilter()));
- }
+ const QVector<Qt3DCore::QNodeId> dirtyTechniqueIds = m_manager->takeDirtyTechniques();
+ for (const Qt3DCore::QNodeId techniqueId : dirtyTechniqueIds) {
+ Technique *technique = m_manager->lookupResource(techniqueId);
+ if (Q_LIKELY(technique != nullptr))
+ technique->setCompatibleWithRenderer((*m_renderer->contextInfo() == *technique->graphicsApiFilter()));
}
}
diff --git a/src/render/jobs/loadscenejob.cpp b/src/render/jobs/loadscenejob.cpp
index 5be733a4d..f767fe720 100644
--- a/src/render/jobs/loadscenejob.cpp
+++ b/src/render/jobs/loadscenejob.cpp
@@ -46,7 +46,7 @@
#include <Qt3DRender/private/qsceneimporter_p.h>
#include <Qt3DRender/private/qurlhelper_p.h>
#include <Qt3DRender/qsceneloader.h>
-
+#include <Qt3DRender/private/renderlogging_p.h>
#include <QFileInfo>
#include <QMimeDatabase>
@@ -93,7 +93,6 @@ void LoadSceneJob::run()
{
// Iterate scene IO handlers until we find one that can handle this file type
Qt3DCore::QEntity *sceneSubTree = nullptr;
-
Scene *scene = m_managers->sceneManager()->lookupResource(m_sceneComponent);
Q_ASSERT(scene);
@@ -107,52 +106,37 @@ void LoadSceneJob::run()
if (m_data.isEmpty()) {
const QString path = QUrlHelper::urlToLocalFileOrQrc(m_source);
- QFileInfo finfo(path);
+ const QFileInfo finfo(path);
+ qCDebug(SceneLoaders) << Q_FUNC_INFO << "Attempting to load" << finfo.filePath();
if (finfo.exists()) {
- QStringList extensions(finfo.suffix());
-
- for (QSceneImporter *sceneImporter : qAsConst(m_sceneImporters)) {
- if (!sceneImporter->areFileTypesSupported(extensions))
- continue;
-
- // If the file type is supported -> enter Loading status
- scene->setStatus(QSceneLoader::Loading);
-
- // File type is supported, try to load it
- sceneImporter->setSource(m_source);
- sceneSubTree = sceneImporter->scene();
- if (sceneSubTree != nullptr) {
- // Successfully built a subtree
- finalStatus = QSceneLoader::Ready;
- break;
- }
- }
+ const QStringList extensions(finfo.suffix());
+ sceneSubTree = tryLoadScene(scene,
+ finalStatus,
+ extensions,
+ [this] (QSceneImporter *importer) {
+ importer->setSource(m_source);
+ });
+ } else {
+ qCWarning(SceneLoaders) << Q_FUNC_INFO << finfo.filePath() << "doesn't exist";
}
} else {
QStringList extensions;
QMimeDatabase db;
- QMimeType mtype = db.mimeTypeForData(m_data);
- if (mtype.isValid()) {
+ const QMimeType mtype = db.mimeTypeForData(m_data);
+
+ if (mtype.isValid())
extensions = mtype.suffixes();
- }
+ else
+ qCWarning(SceneLoaders) << Q_FUNC_INFO << "Invalid mime type" << mtype;
- QString basePath = m_source.adjusted(QUrl::RemoveFilename).toString();
- for (QSceneImporter *sceneImporter : qAsConst(m_sceneImporters)) {
- if (!sceneImporter->areFileTypesSupported(extensions))
- continue;
-
- // If the file type is supported -> enter Loading status
- scene->setStatus(QSceneLoader::Loading);
-
- // File type is supported, try to load it
- sceneImporter->setData(m_data, basePath);
- sceneSubTree = sceneImporter->scene();
- if (sceneSubTree != nullptr) {
- // Successfully built a subtree
- finalStatus = QSceneLoader::Ready;
- break;
- }
- }
+ const QString basePath = m_source.adjusted(QUrl::RemoveFilename).toString();
+
+ sceneSubTree = tryLoadScene(scene,
+ finalStatus,
+ extensions,
+ [this, basePath] (QSceneImporter *importer) {
+ importer->setData(m_data, basePath);
+ });
}
}
@@ -167,6 +151,43 @@ void LoadSceneJob::run()
scene->setStatus(finalStatus);
}
+Qt3DCore::QEntity *LoadSceneJob::tryLoadScene(Scene *scene,
+ QSceneLoader::Status &finalStatus,
+ const QStringList &extensions,
+ const std::function<void (QSceneImporter *)> &importerSetupFunc)
+{
+ Qt3DCore::QEntity *sceneSubTree = nullptr;
+ bool foundSuitableLoggerPlugin = false;
+
+ for (QSceneImporter *sceneImporter : qAsConst(m_sceneImporters)) {
+ if (!sceneImporter->areFileTypesSupported(extensions))
+ continue;
+
+ foundSuitableLoggerPlugin = true;
+
+ // If the file type is supported -> enter Loading status
+ scene->setStatus(QSceneLoader::Loading);
+
+ // Set source file or data on importer
+ importerSetupFunc(sceneImporter);
+
+ // File type is supported, try to load it
+ sceneSubTree = sceneImporter->scene();
+ if (sceneSubTree != nullptr) {
+ // Successfully built a subtree
+ finalStatus = QSceneLoader::Ready;
+ break;
+ }
+
+ qCWarning(SceneLoaders) << Q_FUNC_INFO << "Failed to import" << m_source << "with errors" << sceneImporter->errors();
+ }
+
+ if (!foundSuitableLoggerPlugin)
+ qCWarning(SceneLoaders) << Q_FUNC_INFO << "Found not suitable importer plugin for" << m_source;
+
+ return sceneSubTree;
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/jobs/loadscenejob_p.h b/src/render/jobs/loadscenejob_p.h
index b33637985..0c77dc6e8 100644
--- a/src/render/jobs/loadscenejob_p.h
+++ b/src/render/jobs/loadscenejob_p.h
@@ -53,8 +53,10 @@
#include <Qt3DCore/qaspectjob.h>
#include <Qt3DCore/qnodeid.h>
+#include <Qt3DRender/qsceneloader.h>
#include <QSharedPointer>
#include <QUrl>
+#include <functional>
QT_BEGIN_NAMESPACE
@@ -64,6 +66,7 @@ class QSceneImporter;
namespace Render {
+class Scene;
class NodeManagers;
class Q_AUTOTEST_EXPORT LoadSceneJob : public Qt3DCore::QAspectJob
@@ -87,6 +90,11 @@ private:
Qt3DCore::QNodeId m_sceneComponent;
NodeManagers *m_managers;
QList<QSceneImporter *> m_sceneImporters;
+
+ Qt3DCore::QEntity *tryLoadScene(Scene *scene,
+ QSceneLoader::Status &finalStatus,
+ const QStringList &extensions,
+ const std::function<void (QSceneImporter *)> &importerSetupFunc);
};
typedef QSharedPointer<LoadSceneJob> LoadSceneJobPtr;
diff --git a/src/render/materialsystem/technique.cpp b/src/render/materialsystem/technique.cpp
index 4fd1555e1..5438fa9c8 100644
--- a/src/render/materialsystem/technique.cpp
+++ b/src/render/materialsystem/technique.cpp
@@ -102,43 +102,53 @@ void Technique::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e)
switch (e->type()) {
case PropertyUpdated: {
const auto change = qSharedPointerCast<QPropertyUpdatedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("graphicsApiFilterData")) {
+ if (change->propertyName() == QByteArrayLiteral("enabled")) {
+ markDirty(AbstractRenderer::TechniquesDirty);
+ } else if (change->propertyName() == QByteArrayLiteral("graphicsApiFilterData")) {
GraphicsApiFilterData filterData = change->value().value<GraphicsApiFilterData>();
m_graphicsApiFilterData = filterData;
// Notify the manager that our graphicsApiFilterData has changed
// and that we therefore need to be check for compatibility again
m_isCompatibleWithRenderer = false;
m_nodeManager->techniqueManager()->addDirtyTechnique(peerId());
+ markDirty(AbstractRenderer::TechniquesDirty);
}
break;
}
case PropertyValueAdded: {
const auto change = qSharedPointerCast<QPropertyNodeAddedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("pass"))
+ if (change->propertyName() == QByteArrayLiteral("pass")) {
appendRenderPass(change->addedNodeId());
- else if (change->propertyName() == QByteArrayLiteral("parameter"))
+ markDirty(AbstractRenderer::TechniquesDirty);
+ } else if (change->propertyName() == QByteArrayLiteral("parameter")) {
m_parameterPack.appendParameter(change->addedNodeId());
- else if (change->propertyName() == QByteArrayLiteral("filterKeys"))
+ markDirty(AbstractRenderer::TechniquesDirty);
+ } else if (change->propertyName() == QByteArrayLiteral("filterKeys")) {
appendFilterKey(change->addedNodeId());
+ markDirty(AbstractRenderer::TechniquesDirty);
+ }
break;
}
case PropertyValueRemoved: {
const auto change = qSharedPointerCast<QPropertyNodeRemovedChange>(e);
- if (change->propertyName() == QByteArrayLiteral("pass"))
+ if (change->propertyName() == QByteArrayLiteral("pass")) {
removeRenderPass(change->removedNodeId());
- else if (change->propertyName() == QByteArrayLiteral("parameter"))
+ markDirty(AbstractRenderer::TechniquesDirty);
+ } else if (change->propertyName() == QByteArrayLiteral("parameter")) {
m_parameterPack.removeParameter(change->removedNodeId());
- else if (change->propertyName() == QByteArrayLiteral("filterKeys"))
+ markDirty(AbstractRenderer::TechniquesDirty);
+ } else if (change->propertyName() == QByteArrayLiteral("filterKeys")) {
removeFilterKey(change->removedNodeId());
+ markDirty(AbstractRenderer::TechniquesDirty);
+ }
break;
}
default:
break;
}
- markDirty(AbstractRenderer::AllDirty);
BackendNode::sceneChangeEvent(e);
}
diff --git a/src/render/renderlogging.cpp b/src/render/renderlogging.cpp
index b9d423163..2eb1835e6 100644
--- a/src/render/renderlogging.cpp
+++ b/src/render/renderlogging.cpp
@@ -49,6 +49,7 @@ Q_LOGGING_CATEGORY(Backend, "Qt3D.Renderer.Backend", QtWarningMsg)
Q_LOGGING_CATEGORY(Frontend, "Qt3D.Renderer.Frontend", QtWarningMsg)
Q_LOGGING_CATEGORY(Io, "Qt3D.Renderer.IO", QtWarningMsg)
Q_LOGGING_CATEGORY(Jobs, "Qt3D.Renderer.Jobs", QtWarningMsg)
+Q_LOGGING_CATEGORY(SceneLoaders, "Qt3D.Renderer.SceneLoaders", QtWarningMsg)
Q_LOGGING_CATEGORY(Framegraph, "Qt3D.Renderer.Framegraph", QtWarningMsg)
Q_LOGGING_CATEGORY(RenderNodes, "Qt3D.Renderer.RenderNodes", QtWarningMsg)
Q_LOGGING_CATEGORY(Rendering, "Qt3D.Renderer.Rendering", QtWarningMsg)
diff --git a/src/render/renderlogging_p.h b/src/render/renderlogging_p.h
index dfa761e46..00ae572f4 100644
--- a/src/render/renderlogging_p.h
+++ b/src/render/renderlogging_p.h
@@ -63,6 +63,7 @@ Q_DECLARE_LOGGING_CATEGORY(Backend)
Q_DECLARE_LOGGING_CATEGORY(Frontend)
Q_DECLARE_LOGGING_CATEGORY(Io)
Q_DECLARE_LOGGING_CATEGORY(Jobs)
+Q_DECLARE_LOGGING_CATEGORY(SceneLoaders)
Q_DECLARE_LOGGING_CATEGORY(Framegraph)
Q_DECLARE_LOGGING_CATEGORY(RenderNodes)
Q_DECLARE_LOGGING_CATEGORY(Rendering)