mirror of https://github.com/qt/qt3d.git
Cache material parameter gatherer results
Change-Id: I0660f876d7d967d552f7982c3e33e7c971c9abb4 Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
This commit is contained in:
parent
dc16f08f2c
commit
f660c65709
|
|
@ -1539,6 +1539,9 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
|
|||
const bool layersCacheNeedsToBeRebuilt = layersDirty || entitiesEnabledDirty;
|
||||
bool layersCacheRebuilt = false;
|
||||
|
||||
const bool materialDirty = changesToUnset & AbstractRenderer::MaterialDirty;
|
||||
bool materialGathererCacheRebuilt = false;
|
||||
|
||||
QMutexLocker lock(m_renderQueue->mutex());
|
||||
if (m_renderQueue->wasReset()) { // Have we rendered yet? (Scene3D case)
|
||||
// Traverse the current framegraph. For each leaf node create a
|
||||
|
|
@ -1560,20 +1563,24 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
|
|||
for (int i = 0; i < fgBranchCount; ++i) {
|
||||
RenderViewBuilder builder(fgLeaves.at(i), i, this);
|
||||
builder.setLayerCacheNeedsToBeRebuilt(layersCacheNeedsToBeRebuilt);
|
||||
builder.setMaterialGathererCacheNeedsToBeRebuilt(materialDirty);
|
||||
builder.prepareJobs();
|
||||
renderBinJobs.append(builder.buildJobHierachy());
|
||||
}
|
||||
layersCacheRebuilt = true;
|
||||
materialGathererCacheRebuilt = true;
|
||||
|
||||
// Set target number of RenderViews
|
||||
m_renderQueue->setTargetRenderViewCount(fgBranchCount);
|
||||
}
|
||||
|
||||
// Only reset LayersDirty flag once we have really rebuilt the caches
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -66,7 +66,8 @@ struct RendererCache
|
|||
{
|
||||
struct LeafNodeData
|
||||
{
|
||||
QVector<Entity *> filterEntitiesByLayer;
|
||||
QVector<Entity *> filterEntitiesByLayer;
|
||||
MaterialParameterGathererData materialParameterGatherer;
|
||||
};
|
||||
|
||||
QHash<FrameGraphNode *, LeafNodeData> leafNodeCache;
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ public:
|
|||
inline bool frustumCulling() const Q_DECL_NOTHROW { return m_frustumCulling; }
|
||||
void setFrustumCulling(bool frustumCulling) Q_DECL_NOTHROW { m_frustumCulling = frustumCulling; }
|
||||
|
||||
inline void setMaterialParameterTable(const QHash<Qt3DCore::QNodeId, QVector<RenderPassParameterData>> ¶meters) Q_DECL_NOTHROW { m_parameters = parameters; }
|
||||
inline void setMaterialParameterTable(const MaterialParameterGathererData ¶meters) Q_DECL_NOTHROW { m_parameters = parameters; }
|
||||
|
||||
// TODO: Get rid of this overly complex memory management by splitting out the
|
||||
// InnerData as a RenderViewConfig struct. This can be created by setRenderViewConfigFromFrameGraphLeafNode
|
||||
|
|
@ -326,7 +326,7 @@ private:
|
|||
mutable QVector<LightSource> m_lightSources;
|
||||
EnvironmentLight *m_environmentLight;
|
||||
|
||||
QHash<Qt3DCore::QNodeId, QVector<RenderPassParameterData>> m_parameters;
|
||||
MaterialParameterGathererData m_parameters;
|
||||
|
||||
enum StandardUniform
|
||||
{
|
||||
|
|
|
|||
|
|
@ -246,13 +246,10 @@ public:
|
|||
++i;
|
||||
}
|
||||
m_renderViewBuilderJobs.at(i)->setRenderables(renderableEntities.mid(i * packetSize, packetSize + renderableEntities.size() % (m + 1)));
|
||||
|
||||
// Reduction
|
||||
QHash<Qt3DCore::QNodeId, QVector<RenderPassParameterData>> params;
|
||||
for (const auto &materialGatherer : qAsConst(m_materialGathererJobs))
|
||||
params.unite(materialGatherer->materialToPassAndParameter());
|
||||
// Set all required data on the RenderView for final processing
|
||||
rv->setMaterialParameterTable(std::move(params));
|
||||
{
|
||||
QMutexLocker rendererCacheLock(m_renderer->cache()->mutex());
|
||||
rv->setMaterialParameterTable(m_renderer->cache()->leafNodeCache.value(m_leafNode).materialParameterGatherer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -317,6 +314,34 @@ private:
|
|||
FrameGraphNode *m_leafNode;
|
||||
};
|
||||
|
||||
class SyncMaterialParameterGatherer
|
||||
{
|
||||
public:
|
||||
explicit SyncMaterialParameterGatherer(const QVector<MaterialParameterGathererJobPtr> &materialParameterGathererJobs,
|
||||
Renderer *renderer,
|
||||
FrameGraphNode *leafNode)
|
||||
: m_materialParameterGathererJobs(materialParameterGathererJobs)
|
||||
, m_renderer(renderer)
|
||||
, m_leafNode(leafNode)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
QMutexLocker lock(m_renderer->cache()->mutex());
|
||||
RendererCache::LeafNodeData &dataCacheForLeaf = m_renderer->cache()->leafNodeCache[m_leafNode];
|
||||
dataCacheForLeaf.materialParameterGatherer.clear();
|
||||
|
||||
for (const auto &materialGatherer : qAsConst(m_materialParameterGathererJobs))
|
||||
dataCacheForLeaf.materialParameterGatherer.unite(materialGatherer->materialToPassAndParameter());
|
||||
}
|
||||
|
||||
private:
|
||||
QVector<MaterialParameterGathererJobPtr> m_materialParameterGathererJobs;
|
||||
Renderer *m_renderer;
|
||||
FrameGraphNode *m_leafNode;
|
||||
};
|
||||
|
||||
} // anonymous
|
||||
|
||||
RenderViewBuilder::RenderViewBuilder(Render::FrameGraphNode *leafNode, int renderViewIndex, Renderer *renderer)
|
||||
|
|
@ -324,6 +349,7 @@ RenderViewBuilder::RenderViewBuilder(Render::FrameGraphNode *leafNode, int rende
|
|||
, m_renderViewIndex(renderViewIndex)
|
||||
, m_renderer(renderer)
|
||||
, m_layerCacheNeedsToBeRebuilt(false)
|
||||
, m_materialGathererCacheNeedsToBeRebuilt(false)
|
||||
, m_renderViewJob(RenderViewInitializerJobPtr::create())
|
||||
, m_filterEntityByLayerJob()
|
||||
, m_lightGathererJob(Render::LightGathererPtr::create())
|
||||
|
|
@ -407,6 +433,11 @@ SynchronizerJobPtr RenderViewBuilder::syncFilterEntityByLayerJob() const
|
|||
return m_syncFilterEntityByLayerJob;
|
||||
}
|
||||
|
||||
SynchronizerJobPtr RenderViewBuilder::syncMaterialGathererJob() const
|
||||
{
|
||||
return m_syncMaterialGathererJob;
|
||||
}
|
||||
|
||||
FilterProximityDistanceJobPtr RenderViewBuilder::filterProximityJob() const
|
||||
{
|
||||
return m_filterProximityJob;
|
||||
|
|
@ -435,20 +466,26 @@ void RenderViewBuilder::prepareJobs()
|
|||
m_renderViewBuilderJobs.push_back(renderViewCommandBuilder);
|
||||
}
|
||||
|
||||
// Since Material gathering is an heavy task, we split it
|
||||
const QVector<HMaterial> materialHandles = m_renderer->nodeManagers()->materialManager()->activeHandles();
|
||||
const int elementsPerJob = materialHandles.size() / RenderViewBuilder::m_optimalParallelJobCount;
|
||||
const int lastRemaingElements = materialHandles.size() % RenderViewBuilder::m_optimalParallelJobCount;
|
||||
m_materialGathererJobs.reserve(RenderViewBuilder::m_optimalParallelJobCount);
|
||||
for (auto i = 0; i < RenderViewBuilder::m_optimalParallelJobCount; ++i) {
|
||||
auto materialGatherer = Render::MaterialParameterGathererJobPtr::create();
|
||||
materialGatherer->setNodeManagers(m_renderer->nodeManagers());
|
||||
materialGatherer->setRenderer(m_renderer);
|
||||
if (i == RenderViewBuilder::m_optimalParallelJobCount - 1)
|
||||
materialGatherer->setHandles(materialHandles.mid(i * elementsPerJob, elementsPerJob + lastRemaingElements));
|
||||
else
|
||||
materialGatherer->setHandles(materialHandles.mid(i * elementsPerJob, elementsPerJob));
|
||||
m_materialGathererJobs.push_back(materialGatherer);
|
||||
if (m_materialGathererCacheNeedsToBeRebuilt) {
|
||||
// Since Material gathering is an heavy task, we split it
|
||||
const QVector<HMaterial> materialHandles = m_renderer->nodeManagers()->materialManager()->activeHandles();
|
||||
const int elementsPerJob = materialHandles.size() / RenderViewBuilder::m_optimalParallelJobCount;
|
||||
const int lastRemaingElements = materialHandles.size() % RenderViewBuilder::m_optimalParallelJobCount;
|
||||
m_materialGathererJobs.reserve(RenderViewBuilder::m_optimalParallelJobCount);
|
||||
for (auto i = 0; i < RenderViewBuilder::m_optimalParallelJobCount; ++i) {
|
||||
auto materialGatherer = Render::MaterialParameterGathererJobPtr::create();
|
||||
materialGatherer->setNodeManagers(m_renderer->nodeManagers());
|
||||
materialGatherer->setRenderer(m_renderer);
|
||||
if (i == RenderViewBuilder::m_optimalParallelJobCount - 1)
|
||||
materialGatherer->setHandles(materialHandles.mid(i * elementsPerJob, elementsPerJob + lastRemaingElements));
|
||||
else
|
||||
materialGatherer->setHandles(materialHandles.mid(i * elementsPerJob, elementsPerJob));
|
||||
m_materialGathererJobs.push_back(materialGatherer);
|
||||
}
|
||||
m_syncMaterialGathererJob = SynchronizerJobPtr::create(SyncMaterialParameterGatherer(m_materialGathererJobs,
|
||||
m_renderer,
|
||||
m_leafNode),
|
||||
JobTypes::SyncMaterialGatherer);
|
||||
}
|
||||
|
||||
if (m_layerCacheNeedsToBeRebuilt) {
|
||||
|
|
@ -514,11 +551,6 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
|
|||
m_filterProximityJob->addDependency(m_syncRenderViewInitializationJob);
|
||||
|
||||
m_syncRenderCommandBuildingJob->addDependency(m_syncRenderViewInitializationJob);
|
||||
for (const auto &materialGatherer : qAsConst(m_materialGathererJobs)) {
|
||||
materialGatherer->addDependency(m_syncRenderViewInitializationJob);
|
||||
materialGatherer->addDependency(m_renderer->filterCompatibleTechniqueJob());
|
||||
m_syncRenderCommandBuildingJob->addDependency(materialGatherer);
|
||||
}
|
||||
m_syncRenderCommandBuildingJob->addDependency(m_renderableEntityFilterJob);
|
||||
m_syncRenderCommandBuildingJob->addDependency(m_computableEntityFilterJob);
|
||||
m_syncRenderCommandBuildingJob->addDependency(m_filterProximityJob);
|
||||
|
|
@ -557,8 +589,17 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
|
|||
jobs.push_back(m_filterProximityJob); // Step 3
|
||||
jobs.push_back(m_setClearDrawBufferIndexJob); // Step 3
|
||||
|
||||
for (const auto &materialGatherer : qAsConst(m_materialGathererJobs)) // Step3
|
||||
jobs.push_back(materialGatherer);
|
||||
if (m_materialGathererCacheNeedsToBeRebuilt) {
|
||||
for (const auto &materialGatherer : qAsConst(m_materialGathererJobs)) {
|
||||
materialGatherer->addDependency(m_syncRenderViewInitializationJob);
|
||||
materialGatherer->addDependency(m_renderer->filterCompatibleTechniqueJob());
|
||||
jobs.push_back(materialGatherer); // Step3
|
||||
m_syncMaterialGathererJob->addDependency(materialGatherer);
|
||||
}
|
||||
m_syncRenderCommandBuildingJob->addDependency(m_syncMaterialGathererJob);
|
||||
|
||||
jobs.push_back(m_syncMaterialGathererJob); // Step 3
|
||||
}
|
||||
|
||||
jobs.push_back(m_frustumCullingJob); // Step 4
|
||||
jobs.push_back(m_syncRenderCommandBuildingJob); // Step 5
|
||||
|
|
@ -591,6 +632,16 @@ bool RenderViewBuilder::layerCacheNeedsToBeRebuilt() const
|
|||
return m_layerCacheNeedsToBeRebuilt;
|
||||
}
|
||||
|
||||
void RenderViewBuilder::setMaterialGathererCacheNeedsToBeRebuilt(bool needsToBeRebuilt)
|
||||
{
|
||||
m_materialGathererCacheNeedsToBeRebuilt = needsToBeRebuilt;
|
||||
}
|
||||
|
||||
bool RenderViewBuilder::materialGathererCacheNeedsToBeRebuilt() const
|
||||
{
|
||||
return m_materialGathererCacheNeedsToBeRebuilt;
|
||||
}
|
||||
|
||||
int RenderViewBuilder::optimalJobCount()
|
||||
{
|
||||
return RenderViewBuilder::m_optimalParallelJobCount;
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ public:
|
|||
SynchronizerJobPtr setClearDrawBufferIndexJob() const;
|
||||
SynchronizerJobPtr syncFilterEntityByLayerJob() const;
|
||||
FilterProximityDistanceJobPtr filterProximityJob() const;
|
||||
SynchronizerJobPtr syncMaterialGathererJob() const;
|
||||
|
||||
void prepareJobs();
|
||||
QVector<Qt3DCore::QAspectJobPtr> buildJobHierachy() const;
|
||||
|
|
@ -105,6 +106,8 @@ public:
|
|||
|
||||
void setLayerCacheNeedsToBeRebuilt(bool needsToBeRebuilt);
|
||||
bool layerCacheNeedsToBeRebuilt() const;
|
||||
void setMaterialGathererCacheNeedsToBeRebuilt(bool needsToBeRebuilt);
|
||||
bool materialGathererCacheNeedsToBeRebuilt() const;
|
||||
|
||||
static int optimalJobCount();
|
||||
static void removeEntitiesNotInSubset(QVector<Entity *> &entities, QVector<Entity *> subset);
|
||||
|
|
@ -114,6 +117,7 @@ private:
|
|||
const int m_renderViewIndex;
|
||||
Renderer *m_renderer;
|
||||
bool m_layerCacheNeedsToBeRebuilt;
|
||||
bool m_materialGathererCacheNeedsToBeRebuilt;
|
||||
|
||||
RenderViewInitializerJobPtr m_renderViewJob;
|
||||
FilterLayerEntityJobPtr m_filterEntityByLayerJob;
|
||||
|
|
@ -130,6 +134,7 @@ private:
|
|||
SynchronizerJobPtr m_syncRenderViewCommandBuildersJob;
|
||||
SynchronizerJobPtr m_setClearDrawBufferIndexJob;
|
||||
SynchronizerJobPtr m_syncFilterEntityByLayerJob;
|
||||
SynchronizerJobPtr m_syncMaterialGathererJob;
|
||||
FilterProximityDistanceJobPtr m_filterProximityJob;
|
||||
|
||||
static const int m_optimalParallelJobCount;
|
||||
|
|
|
|||
|
|
@ -103,7 +103,8 @@ namespace JobTypes {
|
|||
LoadSkeleton,
|
||||
UpdateSkinningPalette,
|
||||
ProximityFiltering,
|
||||
SyncFilterEntityByLayer
|
||||
SyncFilterEntityByLayer,
|
||||
SyncMaterialGatherer
|
||||
};
|
||||
|
||||
} // JobTypes
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ public:
|
|||
inline void setTechniqueFilter(TechniqueFilter *techniqueFilter) Q_DECL_NOTHROW { m_techniqueFilter = techniqueFilter; }
|
||||
inline void setRenderPassFilter(RenderPassFilter *renderPassFilter) Q_DECL_NOTHROW { m_renderPassFilter = renderPassFilter; }
|
||||
inline void setRenderer(Renderer *renderer) Q_DECL_NOTHROW { m_renderer = renderer; }
|
||||
inline QHash<Qt3DCore::QNodeId, QVector<RenderPassParameterData>> &materialToPassAndParameter() Q_DECL_NOTHROW { return m_parameters; }
|
||||
inline const MaterialParameterGathererData &materialToPassAndParameter() Q_DECL_NOTHROW { return m_parameters; }
|
||||
inline void setHandles(const QVector<HMaterial> &handles) Q_DECL_NOTHROW { m_handles = handles; }
|
||||
|
||||
inline TechniqueFilter *techniqueFilter() const Q_DECL_NOTHROW { return m_techniqueFilter; }
|
||||
|
|
@ -94,7 +94,7 @@ private:
|
|||
Renderer *m_renderer;
|
||||
|
||||
// Material id to array of RenderPasse with parameters
|
||||
QHash<Qt3DCore::QNodeId, QVector<RenderPassParameterData>> m_parameters;
|
||||
MaterialParameterGathererData m_parameters;
|
||||
QVector<HMaterial> m_handles;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ struct RenderPassParameterData
|
|||
};
|
||||
QT3D_DECLARE_TYPEINFO_2(Qt3DRender, Render, RenderPassParameterData, Q_MOVABLE_TYPE)
|
||||
|
||||
using MaterialParameterGathererData = QHash<Qt3DCore::QNodeId, QVector<RenderPassParameterData>>;
|
||||
|
||||
Q_AUTOTEST_EXPORT void parametersFromMaterialEffectTechnique(ParameterInfoList *infoList,
|
||||
ParameterManager *manager,
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ private Q_SLOTS:
|
|||
renderer.setSettings(&settings);
|
||||
renderer.initialize();
|
||||
|
||||
const int singleRenderViewJobCount = 11 + 2 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount();
|
||||
const int singleRenderViewJobCount = 11 + 1 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount();
|
||||
// RenderViewBuilder renderViewJob,
|
||||
// renderableEntityFilterJob,
|
||||
// lightGatherJob,
|
||||
|
|
|
|||
|
|
@ -187,6 +187,7 @@ private Q_SLOTS:
|
|||
QCOMPARE(renderViewBuilder.renderViewIndex(), 0);
|
||||
QCOMPARE(renderViewBuilder.renderer(), testAspect.renderer());
|
||||
QCOMPARE(renderViewBuilder.layerCacheNeedsToBeRebuilt(), false);
|
||||
QCOMPARE(renderViewBuilder.materialGathererCacheNeedsToBeRebuilt(), false);
|
||||
QVERIFY(!renderViewBuilder.renderViewJob().isNull());
|
||||
QVERIFY(!renderViewBuilder.lightGathererJob().isNull());
|
||||
QVERIFY(!renderViewBuilder.renderableEntityFilterJob().isNull());
|
||||
|
|
@ -215,8 +216,8 @@ private Q_SLOTS:
|
|||
QVERIFY(renderViewBuilder.syncFilterEntityByLayerJob().isNull());
|
||||
|
||||
QCOMPARE(renderViewBuilder.renderViewBuilderJobs().size(), Qt3DRender::Render::RenderViewBuilder::optimalJobCount());
|
||||
QCOMPARE(renderViewBuilder.materialGathererJobs().size(), Qt3DRender::Render::RenderViewBuilder::optimalJobCount());
|
||||
QCOMPARE(renderViewBuilder.buildJobHierachy().size(), 11 + 2 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount());
|
||||
QCOMPARE(renderViewBuilder.materialGathererJobs().size(), 0);
|
||||
QCOMPARE(renderViewBuilder.buildJobHierachy().size(), 11 + 1 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount());
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -231,7 +232,22 @@ private Q_SLOTS:
|
|||
QVERIFY(!renderViewBuilder.syncFilterEntityByLayerJob().isNull());
|
||||
|
||||
// mark jobs dirty and recheck
|
||||
QCOMPARE(renderViewBuilder.buildJobHierachy().size(), 13 + 2 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount());
|
||||
QCOMPARE(renderViewBuilder.buildJobHierachy().size(), 13 + 1 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount());
|
||||
}
|
||||
|
||||
{
|
||||
// WHEN
|
||||
Qt3DRender::Render::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer());
|
||||
renderViewBuilder.setMaterialGathererCacheNeedsToBeRebuilt(true);
|
||||
renderViewBuilder.prepareJobs();
|
||||
|
||||
// THEN
|
||||
QCOMPARE(renderViewBuilder.materialGathererCacheNeedsToBeRebuilt(), true);
|
||||
QCOMPARE(renderViewBuilder.materialGathererJobs().size(), Qt3DRender::Render::RenderViewBuilder::optimalJobCount());
|
||||
QVERIFY(!renderViewBuilder.syncMaterialGathererJob().isNull());
|
||||
|
||||
// mark jobs dirty and recheck
|
||||
QCOMPARE(renderViewBuilder.buildJobHierachy().size(), 12 + 2 * Qt3DRender::Render::RenderViewBuilder::optimalJobCount());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue