From bf2c2e9bb2dd0b13cb2cb6728de0c2421fbafbb7 Mon Sep 17 00:00:00 2001 From: Jim Albamont Date: Wed, 13 Mar 2019 13:23:21 -0500 Subject: Fix Entity parenting hierarchy When the initial Entity backend node hierarchy is created it skips over any non-entity nodes to ensure that Entities are only parented to other Entities. Calling QNode::setParent breaks this when reparenting Entities to non-entity nodes. Fix by sending a new "parentEntityUpdated" property update that backend Entity nodes listen for. They keep the id of their new parent and flag the need to rebuild the entity hierarchy. This triggers a new job to clear the children and parents of every backend Entity, then rebuilds the hierarchy using the stored parent ID in each Entity. This is much more forgiving of creation/parenting ordering issues and shouldn't be less performant because any Entity reparent was previously marking everything dirty anyway. Add a new test from QTBUG-73905 that creates 4 cylinders and manipulates the parents in different ways. Add a new test to tst_nodes to reparent a QEntity to a QNode and ensure the entity finds it's correct QEntity parent. Add a new test to tst_entity to ensure backend nodes correctly handle the new parenting events. Task-number: QTBUG-73905 Change-Id: Iab0203947d89bbed2868b3629fbde879675fe568 Reviewed-by: Paul Lemire --- src/render/renderers/opengl/renderer/renderer.cpp | 19 ++++++++++++++++--- src/render/renderers/opengl/renderer/renderer_p.h | 2 ++ 2 files changed, 18 insertions(+), 3 deletions(-) (limited to 'src/render/renderers/opengl/renderer') diff --git a/src/render/renderers/opengl/renderer/renderer.cpp b/src/render/renderers/opengl/renderer/renderer.cpp index 4b70710f2..a023b82f9 100644 --- a/src/render/renderers/opengl/renderer/renderer.cpp +++ b/src/render/renderers/opengl/renderer/renderer.cpp @@ -198,6 +198,7 @@ Renderer::Renderer(QRenderAspect::RenderType type) , m_sendTextureChangesToFrontendJob(Render::GenericLambdaJobPtr>::create([this] { sendTextureChangesToFrontend(); }, JobTypes::SendTextureChangesToFrontend)) , m_introspectShaderJob(Render::GenericLambdaJobPtr>::create([this] { reloadDirtyShaders(); }, JobTypes::DirtyShaderGathering)) , m_syncTextureLoadingJob(Render::GenericLambdaJobPtr>::create([] {}, JobTypes::SyncTextureLoading)) + , m_updateEntityHierarchyJob(Render::UpdateEntityHierarchyJobPtr::create()) , m_ownedContext(false) , m_offscreenHelper(nullptr) #if QT_CONFIG(qt3d_profile_jobs) @@ -210,6 +211,9 @@ Renderer::Renderer(QRenderAspect::RenderType type) if (m_renderThread) m_renderThread->waitForStart(); + m_worldTransformJob->addDependency(m_updateEntityHierarchyJob); + m_updateEntityLayersJob->addDependency(m_updateEntityHierarchyJob); + // Create jobs to update transforms and bounding volumes // We can only update bounding volumes once all world transforms are known m_updateWorldBoundingVolumeJob->addDependency(m_worldTransformJob); @@ -299,6 +303,7 @@ void Renderer::setNodeManagers(NodeManagers *managers) m_updateMeshTriangleListJob->setManagers(m_nodesManager); m_filterCompatibleTechniqueJob->setManager(m_nodesManager->techniqueManager()); m_updateEntityLayersJob->setManager(m_nodesManager); + m_updateEntityHierarchyJob->setManager(m_nodesManager); } void Renderer::setServices(QServiceLocator *services) @@ -1665,14 +1670,17 @@ QVector Renderer::renderBinJobs() // Add jobs const bool entitiesEnabledDirty = dirtyBitsForFrame & AbstractRenderer::EntityEnabledDirty; - if (entitiesEnabledDirty) { + const bool entityHierarchyNeedsToBeRebuilt = dirtyBitsForFrame & AbstractRenderer::EntityHierarchyDirty; + if (entitiesEnabledDirty || entityHierarchyNeedsToBeRebuilt) { renderBinJobs.push_back(m_updateTreeEnabledJob); // This dependency is added here because we clear all dependencies // at the start of this function. m_calculateBoundingVolumeJob->addDependency(m_updateTreeEnabledJob); + m_calculateBoundingVolumeJob->addDependency(m_updateEntityHierarchyJob); } - if (dirtyBitsForFrame & AbstractRenderer::TransformDirty) { + if (dirtyBitsForFrame & AbstractRenderer::TransformDirty || + dirtyBitsForFrame & AbstractRenderer::EntityHierarchyDirty) { renderBinJobs.push_back(m_worldTransformJob); renderBinJobs.push_back(m_updateWorldBoundingVolumeJob); renderBinJobs.push_back(m_updateShaderDataTransformJob); @@ -1685,6 +1693,7 @@ QVector Renderer::renderBinJobs() } if (dirtyBitsForFrame & AbstractRenderer::GeometryDirty || + dirtyBitsForFrame & AbstractRenderer::EntityHierarchyDirty || dirtyBitsForFrame & AbstractRenderer::TransformDirty) { renderBinJobs.push_back(m_expandBoundingVolumeJob); } @@ -1722,11 +1731,15 @@ QVector Renderer::renderBinJobs() // Layer cache is dependent on layers, layer filters (hence FG structure // changes) and the enabled flag on entities const bool frameGraphDirty = dirtyBitsForFrame & AbstractRenderer::FrameGraphDirty; - const bool layersDirty = dirtyBitsForFrame & AbstractRenderer::LayersDirty; + const bool layersDirty = dirtyBitsForFrame & AbstractRenderer::LayersDirty || entityHierarchyNeedsToBeRebuilt; const bool layersCacheNeedsToBeRebuilt = layersDirty || entitiesEnabledDirty || frameGraphDirty; const bool materialDirty = dirtyBitsForFrame & AbstractRenderer::MaterialDirty; const bool materialCacheNeedsToBeRebuilt = materialDirty || frameGraphDirty; + // Rebuild Entity Hierarchy if dirty + if (entityHierarchyNeedsToBeRebuilt) + renderBinJobs.push_back(m_updateEntityHierarchyJob); + // Rebuild Entity Layers list if layers are dirty if (layersDirty) renderBinJobs.push_back(m_updateEntityLayersJob); diff --git a/src/render/renderers/opengl/renderer/renderer_p.h b/src/render/renderers/opengl/renderer/renderer_p.h index b89c1e7c0..6443215a4 100644 --- a/src/render/renderers/opengl/renderer/renderer_p.h +++ b/src/render/renderers/opengl/renderer/renderer_p.h @@ -78,6 +78,7 @@ #include #include #include +#include #include #include @@ -361,6 +362,7 @@ private: UpdateMeshTriangleListJobPtr m_updateMeshTriangleListJob; FilterCompatibleTechniqueJobPtr m_filterCompatibleTechniqueJob; UpdateEntityLayersJobPtr m_updateEntityLayersJob; + UpdateEntityHierarchyJobPtr m_updateEntityHierarchyJob; QVector m_pendingRenderCaptureSendRequests; -- cgit v1.2.3