blob: 387c5ff8d017f1283ac970fd743a50700009cf38 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2020 Klaralvdalens Datakonsult AB (KDAB).
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt3D module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "renderviewbuilder_p.h"
#include <Qt3DRender/private/qrenderaspect_p.h>
#include <QThread>
namespace Qt3DRender {
namespace Render {
namespace Rhi {
// In some cases having less jobs is better (especially on fast cpus where
// splitting just adds more overhead). Ideally, we should try to set the value
// depending on the platform/CPU/nbr of cores
const int RenderViewBuilder::m_optimalParallelJobCount = QThread::idealThreadCount();
namespace {
int findIdealNumberOfWorkers(int elementCount, int packetSize = 100)
{
if (elementCount == 0 || packetSize == 0)
return 0;
return std::min(std::max(elementCount / packetSize, 1), RenderViewBuilder::optimalJobCount());
}
class SyncPreCommandBuilding
{
public:
explicit SyncPreCommandBuilding(
RenderViewInitializerJobPtr renderViewInitializerJob,
const QVector<RenderViewCommandBuilderJobPtr> &renderViewCommandBuilderJobs,
Renderer *renderer, FrameGraphNode *leafNode)
: m_renderViewInitializer(std::move(renderViewInitializerJob)),
m_renderViewCommandBuilderJobs(renderViewCommandBuilderJobs),
m_renderer(renderer),
m_leafNode(leafNode)
{
}
void operator()()
{
// Split commands to build among jobs
QMutexLocker lock(m_renderer->cache()->mutex());
// Rebuild RenderCommands for all entities in RV (ignoring filtering)
RendererCache *cache = m_renderer->cache();
const RendererCache::LeafNodeData &dataCacheForLeaf = cache->leafNodeCache[m_leafNode];
RenderView *rv = m_renderViewInitializer->renderView();
const auto entities = !rv->isCompute() ? cache->renderableEntities : cache->computeEntities;
rv->setMaterialParameterTable(dataCacheForLeaf.materialParameterGatherer);
lock.unlock();
// Split among the ideal number of command builders
const int idealPacketSize =
std::min(std::max(100, entities.size() / RenderViewBuilder::optimalJobCount()),
entities.size());
// Try to split work into an ideal number of workers
const int m = findIdealNumberOfWorkers(entities.size(), idealPacketSize);
for (int i = 0; i < m; ++i) {
const RenderViewCommandBuilderJobPtr renderViewCommandBuilder =
m_renderViewCommandBuilderJobs.at(i);
const int count =
(i == m - 1) ? entities.size() - (i * idealPacketSize) : idealPacketSize;
renderViewCommandBuilder->setEntities(entities, i * idealPacketSize, count);
}
}
private:
RenderViewInitializerJobPtr m_renderViewInitializer;
QVector<RenderViewCommandBuilderJobPtr> m_renderViewCommandBuilderJobs;
Renderer *m_renderer;
FrameGraphNode *m_leafNode;
};
class SyncRenderViewPostCommandUpdate
{
public:
explicit SyncRenderViewPostCommandUpdate(
const RenderViewInitializerJobPtr &renderViewJob,
const QVector<RenderViewCommandUpdaterJobPtr> &renderViewCommandUpdateJobs,
Renderer *renderer)
: m_renderViewJob(renderViewJob),
m_renderViewCommandUpdaterJobs(renderViewCommandUpdateJobs),
m_renderer(renderer)
{
}
void operator()()
{
// Append all the commands and sort them
RenderView *rv = m_renderViewJob->renderView();
const EntityRenderCommandDataPtr commandData =
m_renderViewCommandUpdaterJobs.first()->renderables();
if (commandData) {
const QVector<RenderCommand> commands = std::move(commandData->commands);
rv->setCommands(commands);
// TO DO: Find way to store commands once or at least only when required
// Sort the commands
rv->sort();
}
// Enqueue our fully populated RenderView with the RenderThread
m_renderer->enqueueRenderView(rv, m_renderViewJob->submitOrderIndex());
}
private:
RenderViewInitializerJobPtr m_renderViewJob;
QVector<RenderViewCommandUpdaterJobPtr> m_renderViewCommandUpdaterJobs;
Renderer *m_renderer;
};
class SyncPreFrustumCulling
{
public:
explicit SyncPreFrustumCulling(const RenderViewInitializerJobPtr &renderViewJob,
const FrustumCullingJobPtr &frustumCulling)
: m_renderViewJob(renderViewJob), m_frustumCullingJob(frustumCulling)
{
}
void operator()()
{
RenderView *rv = m_renderViewJob->renderView();
// Update matrices now that all transforms have been updated
rv->updateMatrices();
// Frustum culling
m_frustumCullingJob->setViewProjection(rv->viewProjectionMatrix());
}
private:
RenderViewInitializerJobPtr m_renderViewJob;
FrustumCullingJobPtr m_frustumCullingJob;
};
class SyncRenderViewPostInitialization
{
public:
explicit SyncRenderViewPostInitialization(
const RenderViewInitializerJobPtr &renderViewJob,
const FrustumCullingJobPtr &frustumCullingJob,
const FilterLayerEntityJobPtr &filterEntityByLayerJob,
const FilterProximityDistanceJobPtr &filterProximityJob,
const QVector<MaterialParameterGathererJobPtr> &materialGathererJobs,
const QVector<RenderViewCommandUpdaterJobPtr> &renderViewCommandUpdaterJobs,
const QVector<RenderViewCommandBuilderJobPtr> &renderViewCommandBuilderJobs)
: m_renderViewJob(renderViewJob),
m_frustumCullingJob(frustumCullingJob),
m_filterEntityByLayerJob(filterEntityByLayerJob),
m_filterProximityJob(filterProximityJob),
m_materialGathererJobs(materialGathererJobs),
m_renderViewCommandUpdaterJobs(renderViewCommandUpdaterJobs),
m_renderViewCommandBuilderJobs(renderViewCommandBuilderJobs)
{
}
void operator()()
{
RenderView *rv = m_renderViewJob->renderView();
// Layer filtering
if (!m_filterEntityByLayerJob.isNull())
m_filterEntityByLayerJob->setLayerFilters(rv->layerFilters());
// Proximity filtering
m_filterProximityJob->setProximityFilterIds(rv->proximityFilterIds());
// Material Parameter building
for (const auto &materialGatherer : qAsConst(m_materialGathererJobs)) {
materialGatherer->setRenderPassFilter(
const_cast<RenderPassFilter *>(rv->renderPassFilter()));
materialGatherer->setTechniqueFilter(
const_cast<TechniqueFilter *>(rv->techniqueFilter()));
}
// Command builders and updates
for (const auto &renderViewCommandUpdater : qAsConst(m_renderViewCommandUpdaterJobs))
renderViewCommandUpdater->setRenderView(rv);
for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewCommandBuilderJobs))
renderViewCommandBuilder->setRenderView(rv);
// Set whether frustum culling is enabled or not
m_frustumCullingJob->setActive(rv->frustumCulling());
}
private:
RenderViewInitializerJobPtr m_renderViewJob;
FrustumCullingJobPtr m_frustumCullingJob;
FilterLayerEntityJobPtr m_filterEntityByLayerJob;
FilterProximityDistanceJobPtr m_filterProximityJob;
QVector<MaterialParameterGathererJobPtr> m_materialGathererJobs;
QVector<RenderViewCommandUpdaterJobPtr> m_renderViewCommandUpdaterJobs;
QVector<RenderViewCommandBuilderJobPtr> m_renderViewCommandBuilderJobs;
};
class SyncRenderViewPreCommandUpdate
{
public:
explicit SyncRenderViewPreCommandUpdate(
const RenderViewInitializerJobPtr &renderViewJob,
const FrustumCullingJobPtr &frustumCullingJob,
const FilterProximityDistanceJobPtr &filterProximityJob,
const QVector<MaterialParameterGathererJobPtr> &materialGathererJobs,
const QVector<RenderViewCommandUpdaterJobPtr> &renderViewCommandUpdaterJobs,
const QVector<RenderViewCommandBuilderJobPtr> &renderViewCommandBuilderJobs,
Renderer *renderer, FrameGraphNode *leafNode, bool fullCommandRebuild)
: m_renderViewJob(renderViewJob),
m_frustumCullingJob(frustumCullingJob),
m_filterProximityJob(filterProximityJob),
m_materialGathererJobs(materialGathererJobs),
m_renderViewCommandUpdaterJobs(renderViewCommandUpdaterJobs),
m_renderViewCommandBuilderJobs(renderViewCommandBuilderJobs),
m_renderer(renderer),
m_leafNode(leafNode),
m_fullRebuild(fullCommandRebuild)
{
}
void operator()()
{
// Set the result of previous job computations
// for final RenderCommand building
RenderView *rv = m_renderViewJob->renderView();
if (!rv->noDraw()) {
///////// CACHE LOCKED ////////////
// Retrieve Data from Cache
RendererCache *cache = m_renderer->cache();
QMutexLocker lock(cache->mutex());
Q_ASSERT(cache->leafNodeCache.contains(m_leafNode));
const bool isDraw = !rv->isCompute();
const RendererCache::LeafNodeData &dataCacheForLeaf = cache->leafNodeCache[m_leafNode];
// Rebuild RenderCommands if required
// This should happen fairly infrequently (FrameGraph Change, Geometry/Material change)
// and allow to skip that step most of the time
if (m_fullRebuild) {
EntityRenderCommandData commandData;
// Reduction
{
int totalCommandCount = 0;
for (const RenderViewCommandBuilderJobPtr &renderViewCommandBuilder :
qAsConst(m_renderViewCommandBuilderJobs))
totalCommandCount += renderViewCommandBuilder->commandData().size();
commandData.reserve(totalCommandCount);
// assert(totalCommandCount != 0);
for (const RenderViewCommandBuilderJobPtr &renderViewCommandBuilder :
qAsConst(m_renderViewCommandBuilderJobs))
commandData += std::move(renderViewCommandBuilder->commandData());
}
// Store new cache
RendererCache::LeafNodeData &writableCacheForLeaf =
cache->leafNodeCache[m_leafNode];
writableCacheForLeaf.renderCommandData = std::move(commandData);
}
const EntityRenderCommandData commandData = dataCacheForLeaf.renderCommandData;
const QVector<Entity *> filteredEntities = dataCacheForLeaf.filterEntitiesByLayer;
QVector<Entity *> renderableEntities =
isDraw ? cache->renderableEntities : cache->computeEntities;
QVector<LightSource> lightSources = cache->gatheredLights;
rv->setMaterialParameterTable(dataCacheForLeaf.materialParameterGatherer);
rv->setEnvironmentLight(cache->environmentLight);
lock.unlock();
///////// END OF CACHE LOCKED ////////////
// Filter out entities that weren't selected by the layer filters
// Remove all entities from the compute and renderable vectors that aren't in the
// filtered layer vector
renderableEntities =
RenderViewBuilder::entitiesInSubset(renderableEntities, filteredEntities);
// Set the light sources, with layer filters applied.
for (int i = 0; i < lightSources.count(); ++i) {
if (!filteredEntities.contains(lightSources[i].entity))
lightSources.removeAt(i--);
}
rv->setLightSources(lightSources);
if (isDraw) {
// Filter out frustum culled entity for drawable entities
if (rv->frustumCulling())
renderableEntities = RenderViewBuilder::entitiesInSubset(
renderableEntities, m_frustumCullingJob->visibleEntities());
// Filter out entities which didn't satisfy proximity filtering
if (!rv->proximityFilterIds().empty())
renderableEntities = RenderViewBuilder::entitiesInSubset(
renderableEntities, m_filterProximityJob->filteredEntities());
}
// Early return in case we have nothing to filter
if (renderableEntities.size() == 0)
return;
// Filter out Render commands for which the Entity wasn't selected because
// of frustum, proximity or layer filtering
EntityRenderCommandDataPtr filteredCommandData = EntityRenderCommandDataPtr::create();
filteredCommandData->reserve(renderableEntities.size());
// Because dataCacheForLeaf.renderableEntities or computeEntities are sorted
// What we get out of EntityRenderCommandData is also sorted by Entity
auto eIt = std::cbegin(renderableEntities);
const auto eEnd = std::cend(renderableEntities);
int cIt = 0;
const int cEnd = commandData.size();
while (eIt != eEnd) {
const Entity *targetEntity = *eIt;
// Advance until we have commands whose Entity has a lower address
// than the selected filtered entity
while (cIt != cEnd && commandData.entities.at(cIt) < targetEntity)
++cIt;
// Push pointers to command data for all commands that match the
// entity
while (cIt != cEnd && commandData.entities.at(cIt) == targetEntity) {
filteredCommandData->push_back(commandData.entities.at(cIt),
commandData.commands.at(cIt),
commandData.passesData.at(cIt));
++cIt;
}
++eIt;
}
// Split among the number of command builders
// The idealPacketSize is at least 100 entities per worker
const int idealPacketSize = std::min(
std::max(100,
filteredCommandData->size() / RenderViewBuilder::optimalJobCount()),
filteredCommandData->size());
const int m = findIdealNumberOfWorkers(filteredCommandData->size(), idealPacketSize);
for (int i = 0; i < m; ++i) {
const RenderViewCommandUpdaterJobPtr renderViewCommandBuilder =
m_renderViewCommandUpdaterJobs.at(i);
const int count = (i == m - 1) ? filteredCommandData->size() - (i * idealPacketSize)
: idealPacketSize;
renderViewCommandBuilder->setRenderables(filteredCommandData, i * idealPacketSize,
count);
}
}
}
private:
RenderViewInitializerJobPtr m_renderViewJob;
FrustumCullingJobPtr m_frustumCullingJob;
FilterProximityDistanceJobPtr m_filterProximityJob;
QVector<MaterialParameterGathererJobPtr> m_materialGathererJobs;
QVector<RenderViewCommandUpdaterJobPtr> m_renderViewCommandUpdaterJobs;
QVector<RenderViewCommandBuilderJobPtr> m_renderViewCommandBuilderJobs;
Renderer *m_renderer;
FrameGraphNode *m_leafNode;
bool m_fullRebuild;
};
class SetClearDrawBufferIndex
{
public:
explicit SetClearDrawBufferIndex(const RenderViewInitializerJobPtr &renderViewJob)
: m_renderViewJob(renderViewJob)
{
}
void operator()()
{
RenderView *rv = m_renderViewJob->renderView();
QVector<ClearBufferInfo> &clearBuffersInfo = rv->specificClearColorBufferInfo();
const AttachmentPack &attachmentPack = rv->attachmentPack();
for (ClearBufferInfo &clearBufferInfo : clearBuffersInfo)
clearBufferInfo.drawBufferIndex =
attachmentPack.getDrawBufferIndex(clearBufferInfo.attchmentPoint);
}
private:
RenderViewInitializerJobPtr m_renderViewJob;
};
class SyncFilterEntityByLayer
{
public:
explicit SyncFilterEntityByLayer(const FilterLayerEntityJobPtr &filterEntityByLayerJob,
Renderer *renderer, FrameGraphNode *leafNode)
: m_filterEntityByLayerJob(filterEntityByLayerJob),
m_renderer(renderer),
m_leafNode(leafNode)
{
}
void operator()()
{
QMutexLocker lock(m_renderer->cache()->mutex());
// Save the filtered by layer subset into the cache
const QVector<Entity *> filteredEntities = m_filterEntityByLayerJob->filteredEntities();
RendererCache::LeafNodeData &dataCacheForLeaf =
m_renderer->cache()->leafNodeCache[m_leafNode];
dataCacheForLeaf.filterEntitiesByLayer = filteredEntities;
}
private:
FilterLayerEntityJobPtr m_filterEntityByLayerJob;
Renderer *m_renderer;
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)
: m_leafNode(leafNode),
m_renderViewIndex(renderViewIndex),
m_renderer(renderer),
m_layerCacheNeedsToBeRebuilt(false),
m_materialGathererCacheNeedsToBeRebuilt(false),
m_renderCommandCacheNeedsToBeRebuilt(false),
m_renderViewJob(RenderViewInitializerJobPtr::create()),
m_filterEntityByLayerJob(),
m_frustumCullingJob(new Render::FrustumCullingJob()),
m_syncPreFrustumCullingJob(SynchronizerJobPtr::create(
SyncPreFrustumCulling(m_renderViewJob, m_frustumCullingJob),
JobTypes::SyncFrustumCulling)),
m_setClearDrawBufferIndexJob(SynchronizerJobPtr::create(
SetClearDrawBufferIndex(m_renderViewJob), JobTypes::ClearBufferDrawIndex)),
m_syncFilterEntityByLayerJob(),
m_filterProximityJob(Render::FilterProximityDistanceJobPtr::create())
{
}
RenderViewInitializerJobPtr RenderViewBuilder::renderViewJob() const
{
return m_renderViewJob;
}
FilterLayerEntityJobPtr RenderViewBuilder::filterEntityByLayerJob() const
{
return m_filterEntityByLayerJob;
}
FrustumCullingJobPtr RenderViewBuilder::frustumCullingJob() const
{
return m_frustumCullingJob;
}
QVector<RenderViewCommandUpdaterJobPtr> RenderViewBuilder::renderViewCommandUpdaterJobs() const
{
return m_renderViewCommandUpdaterJobs;
}
QVector<RenderViewCommandBuilderJobPtr> RenderViewBuilder::renderViewCommandBuilderJobs() const
{
return m_renderViewCommandBuilderJobs;
}
QVector<MaterialParameterGathererJobPtr> RenderViewBuilder::materialGathererJobs() const
{
return m_materialGathererJobs;
}
SynchronizerJobPtr RenderViewBuilder::syncRenderViewPostInitializationJob() const
{
return m_syncRenderViewPostInitializationJob;
}
SynchronizerJobPtr RenderViewBuilder::syncPreFrustumCullingJob() const
{
return m_syncPreFrustumCullingJob;
}
SynchronizerJobPtr RenderViewBuilder::syncRenderViewPreCommandBuildingJob() const
{
return m_syncRenderViewPreCommandBuildingJob;
}
SynchronizerJobPtr RenderViewBuilder::syncRenderViewPreCommandUpdateJob() const
{
return m_syncRenderViewPreCommandUpdateJob;
}
SynchronizerJobPtr RenderViewBuilder::syncRenderViewPostCommandUpdateJob() const
{
return m_syncRenderViewPostCommandUpdateJob;
}
SynchronizerJobPtr RenderViewBuilder::setClearDrawBufferIndexJob() const
{
return m_setClearDrawBufferIndexJob;
}
SynchronizerJobPtr RenderViewBuilder::syncFilterEntityByLayerJob() const
{
return m_syncFilterEntityByLayerJob;
}
SynchronizerJobPtr RenderViewBuilder::syncMaterialGathererJob() const
{
return m_syncMaterialGathererJob;
}
FilterProximityDistanceJobPtr RenderViewBuilder::filterProximityJob() const
{
return m_filterProximityJob;
}
void RenderViewBuilder::prepareJobs()
{
// Init what we can here
m_filterProximityJob->setManager(m_renderer->nodeManagers());
m_frustumCullingJob->setRoot(m_renderer->sceneRoot());
if (m_renderCommandCacheNeedsToBeRebuilt) {
m_renderViewCommandBuilderJobs.reserve(RenderViewBuilder::m_optimalParallelJobCount);
for (auto i = 0; i < RenderViewBuilder::m_optimalParallelJobCount; ++i) {
auto renderViewCommandBuilder = Render::Rhi::RenderViewCommandBuilderJobPtr::create();
m_renderViewCommandBuilderJobs.push_back(renderViewCommandBuilder);
}
m_syncRenderViewPreCommandBuildingJob = SynchronizerJobPtr::create(
SyncPreCommandBuilding(m_renderViewJob, m_renderViewCommandBuilderJobs, m_renderer,
m_leafNode),
JobTypes::SyncRenderViewPreCommandBuilding);
}
m_renderViewJob->setRenderer(m_renderer);
m_renderViewJob->setFrameGraphLeafNode(m_leafNode);
m_renderViewJob->setSubmitOrderIndex(m_renderViewIndex);
// RenderCommand building is the most consuming task -> split it
// Estimate the number of jobs to create based on the number of entities
m_renderViewCommandUpdaterJobs.reserve(RenderViewBuilder::m_optimalParallelJobCount);
for (auto i = 0; i < RenderViewBuilder::m_optimalParallelJobCount; ++i) {
auto renderViewCommandUpdater = Render::Rhi::RenderViewCommandUpdaterJobPtr::create();
renderViewCommandUpdater->setRenderer(m_renderer);
m_renderViewCommandUpdaterJobs.push_back(renderViewCommandUpdater);
}
if (m_materialGathererCacheNeedsToBeRebuilt) {
// Since Material gathering is an heavy task, we split it
const std::vector<HMaterial> &materialHandles =
m_renderer->nodeManagers()->materialManager()->activeHandles();
const size_t handlesCount = materialHandles.size();
if (handlesCount) {
m_materialGathererJobs.reserve(m_optimalParallelJobCount);
const size_t elementsPerJob = std::max(handlesCount / m_optimalParallelJobCount, size_t(1));
size_t elementCount = 0;
while (elementCount < handlesCount) {
auto materialGatherer = MaterialParameterGathererJobPtr::create();
materialGatherer->setNodeManagers(m_renderer->nodeManagers());
// TO DO: Candidate for std::span if C++20
materialGatherer->setHandles({materialHandles.begin() + elementCount,
materialHandles.begin() + std::min(elementCount + elementsPerJob, handlesCount)});
m_materialGathererJobs.push_back(materialGatherer);
elementCount += elementsPerJob;
}
}
m_syncMaterialGathererJob = SynchronizerJobPtr::create(
SyncMaterialParameterGatherer(m_materialGathererJobs, m_renderer, m_leafNode),
JobTypes::SyncMaterialGatherer);
}
if (m_layerCacheNeedsToBeRebuilt) {
m_filterEntityByLayerJob = Render::FilterLayerEntityJobPtr::create();
m_filterEntityByLayerJob->setManager(m_renderer->nodeManagers());
m_syncFilterEntityByLayerJob = SynchronizerJobPtr::create(
SyncFilterEntityByLayer(m_filterEntityByLayerJob, m_renderer, m_leafNode),
JobTypes::SyncFilterEntityByLayer);
}
m_syncRenderViewPreCommandUpdateJob = SynchronizerJobPtr::create(
SyncRenderViewPreCommandUpdate(m_renderViewJob, m_frustumCullingJob,
m_filterProximityJob, m_materialGathererJobs,
m_renderViewCommandUpdaterJobs,
m_renderViewCommandBuilderJobs, m_renderer, m_leafNode,
m_renderCommandCacheNeedsToBeRebuilt),
JobTypes::SyncRenderViewPreCommandUpdate);
m_syncRenderViewPostCommandUpdateJob = SynchronizerJobPtr::create(
SyncRenderViewPostCommandUpdate(m_renderViewJob, m_renderViewCommandUpdaterJobs,
m_renderer),
JobTypes::SyncRenderViewPostCommandUpdate);
m_syncRenderViewPostInitializationJob = SynchronizerJobPtr::create(
SyncRenderViewPostInitialization(m_renderViewJob, m_frustumCullingJob,
m_filterEntityByLayerJob, m_filterProximityJob,
m_materialGathererJobs, m_renderViewCommandUpdaterJobs,
m_renderViewCommandBuilderJobs),
JobTypes::SyncRenderViewInitialization);
}
QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
{
QVector<Qt3DCore::QAspectJobPtr> jobs;
auto daspect = QRenderAspectPrivate::get(m_renderer->aspect());
auto expandBVJob = daspect->m_expandBoundingVolumeJob;
auto worldTransformJob = daspect->m_worldTransformJob;
auto updateTreeEnabledJob = daspect->m_updateTreeEnabledJob;
auto updateSkinningPaletteJob = daspect->m_updateSkinningPaletteJob;
auto updateEntityLayersJob = daspect->m_updateEntityLayersJob;
jobs.reserve(m_materialGathererJobs.size() + m_renderViewCommandUpdaterJobs.size() + 11);
// Set dependencies
// Finish the skinning palette job before processing renderviews
// TODO: Maybe only update skinning palettes for non-culled entities
m_renderViewJob->addDependency(updateSkinningPaletteJob);
m_syncPreFrustumCullingJob->addDependency(worldTransformJob);
m_syncPreFrustumCullingJob->addDependency(m_renderer->updateShaderDataTransformJob());
m_syncPreFrustumCullingJob->addDependency(m_syncRenderViewPostInitializationJob);
m_frustumCullingJob->addDependency(expandBVJob);
m_frustumCullingJob->addDependency(m_syncPreFrustumCullingJob);
m_setClearDrawBufferIndexJob->addDependency(m_syncRenderViewPostInitializationJob);
m_syncRenderViewPostInitializationJob->addDependency(m_renderViewJob);
m_filterProximityJob->addDependency(expandBVJob);
m_filterProximityJob->addDependency(m_syncRenderViewPostInitializationJob);
m_syncRenderViewPreCommandUpdateJob->addDependency(m_syncRenderViewPostInitializationJob);
m_syncRenderViewPreCommandUpdateJob->addDependency(m_filterProximityJob);
m_syncRenderViewPreCommandUpdateJob->addDependency(m_frustumCullingJob);
// Ensure the RenderThread won't be able to process dirtyResources
// before they have been completely gathered
m_syncRenderViewPreCommandUpdateJob->addDependency(m_renderer->introspectShadersJob());
m_syncRenderViewPreCommandUpdateJob->addDependency(m_renderer->bufferGathererJob());
m_syncRenderViewPreCommandUpdateJob->addDependency(m_renderer->textureGathererJob());
m_syncRenderViewPreCommandUpdateJob->addDependency(m_renderer->lightGathererJob());
for (const auto &renderViewCommandUpdater : qAsConst(m_renderViewCommandUpdaterJobs)) {
renderViewCommandUpdater->addDependency(m_syncRenderViewPreCommandUpdateJob);
m_syncRenderViewPostCommandUpdateJob->addDependency(renderViewCommandUpdater);
}
m_renderer->frameCleanupJob()->addDependency(m_syncRenderViewPostCommandUpdateJob);
m_renderer->frameCleanupJob()->addDependency(m_setClearDrawBufferIndexJob);
// Add jobs
jobs.push_back(m_renderViewJob); // Step 1
jobs.push_back(m_syncRenderViewPostInitializationJob); // Step 2
if (m_renderCommandCacheNeedsToBeRebuilt) { // Step 3
m_syncRenderViewPreCommandBuildingJob->addDependency(
m_renderer->computableEntityFilterJob());
m_syncRenderViewPreCommandBuildingJob->addDependency(
m_renderer->renderableEntityFilterJob());
m_syncRenderViewPreCommandBuildingJob->addDependency(m_syncRenderViewPostInitializationJob);
if (m_materialGathererCacheNeedsToBeRebuilt)
m_syncRenderViewPreCommandBuildingJob->addDependency(m_syncMaterialGathererJob);
jobs.push_back(m_syncRenderViewPreCommandBuildingJob);
for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewCommandBuilderJobs)) {
renderViewCommandBuilder->addDependency(m_syncRenderViewPreCommandBuildingJob);
m_syncRenderViewPreCommandUpdateJob->addDependency(renderViewCommandBuilder);
jobs.push_back(renderViewCommandBuilder);
}
}
if (m_layerCacheNeedsToBeRebuilt) {
m_filterEntityByLayerJob->addDependency(updateEntityLayersJob);
m_filterEntityByLayerJob->addDependency(m_syncRenderViewPostInitializationJob);
m_filterEntityByLayerJob->addDependency(updateTreeEnabledJob);
m_syncFilterEntityByLayerJob->addDependency(m_filterEntityByLayerJob);
m_syncRenderViewPreCommandUpdateJob->addDependency(m_syncFilterEntityByLayerJob);
jobs.push_back(m_filterEntityByLayerJob); // Step 3
jobs.push_back(m_syncFilterEntityByLayerJob); // Step 4
}
jobs.push_back(m_syncPreFrustumCullingJob); // Step 3
jobs.push_back(m_filterProximityJob); // Step 3
jobs.push_back(m_setClearDrawBufferIndexJob); // Step 3
if (m_materialGathererCacheNeedsToBeRebuilt) {
for (const auto &materialGatherer : qAsConst(m_materialGathererJobs)) {
materialGatherer->addDependency(m_syncRenderViewPostInitializationJob);
materialGatherer->addDependency(m_renderer->introspectShadersJob());
materialGatherer->addDependency(m_renderer->filterCompatibleTechniqueJob());
jobs.push_back(materialGatherer); // Step3
m_syncMaterialGathererJob->addDependency(materialGatherer);
}
m_syncRenderViewPreCommandUpdateJob->addDependency(m_syncMaterialGathererJob);
jobs.push_back(m_syncMaterialGathererJob); // Step 3
}
jobs.push_back(m_frustumCullingJob); // Step 4
jobs.push_back(m_syncRenderViewPreCommandUpdateJob); // Step 5
// Build RenderCommands or Update RenderCommand Uniforms
for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewCommandUpdaterJobs)) // Step 6
jobs.push_back(renderViewCommandBuilder);
jobs.push_back(m_syncRenderViewPostCommandUpdateJob); // Step 7
return jobs;
}
Renderer *RenderViewBuilder::renderer() const
{
return m_renderer;
}
int RenderViewBuilder::renderViewIndex() const
{
return m_renderViewIndex;
}
void RenderViewBuilder::setLayerCacheNeedsToBeRebuilt(bool needsToBeRebuilt)
{
m_layerCacheNeedsToBeRebuilt = needsToBeRebuilt;
}
bool RenderViewBuilder::layerCacheNeedsToBeRebuilt() const
{
return m_layerCacheNeedsToBeRebuilt;
}
void RenderViewBuilder::setMaterialGathererCacheNeedsToBeRebuilt(bool needsToBeRebuilt)
{
m_materialGathererCacheNeedsToBeRebuilt = needsToBeRebuilt;
}
bool RenderViewBuilder::materialGathererCacheNeedsToBeRebuilt() const
{
return m_materialGathererCacheNeedsToBeRebuilt;
}
void RenderViewBuilder::setRenderCommandCacheNeedsToBeRebuilt(bool needsToBeRebuilt)
{
m_renderCommandCacheNeedsToBeRebuilt = needsToBeRebuilt;
}
bool RenderViewBuilder::renderCommandCacheNeedsToBeRebuilt() const
{
return m_renderCommandCacheNeedsToBeRebuilt;
}
int RenderViewBuilder::optimalJobCount()
{
return RenderViewBuilder::m_optimalParallelJobCount;
}
QVector<Entity *> RenderViewBuilder::entitiesInSubset(const QVector<Entity *> &entities,
const QVector<Entity *> &subset)
{
QVector<Entity *> intersection;
intersection.reserve(qMin(entities.size(), subset.size()));
std::set_intersection(entities.begin(), entities.end(), subset.begin(), subset.end(),
std::back_inserter(intersection));
return intersection;
}
} // Rhi
} // Render
} // Qt3DRender
QT_END_NAMESPACE