summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/renderers/opengl/debug/imguirenderer.cpp1
-rw-r--r--src/plugins/renderers/opengl/renderer/rendercommand_p.h9
-rw-r--r--src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp466
-rw-r--r--src/plugins/renderers/opengl/renderer/renderviewbuilder_p.h5
-rw-r--r--src/plugins/renderers/rhi/renderer/rendercommand_p.h9
-rw-r--r--src/plugins/renderers/rhi/renderer/renderview_p.h1
-rw-r--r--src/plugins/renderers/rhi/renderer/renderviewbuilder.cpp467
-rw-r--r--src/plugins/renderers/rhi/renderer/renderviewbuilder_p.h5
-rw-r--r--src/render/CMakeLists.txt1
-rw-r--r--src/render/jobs/jobs.pri3
-rw-r--r--src/render/jobs/renderercache_p.h3
-rw-r--r--src/render/jobs/rendersyncjobs_p.h539
-rw-r--r--src/render/jobs/renderviewjobutils.cpp18
-rw-r--r--src/render/jobs/renderviewjobutils_p.h6
-rw-r--r--tests/auto/render/opengl/renderviewbuilder/tst_renderviewbuilder.cpp3
15 files changed, 576 insertions, 960 deletions
diff --git a/src/plugins/renderers/opengl/debug/imguirenderer.cpp b/src/plugins/renderers/opengl/debug/imguirenderer.cpp
index 5ee72985a..3d4e9e614 100644
--- a/src/plugins/renderers/opengl/debug/imguirenderer.cpp
+++ b/src/plugins/renderers/opengl/debug/imguirenderer.cpp
@@ -46,6 +46,7 @@
#include "imguirenderer_p.h"
#include <renderview_p.h>
+#include <rendercommand_p.h>
#include <renderer_p.h>
#include <submissioncontext_p.h>
#include <Qt3DRender/private/geometryrenderermanager_p.h>
diff --git a/src/plugins/renderers/opengl/renderer/rendercommand_p.h b/src/plugins/renderers/opengl/renderer/rendercommand_p.h
index 710430073..09ed04855 100644
--- a/src/plugins/renderers/opengl/renderer/rendercommand_p.h
+++ b/src/plugins/renderers/opengl/renderer/rendercommand_p.h
@@ -75,15 +75,6 @@ namespace Render {
class RenderStateSet;
using RenderStateSetPtr = QSharedPointer<RenderStateSet>;
-enum RebuildFlag {
- FullCommandRebuild = 1 << 0,
- LayerCacheRebuild = 1 << 1,
- MaterialCacheRebuild = 1 << 2,
- LightCacheRebuild = 1 << 3
-};
-Q_DECLARE_FLAGS(RebuildFlagSet, RebuildFlag)
-Q_DECLARE_OPERATORS_FOR_FLAGS(RebuildFlagSet)
-
namespace OpenGL {
class GLShader;
diff --git a/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp b/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp
index 26ad8f0ec..6ba85db9e 100644
--- a/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp
+++ b/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp
@@ -39,6 +39,7 @@
#include "renderviewbuilder_p.h"
#include <Qt3DRender/private/qrenderaspect_p.h>
+#include <Qt3DRender/private/rendersyncjobs_p.h>
#include <QThread>
@@ -49,398 +50,8 @@ namespace Qt3DRender {
namespace Render {
namespace OpenGL {
-using RendererCache = Render::RendererCache<RenderCommand>;
-
namespace {
-int findIdealNumberOfWorkers(int elementCount, int packetSize = 100, int maxJobCount = 1)
-{
- if (elementCount == 0 || packetSize == 0)
- return 0;
- return std::min(std::max(elementCount / packetSize, 1), maxJobCount);
-}
-
-
-class SyncPreCommandBuilding
-{
-public:
- explicit SyncPreCommandBuilding(RenderViewInitializerJobPtr renderViewInitializerJob,
- const std::vector<RenderViewCommandBuilderJobPtr> &renderViewCommandBuilderJobs,
- Renderer *renderer,
- FrameGraphNode *leafNode)
- : m_renderViewInitializer(renderViewInitializerJob)
- , m_renderViewCommandBuilderJobs(renderViewCommandBuilderJobs)
- , m_renderer(renderer)
- , m_leafNode(leafNode)
- {
- }
-
- void operator()()
- {
- // Split commands to build among jobs
-
- // Rebuild RenderCommands for all entities in RV (ignoring filtering)
- RendererCache *cache = m_renderer->cache();
- QMutexLocker lock(cache->mutex());
-
- Q_ASSERT(cache->leafNodeCache.contains(m_leafNode));
- // The cache leaf should already have been created so we don't need to protect the access
- 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);
-
- // Split among the ideal number of command builders
- const int jobCount = m_renderViewCommandBuilderJobs.size();
- const int entityCount = entities.size();
- const int idealPacketSize = std::min(std::max(10, entityCount / jobCount), entityCount);
- // Try to split work into an ideal number of workers
- const int m = findIdealNumberOfWorkers(entityCount, idealPacketSize, jobCount);
-
- const Entity **entitiesPtr = const_cast<const Entity **>(entities.data());
- for (int i = 0; i < m; ++i) {
- const RenderViewCommandBuilderJobPtr renderViewCommandBuilder = m_renderViewCommandBuilderJobs.at(i);
- const int count = (i == m - 1) ? entityCount - (i * idealPacketSize) : idealPacketSize;
- renderViewCommandBuilder->setEntities(entitiesPtr, i * idealPacketSize, count);
- }
- }
-
-private:
- RenderViewInitializerJobPtr m_renderViewInitializer;
- std::vector<RenderViewCommandBuilderJobPtr> m_renderViewCommandBuilderJobs;
- Renderer *m_renderer;
- FrameGraphNode *m_leafNode;
-};
-
-class SyncRenderViewPostCommandUpdate
-{
-public:
- explicit SyncRenderViewPostCommandUpdate(const RenderViewInitializerJobPtr &renderViewJob,
- const std::vector<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();
-
- if (!rv->noDraw()) {
- // Sort command on RenderView
- rv->sort();
- }
- // Enqueue our fully populated RenderView with the RenderThread
- m_renderer->enqueueRenderView(rv, m_renderViewJob->submitOrderIndex());
- }
-
-private:
- RenderViewInitializerJobPtr m_renderViewJob;
- std::vector<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 std::vector<MaterialParameterGathererJobPtr> &materialGathererJobs,
- const std::vector<RenderViewCommandUpdaterJobPtr> &renderViewCommandUpdaterJobs,
- const std::vector<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 : m_materialGathererJobs) {
- materialGatherer->setRenderPassFilter(const_cast<RenderPassFilter *>(rv->renderPassFilter()));
- materialGatherer->setTechniqueFilter(const_cast<TechniqueFilter *>(rv->techniqueFilter()));
- }
-
- // Command builders and updates
- for (const auto &renderViewCommandUpdater : m_renderViewCommandUpdaterJobs)
- renderViewCommandUpdater->setRenderView(rv);
- for (const auto &renderViewCommandBuilder : 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;
- std::vector<MaterialParameterGathererJobPtr> m_materialGathererJobs;
- std::vector<RenderViewCommandUpdaterJobPtr> m_renderViewCommandUpdaterJobs;
- std::vector<RenderViewCommandBuilderJobPtr> m_renderViewCommandBuilderJobs;
-};
-
-class SyncRenderViewPreCommandUpdate
-{
-public:
- explicit SyncRenderViewPreCommandUpdate(const RenderViewInitializerJobPtr &renderViewJob,
- const FrustumCullingJobPtr &frustumCullingJob,
- const FilterProximityDistanceJobPtr &filterProximityJob,
- const std::vector<MaterialParameterGathererJobPtr> &materialGathererJobs,
- const std::vector<RenderViewCommandUpdaterJobPtr> &renderViewCommandUpdaterJobs,
- const std::vector<RenderViewCommandBuilderJobPtr> &renderViewCommandBuilderJobs,
- Renderer *renderer,
- FrameGraphNode *leafNode,
- RebuildFlagSet rebuildFlags)
- : 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_rebuildFlags(rebuildFlags)
- {}
-
- 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));
-
- // We don't need to protect the cache access as
- // 1) The cache leaf is created
- // 2) We are only reading conccurently the cache values that are shared across all RV
- // 3) Each instance of this job is reading and writing in its own cache leaf so there's
- // no conflict
-
- const bool isDraw = !rv->isCompute();
- RendererCache::LeafNodeData &cacheForLeaf = cache->leafNodeCache[m_leafNode];
-
- const bool fullRebuild = m_rebuildFlags.testFlag(RebuildFlag::FullCommandRebuild);
- const bool layerFilteringRebuild = m_rebuildFlags.testFlag(RebuildFlag::LayerCacheRebuild);
- const bool lightsCacheRebuild = m_rebuildFlags.testFlag(RebuildFlag::LightCacheRebuild);
- const bool cameraDirty = cacheForLeaf.viewProjectionMatrix != rv->viewProjectionMatrix();
- const bool hasProximityFilter = !rv->proximityFilterIds().empty();
- const bool commandFilteringRequired =
- fullRebuild ||
- layerFilteringRebuild ||
- lightsCacheRebuild ||
- cameraDirty ||
- hasProximityFilter;
-
- // If we have no filteredRenderCommandDataViews then we should have fullRebuild set to true
- // otherwise something is wrong
- Q_ASSERT(fullRebuild || cacheForLeaf.filteredRenderCommandDataViews);
-
- // 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 (fullRebuild) {
- EntityRenderCommandData commandData;
- // Reduction
- {
- int totalCommandCount = 0;
- for (const RenderViewCommandBuilderJobPtr &renderViewCommandBuilder : qAsConst(m_renderViewCommandBuilderJobs))
- totalCommandCount += renderViewCommandBuilder->commandData().size();
- commandData.reserve(totalCommandCount);
- for (const RenderViewCommandBuilderJobPtr &renderViewCommandBuilder : qAsConst(m_renderViewCommandBuilderJobs))
- commandData += std::move(renderViewCommandBuilder->commandData());
- }
-
- // Store new cache
- EntityRenderCommandDataViewPtr dataView = EntityRenderCommandDataViewPtr::create();
- dataView->data = std::move(commandData);
- // Store the update dataView
- cacheForLeaf.filteredRenderCommandDataViews = dataView;
- }
-
-
- // Should be fairly infrequent
- if (layerFilteringRebuild || fullRebuild) {
- // Filter out renderable entities that weren't selected by the layer filters and store that in cache
- cacheForLeaf.layeredFilteredRenderables = RenderViewBuilder::entitiesInSubset(
- isDraw ? cache->renderableEntities : cache->computeEntities,
- cacheForLeaf.filterEntitiesByLayer);
- // Set default value for filteredAndCulledRenderables
- if (isDraw)
- cacheForLeaf.filteredAndCulledRenderables = cacheForLeaf.layeredFilteredRenderables;
- }
-
- // Should be fairly infrequent
- if (lightsCacheRebuild) {
- // Filter out light sources that weren't selected by the
- // layer filters and store that in cache
- const std::vector<Entity *> &layeredFilteredEntities = cacheForLeaf.filterEntitiesByLayer;
- std::vector<LightSource> filteredLightSources = cache->gatheredLights;
-
- auto it = filteredLightSources.begin();
-
- while (it != filteredLightSources.end()) {
- if (!std::binary_search(layeredFilteredEntities.begin(),
- layeredFilteredEntities.end(),
- it->entity))
- it = filteredLightSources.erase(it);
- else
- ++it;
- }
- cacheForLeaf.layeredFilteredLightSources = std::move(filteredLightSources);
- }
-
- // This is likely very frequent
- if (cameraDirty) {
- // Record the updated viewProjectionMatrix in the cache to allow check to be performed
- // next frame
- cacheForLeaf.viewProjectionMatrix = rv->viewProjectionMatrix();
- }
-
- // Filter out frustum culled entity for drawable entities and store in cache
- // We need to check this regardless of whether the camera has moved since
- // entities in the scene themselves could have moved
- if (isDraw && rv->frustumCulling()) {
- cacheForLeaf.filteredAndCulledRenderables = RenderViewBuilder::entitiesInSubset(
- cacheForLeaf.layeredFilteredRenderables,
- m_frustumCullingJob->visibleEntities());
- }
-
- rv->setMaterialParameterTable(cacheForLeaf.materialParameterGatherer);
- rv->setEnvironmentLight(cache->environmentLight);
-
- // Set the light sources, with layer filters applied.
- rv->setLightSources(cacheForLeaf.layeredFilteredLightSources);
-
- std::vector<Entity *> renderableEntities = isDraw ? cacheForLeaf.filteredAndCulledRenderables : cacheForLeaf.layeredFilteredRenderables;
-
- // TO DO: Find a way to do that only if proximity entities has changed
- if (isDraw) {
- // Filter out entities which didn't satisfy proximity filtering
- if (hasProximityFilter)
- renderableEntities = RenderViewBuilder::entitiesInSubset(renderableEntities,
- m_filterProximityJob->filteredEntities());
- }
-
- EntityRenderCommandDataViewPtr filteredCommandData = cacheForLeaf.filteredRenderCommandDataViews;
-
- // Set RenderCommandDataView on RV (will be used later on to sort commands ...)
- rv->setRenderCommandDataView(filteredCommandData);
-
- // Filter out Render commands for which the Entity wasn't selected because
- // of frustum, proximity or layer filtering
- if (commandFilteringRequired) {
- const std::vector<const Entity *> &entities = filteredCommandData->data.entities;
- // Because cacheForLeaf.renderableEntities or computeEntities are sorted
- // What we get out of EntityRenderCommandData is also sorted by Entity
- auto eIt = renderableEntities.cbegin();
- const auto eEnd = renderableEntities.cend();
- size_t cIt = 0;
- const size_t cEnd = entities.size();
-
- std::vector<size_t> filteredCommandIndices;
- filteredCommandIndices.reserve(renderableEntities.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 && entities[cIt] < targetEntity)
- ++cIt;
-
- // Push pointers to command data for all commands that match the
- // entity
- while (cIt != cEnd && entities[cIt] == targetEntity) {
- filteredCommandIndices.push_back(cIt);
- ++cIt;
- }
- ++eIt;
- }
-
- // Store result in cache
- cacheForLeaf.filteredRenderCommandDataViews->indices = std::move(filteredCommandIndices);
- }
-
- // Split among the number of command updaters
- const int jobCount = m_renderViewCommandUpdaterJobs.size();
- const int commandCount = filteredCommandData->size();
- const int idealPacketSize = std::min(std::max(10, commandCount), commandCount);
- const int m = findIdealNumberOfWorkers(commandCount, idealPacketSize, jobCount);
-
- for (int i = 0; i < m; ++i) {
- // TO DO: Based on whether we had to update the commands
- // we should be able to know what needs to be recomputed
- // -> lights/standard uniforms ... might no have to be set over and over again
- // if they are identical
- const RenderViewCommandUpdaterJobPtr &renderViewCommandUpdater = m_renderViewCommandUpdaterJobs.at(i);
- const size_t count = (i == m - 1) ? commandCount - (i * idealPacketSize) : idealPacketSize;
- renderViewCommandUpdater->setRenderablesSubView({filteredCommandData, size_t(i * idealPacketSize), count});
- }
- }
- }
-
-private:
- RenderViewInitializerJobPtr m_renderViewJob;
- FrustumCullingJobPtr m_frustumCullingJob;
- FilterProximityDistanceJobPtr m_filterProximityJob;
- std::vector<MaterialParameterGathererJobPtr> m_materialGathererJobs;
- std::vector<RenderViewCommandUpdaterJobPtr> m_renderViewCommandUpdaterJobs;
- std::vector<RenderViewCommandBuilderJobPtr> m_renderViewCommandBuilderJobs;
- Renderer *m_renderer;
- FrameGraphNode *m_leafNode;
- RebuildFlagSet m_rebuildFlags;
-};
-
class SetClearDrawBufferIndex
{
public:
@@ -462,69 +73,6 @@ 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());
- Q_ASSERT(m_renderer->cache()->leafNodeCache.contains(m_leafNode));
- // The cache leaf should already have been created so we don't need to protect the access
- RendererCache::LeafNodeData &dataCacheForLeaf = m_renderer->cache()->leafNodeCache[m_leafNode];
- // Save the filtered by layer subset into the cache
- dataCacheForLeaf.filterEntitiesByLayer = std::move(m_filterEntityByLayerJob->filteredEntities());
- }
-
-private:
- FilterLayerEntityJobPtr m_filterEntityByLayerJob;
- Renderer *m_renderer;
- FrameGraphNode *m_leafNode;
-};
-
-class SyncMaterialParameterGatherer
-{
-public:
- explicit SyncMaterialParameterGatherer(const std::vector<MaterialParameterGathererJobPtr> &materialParameterGathererJobs,
- Renderer *renderer,
- FrameGraphNode *leafNode)
- : m_materialParameterGathererJobs(materialParameterGathererJobs)
- , m_renderer(renderer)
- , m_leafNode(leafNode)
- {
- }
-
- void operator()()
- {
- // The cache leaf was created by SyncRenderViewPostInitialization on which we depend
- // so we don't need to protect the access
- QMutexLocker lock(m_renderer->cache()->mutex());
- RendererCache::LeafNodeData &dataCacheForLeaf = m_renderer->cache()->leafNodeCache[m_leafNode];
- dataCacheForLeaf.materialParameterGatherer.clear();
-
- for (const auto &materialGatherer : m_materialParameterGathererJobs) {
- const MaterialParameterGathererData &source = materialGatherer->materialToPassAndParameter();
- for (auto it = std::begin(source); it != std::end(source); ++it) {
- Q_ASSERT(!dataCacheForLeaf.materialParameterGatherer.contains(it.key()));
- dataCacheForLeaf.materialParameterGatherer.insert(it.key(), it.value());
- }
- }
- }
-
-private:
- std::vector<MaterialParameterGathererJobPtr> m_materialParameterGathererJobs;
- Renderer *m_renderer;
- FrameGraphNode *m_leafNode;
-};
-
} // anonymous
RenderViewBuilder::RenderViewBuilder(Render::FrameGraphNode *leafNode, int renderViewIndex, Renderer *renderer)
@@ -917,18 +465,6 @@ void RenderViewBuilder::setOptimalJobCount(int v)
m_optimalParallelJobCount = v;
}
-std::vector<Entity *> RenderViewBuilder::entitiesInSubset(const std::vector<Entity *> &entities,
- const std::vector<Entity *> &subset)
-{
- std::vector<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;
-}
-
} // OpenGL
} // Render
diff --git a/src/plugins/renderers/opengl/renderer/renderviewbuilder_p.h b/src/plugins/renderers/opengl/renderer/renderviewbuilder_p.h
index 77fec9f0c..a2a515d1a 100644
--- a/src/plugins/renderers/opengl/renderer/renderviewbuilder_p.h
+++ b/src/plugins/renderers/opengl/renderer/renderviewbuilder_p.h
@@ -61,6 +61,8 @@
#include <Qt3DRender/private/materialparametergathererjob_p.h>
#include <Qt3DRender/private/renderviewcommandbuilderjob_p.h>
#include <Qt3DRender/private/renderviewcommandupdaterjob_p.h>
+#include <Qt3DRender/private/rendersyncjobs_p.h>
+#include <rendercommand_p.h>
#include <renderview_p.h>
QT_BEGIN_NAMESPACE
@@ -121,9 +123,6 @@ public:
int optimalJobCount() const;
void setOptimalJobCount(int v);
- static std::vector<Entity *> entitiesInSubset(const std::vector<Entity *> &entities,
- const std::vector<Entity *> &subset);
-
private:
Render::FrameGraphNode *m_leafNode;
const int m_renderViewIndex;
diff --git a/src/plugins/renderers/rhi/renderer/rendercommand_p.h b/src/plugins/renderers/rhi/renderer/rendercommand_p.h
index 031b4fca2..a4f7332de 100644
--- a/src/plugins/renderers/rhi/renderer/rendercommand_p.h
+++ b/src/plugins/renderers/rhi/renderer/rendercommand_p.h
@@ -77,15 +77,6 @@ namespace Render {
class RenderStateSet;
using RenderStateSetPtr = QSharedPointer<RenderStateSet>;
-enum RebuildFlag {
- FullCommandRebuild = 1 << 0,
- LayerCacheRebuild = 1 << 1,
- MaterialCacheRebuild = 1 << 2,
- LightCacheRebuild = 1 << 3
-};
-Q_DECLARE_FLAGS(RebuildFlagSet, RebuildFlag)
-Q_DECLARE_OPERATORS_FOR_FLAGS(RebuildFlagSet)
-
namespace Rhi {
class RHIShader;
diff --git a/src/plugins/renderers/rhi/renderer/renderview_p.h b/src/plugins/renderers/rhi/renderer/renderview_p.h
index 8600b1591..87ff7407f 100644
--- a/src/plugins/renderers/rhi/renderer/renderview_p.h
+++ b/src/plugins/renderers/rhi/renderer/renderview_p.h
@@ -97,6 +97,7 @@ namespace Rhi {
class Renderer;
class RenderCommand;
+class RHIShader;
typedef QPair<ShaderUniform, QVariant> ActivePropertyContent;
typedef QPair<QString, ActivePropertyContent> ActiveProperty;
diff --git a/src/plugins/renderers/rhi/renderer/renderviewbuilder.cpp b/src/plugins/renderers/rhi/renderer/renderviewbuilder.cpp
index 9b78c3136..138d53612 100644
--- a/src/plugins/renderers/rhi/renderer/renderviewbuilder.cpp
+++ b/src/plugins/renderers/rhi/renderer/renderviewbuilder.cpp
@@ -49,461 +49,6 @@ namespace Qt3DRender {
namespace Render {
namespace Rhi {
-using RendererCache = Render::RendererCache<RenderCommand>;
-
-namespace {
-
-int findIdealNumberOfWorkers(int elementCount, int packetSize = 100, int maxJobCount = 1)
-{
- if (elementCount == 0 || packetSize == 0)
- return 0;
- return std::min(std::max(elementCount / packetSize, 1), maxJobCount);
-}
-
-
-class SyncPreCommandBuilding
-{
-public:
- explicit SyncPreCommandBuilding(RenderViewInitializerJobPtr renderViewInitializerJob,
- const std::vector<RenderViewCommandBuilderJobPtr> &renderViewCommandBuilderJobs,
- Renderer *renderer,
- FrameGraphNode *leafNode)
- : m_renderViewInitializer(renderViewInitializerJob)
- , m_renderViewCommandBuilderJobs(renderViewCommandBuilderJobs)
- , m_renderer(renderer)
- , m_leafNode(leafNode)
- {
- }
-
- void operator()()
- {
- // Split commands to build among jobs
-
- // Rebuild RenderCommands for all entities in RV (ignoring filtering)
- RendererCache *cache = m_renderer->cache();
- QMutexLocker lock(m_renderer->cache()->mutex());
- Q_ASSERT(cache->leafNodeCache.contains(m_leafNode));
- // The cache leaf should already have been created so we don't need to protect the access
- 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);
-
- // Split among the ideal number of command builders
- const int jobCount = m_renderViewCommandBuilderJobs.size();
- const int entityCount = entities.size();
- const int idealPacketSize = std::min(std::max(10, entityCount / jobCount), entityCount);
- // Try to split work into an ideal number of workers
- const int m = findIdealNumberOfWorkers(entityCount, idealPacketSize, jobCount);
-
- const Entity **entitiesPtr = const_cast<const Entity **>(entities.data());
- for (int i = 0; i < m; ++i) {
- const RenderViewCommandBuilderJobPtr renderViewCommandBuilder = m_renderViewCommandBuilderJobs.at(i);
- const int count = (i == m - 1) ? entityCount - (i * idealPacketSize) : idealPacketSize;
- renderViewCommandBuilder->setEntities(entitiesPtr, i * idealPacketSize, count);
- }
- }
-
-private:
- RenderViewInitializerJobPtr m_renderViewInitializer;
- std::vector<RenderViewCommandBuilderJobPtr> m_renderViewCommandBuilderJobs;
- Renderer *m_renderer;
- FrameGraphNode *m_leafNode;
-};
-
-class SyncRenderViewPostCommandUpdate
-{
-public:
- explicit SyncRenderViewPostCommandUpdate(const RenderViewInitializerJobPtr &renderViewJob,
- const std::vector<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();
-
- if (!rv->noDraw()) {
- // Sort command on RenderView
- rv->sort();
- }
- // Enqueue our fully populated RenderView with the RenderThread
- m_renderer->enqueueRenderView(rv, m_renderViewJob->submitOrderIndex());
- }
-
-private:
- RenderViewInitializerJobPtr m_renderViewJob;
- std::vector<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 std::vector<MaterialParameterGathererJobPtr> &materialGathererJobs,
- const std::vector<RenderViewCommandUpdaterJobPtr> &renderViewCommandUpdaterJobs,
- const std::vector<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 : m_materialGathererJobs) {
- materialGatherer->setRenderPassFilter(const_cast<RenderPassFilter *>(rv->renderPassFilter()));
- materialGatherer->setTechniqueFilter(const_cast<TechniqueFilter *>(rv->techniqueFilter()));
- }
-
- // Command builders and updates
- for (const auto &renderViewCommandUpdater : m_renderViewCommandUpdaterJobs)
- renderViewCommandUpdater->setRenderView(rv);
- for (const auto &renderViewCommandBuilder : 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;
- std::vector<MaterialParameterGathererJobPtr> m_materialGathererJobs;
- std::vector<RenderViewCommandUpdaterJobPtr> m_renderViewCommandUpdaterJobs;
- std::vector<RenderViewCommandBuilderJobPtr> m_renderViewCommandBuilderJobs;
-};
-
-class SyncRenderViewPreCommandUpdate
-{
-public:
- explicit SyncRenderViewPreCommandUpdate(const RenderViewInitializerJobPtr &renderViewJob,
- const FrustumCullingJobPtr &frustumCullingJob,
- const FilterProximityDistanceJobPtr &filterProximityJob,
- const std::vector<MaterialParameterGathererJobPtr> &materialGathererJobs,
- const std::vector<RenderViewCommandUpdaterJobPtr> &renderViewCommandUpdaterJobs,
- const std::vector<RenderViewCommandBuilderJobPtr> &renderViewCommandBuilderJobs,
- Renderer *renderer,
- FrameGraphNode *leafNode,
- RebuildFlagSet rebuildFlags)
- : 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_rebuildFlags(rebuildFlags)
- {}
-
- 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));
-
- // We don't need to protect the cache access as
- // 1) The cache leaf is created
- // 2) We are only reading conccurently the cache values that are shared across all RV
- // 3) Each instance of this job is reading and writing in its own cache leaf so there's
- // no conflict
-
- const bool isDraw = !rv->isCompute();
- RendererCache::LeafNodeData &cacheForLeaf = cache->leafNodeCache[m_leafNode];
-
- const bool fullRebuild = m_rebuildFlags.testFlag(RebuildFlag::FullCommandRebuild);
- const bool layerFilteringRebuild = m_rebuildFlags.testFlag(RebuildFlag::LayerCacheRebuild);
- const bool lightsCacheRebuild = m_rebuildFlags.testFlag(RebuildFlag::LightCacheRebuild);
- const bool cameraDirty = cacheForLeaf.viewProjectionMatrix != rv->viewProjectionMatrix();
- const bool hasProximityFilter = !rv->proximityFilterIds().empty();
- const bool commandFilteringRequired =
- fullRebuild ||
- layerFilteringRebuild ||
- lightsCacheRebuild ||
- cameraDirty ||
- hasProximityFilter;
-
- // If we have no filteredRenderCommandDataViews then we should have fullRebuild set to true
- // otherwise something is wrong
- Q_ASSERT(fullRebuild || cacheForLeaf.filteredRenderCommandDataViews);
-
- // 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 (fullRebuild) {
- EntityRenderCommandData commandData;
- // Reduction
- {
- int totalCommandCount = 0;
- for (const RenderViewCommandBuilderJobPtr &renderViewCommandBuilder : qAsConst(m_renderViewCommandBuilderJobs))
- totalCommandCount += renderViewCommandBuilder->commandData().size();
- commandData.reserve(totalCommandCount);
- for (const RenderViewCommandBuilderJobPtr &renderViewCommandBuilder : qAsConst(m_renderViewCommandBuilderJobs))
- commandData += std::move(renderViewCommandBuilder->commandData());
- }
-
- // Store new cache
- EntityRenderCommandDataViewPtr dataView = EntityRenderCommandDataViewPtr::create();
- dataView->data = std::move(commandData);
- // Store the update dataView
- cacheForLeaf.filteredRenderCommandDataViews = dataView;
- }
-
-
- // Should be fairly infrequent
- if (layerFilteringRebuild || fullRebuild) {
- // Filter out renderable entities that weren't selected by the layer filters and store that in cache
- cacheForLeaf.layeredFilteredRenderables = RenderViewBuilder::entitiesInSubset(
- isDraw ? cache->renderableEntities : cache->computeEntities,
- cacheForLeaf.filterEntitiesByLayer);
- // Set default value for filteredAndCulledRenderables
- if (isDraw)
- cacheForLeaf.filteredAndCulledRenderables = cacheForLeaf.layeredFilteredRenderables;
- }
-
- // Should be fairly infrequent
- if (lightsCacheRebuild) {
- // Filter out light sources that weren't selected by the
- // layer filters and store that in cache
- const std::vector<Entity *> &layeredFilteredEntities = cacheForLeaf.filterEntitiesByLayer;
- std::vector<LightSource> filteredLightSources = cache->gatheredLights;
-
- auto it = filteredLightSources.begin();
-
- while (it != filteredLightSources.end()) {
- if (!std::binary_search(layeredFilteredEntities.begin(),
- layeredFilteredEntities.end(),
- it->entity))
- it = filteredLightSources.erase(it);
- else
- ++it;
- }
- cacheForLeaf.layeredFilteredLightSources = std::move(filteredLightSources);
- }
-
- // This is likely very frequent
- if (cameraDirty) {
- // Record the updated viewProjectionMatrix in the cache to allow check to be performed
- // next frame
- cacheForLeaf.viewProjectionMatrix = rv->viewProjectionMatrix();
- }
-
- // Filter out frustum culled entity for drawable entities and store in cache
- // We need to check this regardless of whether the camera has moved since
- // entities in the scene themselves could have moved
- if (isDraw && rv->frustumCulling()) {
- cacheForLeaf.filteredAndCulledRenderables = RenderViewBuilder::entitiesInSubset(
- cacheForLeaf.layeredFilteredRenderables,
- m_frustumCullingJob->visibleEntities());
- }
-
- rv->setMaterialParameterTable(cacheForLeaf.materialParameterGatherer);
- rv->setEnvironmentLight(cache->environmentLight);
-
- // Set the light sources, with layer filters applied.
- rv->setLightSources(cacheForLeaf.layeredFilteredLightSources);
-
- std::vector<Entity *> renderableEntities = isDraw ? cacheForLeaf.filteredAndCulledRenderables : cacheForLeaf.layeredFilteredRenderables;
-
- // TO DO: Find a way to do that only if proximity entities has changed
- if (isDraw) {
- // Filter out entities which didn't satisfy proximity filtering
- if (hasProximityFilter)
- renderableEntities = RenderViewBuilder::entitiesInSubset(renderableEntities,
- m_filterProximityJob->filteredEntities());
- }
-
- EntityRenderCommandDataViewPtr filteredCommandData = cacheForLeaf.filteredRenderCommandDataViews;
-
- // Set RenderCommandDataView on RV (will be used later on to sort commands ...)
- rv->setRenderCommandDataView(filteredCommandData);
-
- // Filter out Render commands for which the Entity wasn't selected because
- // of frustum, proximity or layer filtering
- if (commandFilteringRequired) {
- const std::vector<const Entity *> &entities = filteredCommandData->data.entities;
- // Because cacheForLeaf.renderableEntities or computeEntities are sorted
- // What we get out of EntityRenderCommandData is also sorted by Entity
- auto eIt = renderableEntities.cbegin();
- const auto eEnd = renderableEntities.cend();
- size_t cIt = 0;
- const size_t cEnd = entities.size();
-
- std::vector<size_t> filteredCommandIndices;
- filteredCommandIndices.reserve(renderableEntities.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 && entities[cIt] < targetEntity)
- ++cIt;
-
- // Push pointers to command data for all commands that match the
- // entity
- while (cIt != cEnd && entities[cIt] == targetEntity) {
- filteredCommandIndices.push_back(cIt);
- ++cIt;
- }
- ++eIt;
- }
-
- // Store result in cache
- cacheForLeaf.filteredRenderCommandDataViews->indices = std::move(filteredCommandIndices);
- }
-
- // Split among the number of command updaters
- const int jobCount = m_renderViewCommandUpdaterJobs.size();
- const int commandCount = filteredCommandData->size();
- const int idealPacketSize = std::min(std::max(10, commandCount), commandCount);
- const int m = findIdealNumberOfWorkers(commandCount, idealPacketSize, jobCount);
-
- for (int i = 0; i < m; ++i) {
- // TO DO: Based on whether we had to update the commands
- // we should be able to know what needs to be recomputed
- // -> lights/standard uniforms ... might no have to be set over and over again
- // if they are identical
- const RenderViewCommandUpdaterJobPtr &renderViewCommandUpdater = m_renderViewCommandUpdaterJobs.at(i);
- const size_t count = (i == m - 1) ? commandCount - (i * idealPacketSize) : idealPacketSize;
- renderViewCommandUpdater->setRenderablesSubView({filteredCommandData, size_t(i * idealPacketSize), count});
- }
- }
- }
-
-private:
- RenderViewInitializerJobPtr m_renderViewJob;
- FrustumCullingJobPtr m_frustumCullingJob;
- FilterProximityDistanceJobPtr m_filterProximityJob;
- std::vector<MaterialParameterGathererJobPtr> m_materialGathererJobs;
- std::vector<RenderViewCommandUpdaterJobPtr> m_renderViewCommandUpdaterJobs;
- std::vector<RenderViewCommandBuilderJobPtr> m_renderViewCommandBuilderJobs;
- Renderer *m_renderer;
- FrameGraphNode *m_leafNode;
- RebuildFlagSet m_rebuildFlags;
-};
-
-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());
- Q_ASSERT(m_renderer->cache()->leafNodeCache.contains(m_leafNode));
- // The cache leaf should already have been created so we don't need to protect the access
- RendererCache::LeafNodeData &dataCacheForLeaf = m_renderer->cache()->leafNodeCache[m_leafNode];
- // Save the filtered by layer subset into the cache
- dataCacheForLeaf.filterEntitiesByLayer = std::move(m_filterEntityByLayerJob->filteredEntities());
- }
-
-private:
- FilterLayerEntityJobPtr m_filterEntityByLayerJob;
- Renderer *m_renderer;
- FrameGraphNode *m_leafNode;
-};
-
-class SyncMaterialParameterGatherer
-{
-public:
- explicit SyncMaterialParameterGatherer(const std::vector<MaterialParameterGathererJobPtr> &materialParameterGathererJobs,
- Renderer *renderer,
- FrameGraphNode *leafNode)
- : m_materialParameterGathererJobs(materialParameterGathererJobs)
- , m_renderer(renderer)
- , m_leafNode(leafNode)
- {
- }
-
- void operator()()
- {
- // The cache leaf was created by SyncRenderViewPostInitialization on which we depend
- // so we don't need to protect the access
- QMutexLocker lock(m_renderer->cache()->mutex());
- RendererCache::LeafNodeData &dataCacheForLeaf = m_renderer->cache()->leafNodeCache[m_leafNode];
- dataCacheForLeaf.materialParameterGatherer.clear();
-
- for (const auto &materialGatherer : m_materialParameterGathererJobs) {
- const MaterialParameterGathererData &source = materialGatherer->materialToPassAndParameter();
- for (auto it = std::begin(source); it != std::end(source); ++it) {
- Q_ASSERT(!dataCacheForLeaf.materialParameterGatherer.contains(it.key()));
- dataCacheForLeaf.materialParameterGatherer.insert(it.key(), it.value());
- }
- }
- }
-
-private:
- std::vector<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)
@@ -878,18 +423,6 @@ void RenderViewBuilder::setOptimalJobCount(int v)
m_optimalParallelJobCount = v;
}
-std::vector<Entity *> RenderViewBuilder::entitiesInSubset(const std::vector<Entity *> &entities,
- const std::vector<Entity *> &subset)
-{
- std::vector<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
diff --git a/src/plugins/renderers/rhi/renderer/renderviewbuilder_p.h b/src/plugins/renderers/rhi/renderer/renderviewbuilder_p.h
index 6883a10e0..790d2d5e6 100644
--- a/src/plugins/renderers/rhi/renderer/renderviewbuilder_p.h
+++ b/src/plugins/renderers/rhi/renderer/renderviewbuilder_p.h
@@ -61,6 +61,8 @@
#include <Qt3DRender/private/materialparametergathererjob_p.h>
#include <Qt3DRender/private/renderviewcommandbuilderjob_p.h>
#include <Qt3DRender/private/renderviewcommandupdaterjob_p.h>
+#include <Qt3DRender/private/rendersyncjobs_p.h>
+#include <rendercommand_p.h>
#include <renderview_p.h>
QT_BEGIN_NAMESPACE
@@ -120,9 +122,6 @@ public:
int optimalJobCount() const;
void setOptimalJobCount(int v);
- static std::vector<Entity *> entitiesInSubset(const std::vector<Entity *> &entities,
- const std::vector<Entity *> &subset);
-
private:
Render::FrameGraphNode *m_leafNode;
const int m_renderViewIndex;
diff --git a/src/render/CMakeLists.txt b/src/render/CMakeLists.txt
index 061dae524..5380659cc 100644
--- a/src/render/CMakeLists.txt
+++ b/src/render/CMakeLists.txt
@@ -170,6 +170,7 @@ qt_add_module(3DRender
jobs/renderviewcommandbuilderjob_p.h
jobs/renderviewcommandupdaterjob_p.h
jobs/renderviewinitializerjob_p.h
+ jobs/rendersyncjobs_p.h
lights/environmentlight.cpp lights/environmentlight_p.h
lights/light.cpp lights/light_p.h
lights/lightsource.cpp lights/lightsource_p.h
diff --git a/src/render/jobs/jobs.pri b/src/render/jobs/jobs.pri
index 20dc9d1f9..c258202ac 100644
--- a/src/render/jobs/jobs.pri
+++ b/src/render/jobs/jobs.pri
@@ -35,7 +35,8 @@ HEADERS += \
$$PWD/renderercache_p.h \
$$PWD/renderviewcommandbuilderjob_p.h \
$$PWD/renderviewcommandupdaterjob_p.h \
- $$PWD/renderviewinitializerjob_p.h
+ $$PWD/renderviewinitializerjob_p.h \
+ $$PWD/rendersyncjobs_p.h
SOURCES += \
$$PWD/updateworldtransformjob.cpp \
diff --git a/src/render/jobs/renderercache_p.h b/src/render/jobs/renderercache_p.h
index 46e9aadc2..1be46a3d4 100644
--- a/src/render/jobs/renderercache_p.h
+++ b/src/render/jobs/renderercache_p.h
@@ -51,12 +51,11 @@
// We mean it.
//
+#include <Qt3DCore/private/vector_helper_p.h>
#include <Qt3DRender/QFrameGraphNode>
-
#include <Qt3DRender/private/entity_p.h>
#include <Qt3DRender/private/renderviewjobutils_p.h>
#include <Qt3DRender/private/lightsource_p.h>
-#include <rendercommand_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/render/jobs/rendersyncjobs_p.h b/src/render/jobs/rendersyncjobs_p.h
new file mode 100644
index 000000000..c2ad714a3
--- /dev/null
+++ b/src/render/jobs/rendersyncjobs_p.h
@@ -0,0 +1,539 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_RENDERSYNCJOBS_H
+#define QT3DRENDER_RENDER_RENDERSYNCJOBS_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DCore/qaspectjob.h>
+#include <Qt3DRender/private/renderviewinitializerjob_p.h>
+#include <Qt3DRender/private/frustumcullingjob_p.h>
+#include <Qt3DRender/private/filterlayerentityjob_p.h>
+#include <Qt3DRender/private/filterproximitydistancejob_p.h>
+#include <Qt3DRender/private/materialparametergathererjob_p.h>
+#include <Qt3DRender/private/renderviewcommandbuilderjob_p.h>
+#include <Qt3DRender/private/renderviewcommandupdaterjob_p.h>
+#include <Qt3DRender/private/renderercache_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+enum RebuildFlag {
+ FullCommandRebuild = 1 << 0,
+ LayerCacheRebuild = 1 << 1,
+ MaterialCacheRebuild = 1 << 2,
+ LightCacheRebuild = 1 << 3
+};
+Q_DECLARE_FLAGS(RebuildFlagSet, RebuildFlag)
+Q_DECLARE_OPERATORS_FOR_FLAGS(RebuildFlagSet)
+
+#define RenderViewInitializerJobPtrAlias RenderViewInitializerJobPtr<RenderView, Renderer>
+#define RenderViewCommandBuilderJobPtrAlias RenderViewCommandBuilderJobPtr<RenderView, RenderCommand>
+#define RenderViewCommandUpdaterJobPtrAlias RenderViewCommandUpdaterJobPtr<RenderView, RenderCommand>
+
+template<class RenderView, class Renderer, class RenderCommand>
+class SyncPreCommandBuilding
+{
+public:
+ explicit SyncPreCommandBuilding(RenderViewInitializerJobPtrAlias renderViewInitializerJob,
+ const std::vector<RenderViewCommandBuilderJobPtrAlias> &renderViewCommandBuilderJobs,
+ Renderer *renderer,
+ FrameGraphNode *leafNode)
+ : m_renderViewInitializer(renderViewInitializerJob)
+ , m_renderViewCommandBuilderJobs(renderViewCommandBuilderJobs)
+ , m_renderer(renderer)
+ , m_leafNode(leafNode)
+ {
+ }
+
+ void operator()()
+ {
+ // Split commands to build among jobs
+
+ // Rebuild RenderCommands for all entities in RV (ignoring filtering)
+ auto *cache = m_renderer->cache();
+ QMutexLocker lock(cache->mutex());
+
+ Q_ASSERT(cache->leafNodeCache.contains(m_leafNode));
+ // The cache leaf should already have been created so we don't need to protect the access
+ const auto &dataCacheForLeaf = cache->leafNodeCache[m_leafNode];
+ RenderView *rv = m_renderViewInitializer->renderView();
+ const auto &entities = !rv->isCompute() ? cache->renderableEntities : cache->computeEntities;
+
+ rv->setMaterialParameterTable(dataCacheForLeaf.materialParameterGatherer);
+
+ // Split among the ideal number of command builders
+ const int jobCount = m_renderViewCommandBuilderJobs.size();
+ const int entityCount = entities.size();
+ const int idealPacketSize = std::min(std::max(10, entityCount / jobCount), entityCount);
+ // Try to split work into an ideal number of workers
+ const int m = findIdealNumberOfWorkers(entityCount, idealPacketSize, jobCount);
+
+ const Entity **entitiesPtr = const_cast<const Entity **>(entities.data());
+ for (int i = 0; i < m; ++i) {
+ const auto &renderViewCommandBuilder = m_renderViewCommandBuilderJobs[i];
+ const int count = (i == m - 1) ? entityCount - (i * idealPacketSize) : idealPacketSize;
+ renderViewCommandBuilder->setEntities(entitiesPtr, i * idealPacketSize, count);
+ }
+ }
+
+private:
+ RenderViewInitializerJobPtrAlias m_renderViewInitializer;
+ std::vector<RenderViewCommandBuilderJobPtrAlias> m_renderViewCommandBuilderJobs;
+ Renderer *m_renderer;
+ FrameGraphNode *m_leafNode;
+};
+
+template<class RenderView, class Renderer, class RenderCommand>
+class SyncRenderViewPostCommandUpdate
+{
+public:
+ explicit SyncRenderViewPostCommandUpdate(const RenderViewInitializerJobPtrAlias &renderViewJob,
+ const std::vector<RenderViewCommandUpdaterJobPtrAlias> &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();
+
+ if (!rv->noDraw()) {
+ // Sort command on RenderView
+ rv->sort();
+ }
+ // Enqueue our fully populated RenderView with the RenderThread
+ m_renderer->enqueueRenderView(rv, m_renderViewJob->submitOrderIndex());
+ }
+
+private:
+ RenderViewInitializerJobPtrAlias m_renderViewJob;
+ std::vector<RenderViewCommandUpdaterJobPtrAlias> m_renderViewCommandUpdaterJobs;
+ Renderer *m_renderer;
+};
+
+template<class RenderView, class Renderer>
+class SyncPreFrustumCulling
+{
+public:
+ explicit SyncPreFrustumCulling(const RenderViewInitializerJobPtrAlias &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:
+ RenderViewInitializerJobPtrAlias m_renderViewJob;
+ FrustumCullingJobPtr m_frustumCullingJob;
+};
+
+template<class RenderView, class Renderer, class RenderCommand>
+class SyncRenderViewPostInitialization
+{
+public:
+ explicit SyncRenderViewPostInitialization(const RenderViewInitializerJobPtrAlias &renderViewJob,
+ const FrustumCullingJobPtr &frustumCullingJob,
+ const FilterLayerEntityJobPtr &filterEntityByLayerJob,
+ const FilterProximityDistanceJobPtr &filterProximityJob,
+ const std::vector<MaterialParameterGathererJobPtr> &materialGathererJobs,
+ const std::vector<RenderViewCommandUpdaterJobPtrAlias> &renderViewCommandUpdaterJobs,
+ const std::vector<RenderViewCommandBuilderJobPtrAlias> &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 : m_materialGathererJobs) {
+ materialGatherer->setRenderPassFilter(const_cast<RenderPassFilter *>(rv->renderPassFilter()));
+ materialGatherer->setTechniqueFilter(const_cast<TechniqueFilter *>(rv->techniqueFilter()));
+ }
+
+ // Command builders and updates
+ for (const auto &renderViewCommandUpdater : m_renderViewCommandUpdaterJobs)
+ renderViewCommandUpdater->setRenderView(rv);
+ for (const auto &renderViewCommandBuilder : m_renderViewCommandBuilderJobs)
+ renderViewCommandBuilder->setRenderView(rv);
+
+ // Set whether frustum culling is enabled or not
+ m_frustumCullingJob->setActive(rv->frustumCulling());
+ }
+
+private:
+ RenderViewInitializerJobPtrAlias m_renderViewJob;
+ FrustumCullingJobPtr m_frustumCullingJob;
+ FilterLayerEntityJobPtr m_filterEntityByLayerJob;
+ FilterProximityDistanceJobPtr m_filterProximityJob;
+ std::vector<MaterialParameterGathererJobPtr> m_materialGathererJobs;
+ std::vector<RenderViewCommandUpdaterJobPtrAlias> m_renderViewCommandUpdaterJobs;
+ std::vector<RenderViewCommandBuilderJobPtrAlias> m_renderViewCommandBuilderJobs;
+};
+
+template<class RenderView, class Renderer, class RenderCommand>
+class SyncRenderViewPreCommandUpdate
+{
+public:
+ explicit SyncRenderViewPreCommandUpdate(const RenderViewInitializerJobPtrAlias &renderViewJob,
+ const FrustumCullingJobPtr &frustumCullingJob,
+ const FilterProximityDistanceJobPtr &filterProximityJob,
+ const std::vector<MaterialParameterGathererJobPtr> &materialGathererJobs,
+ const std::vector<RenderViewCommandUpdaterJobPtrAlias> &renderViewCommandUpdaterJobs,
+ const std::vector<RenderViewCommandBuilderJobPtrAlias> &renderViewCommandBuilderJobs,
+ Renderer *renderer,
+ FrameGraphNode *leafNode,
+ RebuildFlagSet rebuildFlags)
+ : 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_rebuildFlags(rebuildFlags)
+ {}
+
+ 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
+ auto *cache = m_renderer->cache();
+ QMutexLocker lock(cache->mutex());
+ Q_ASSERT(cache->leafNodeCache.contains(m_leafNode));
+
+ // We don't need to protect the cache access as
+ // 1) The cache leaf is created
+ // 2) We are only reading conccurently the cache values that are shared across all RV
+ // 3) Each instance of this job is reading and writing in its own cache leaf so there's
+ // no conflict
+
+ const bool isDraw = !rv->isCompute();
+ auto &cacheForLeaf = cache->leafNodeCache[m_leafNode];
+
+ const bool fullRebuild = m_rebuildFlags.testFlag(RebuildFlag::FullCommandRebuild);
+ const bool layerFilteringRebuild = m_rebuildFlags.testFlag(RebuildFlag::LayerCacheRebuild);
+ const bool lightsCacheRebuild = m_rebuildFlags.testFlag(RebuildFlag::LightCacheRebuild);
+ const bool cameraDirty = cacheForLeaf.viewProjectionMatrix != rv->viewProjectionMatrix();
+ const bool hasProximityFilter = !rv->proximityFilterIds().empty();
+ const bool commandFilteringRequired =
+ fullRebuild ||
+ layerFilteringRebuild ||
+ lightsCacheRebuild ||
+ cameraDirty ||
+ hasProximityFilter;
+
+ // If we have no filteredRenderCommandDataViews then we should have fullRebuild set to true
+ // otherwise something is wrong
+ Q_ASSERT(fullRebuild || cacheForLeaf.filteredRenderCommandDataViews);
+
+ // 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 (fullRebuild) {
+ EntityRenderCommandData<RenderCommand> commandData;
+ // Reduction
+ {
+ int totalCommandCount = 0;
+ for (const RenderViewCommandBuilderJobPtrAlias &renderViewCommandBuilder : qAsConst(m_renderViewCommandBuilderJobs))
+ totalCommandCount += renderViewCommandBuilder->commandData().size();
+ commandData.reserve(totalCommandCount);
+ for (const RenderViewCommandBuilderJobPtrAlias &renderViewCommandBuilder : qAsConst(m_renderViewCommandBuilderJobs))
+ commandData += std::move(renderViewCommandBuilder->commandData());
+ }
+
+ // Store new cache
+ auto dataView = EntityRenderCommandDataViewPtr<RenderCommand>::create();
+ dataView->data = std::move(commandData);
+ // Store the update dataView
+ cacheForLeaf.filteredRenderCommandDataViews = dataView;
+ }
+
+
+ // Should be fairly infrequent
+ if (layerFilteringRebuild || fullRebuild) {
+ // Filter out renderable entities that weren't selected by the layer filters and store that in cache
+ cacheForLeaf.layeredFilteredRenderables = entitiesInSubset(
+ isDraw ? cache->renderableEntities : cache->computeEntities,
+ cacheForLeaf.filterEntitiesByLayer);
+ // Set default value for filteredAndCulledRenderables
+ if (isDraw)
+ cacheForLeaf.filteredAndCulledRenderables = cacheForLeaf.layeredFilteredRenderables;
+ }
+
+ // Should be fairly infrequent
+ if (lightsCacheRebuild) {
+ // Filter out light sources that weren't selected by the
+ // layer filters and store that in cache
+ const std::vector<Entity *> &layeredFilteredEntities = cacheForLeaf.filterEntitiesByLayer;
+ std::vector<LightSource> filteredLightSources = cache->gatheredLights;
+
+ auto it = filteredLightSources.begin();
+
+ while (it != filteredLightSources.end()) {
+ if (!std::binary_search(layeredFilteredEntities.begin(),
+ layeredFilteredEntities.end(),
+ it->entity))
+ it = filteredLightSources.erase(it);
+ else
+ ++it;
+ }
+ cacheForLeaf.layeredFilteredLightSources = std::move(filteredLightSources);
+ }
+
+ // This is likely very frequent
+ if (cameraDirty) {
+ // Record the updated viewProjectionMatrix in the cache to allow check to be performed
+ // next frame
+ cacheForLeaf.viewProjectionMatrix = rv->viewProjectionMatrix();
+ }
+
+ // Filter out frustum culled entity for drawable entities and store in cache
+ // We need to check this regardless of whether the camera has moved since
+ // entities in the scene themselves could have moved
+ if (isDraw && rv->frustumCulling()) {
+ cacheForLeaf.filteredAndCulledRenderables = entitiesInSubset(
+ cacheForLeaf.layeredFilteredRenderables,
+ m_frustumCullingJob->visibleEntities());
+ }
+
+ rv->setMaterialParameterTable(cacheForLeaf.materialParameterGatherer);
+ rv->setEnvironmentLight(cache->environmentLight);
+
+ // Set the light sources, with layer filters applied.
+ rv->setLightSources(cacheForLeaf.layeredFilteredLightSources);
+
+ std::vector<Entity *> renderableEntities = isDraw ? cacheForLeaf.filteredAndCulledRenderables : cacheForLeaf.layeredFilteredRenderables;
+
+ // TO DO: Find a way to do that only if proximity entities has changed
+ if (isDraw) {
+ // Filter out entities which didn't satisfy proximity filtering
+ if (hasProximityFilter)
+ renderableEntities = entitiesInSubset(renderableEntities,
+ m_filterProximityJob->filteredEntities());
+ }
+
+ EntityRenderCommandDataViewPtr<RenderCommand> filteredCommandData = cacheForLeaf.filteredRenderCommandDataViews;
+
+ // Set RenderCommandDataView on RV (will be used later on to sort commands ...)
+ rv->setRenderCommandDataView(filteredCommandData);
+
+ // Filter out Render commands for which the Entity wasn't selected because
+ // of frustum, proximity or layer filtering
+ if (commandFilteringRequired) {
+ const std::vector<const Entity *> &entities = filteredCommandData->data.entities;
+ // Because cacheForLeaf.renderableEntities or computeEntities are sorted
+ // What we get out of EntityRenderCommandData is also sorted by Entity
+ auto eIt = renderableEntities.cbegin();
+ const auto eEnd = renderableEntities.cend();
+ size_t cIt = 0;
+ const size_t cEnd = entities.size();
+
+ std::vector<size_t> filteredCommandIndices;
+ filteredCommandIndices.reserve(renderableEntities.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 && entities[cIt] < targetEntity)
+ ++cIt;
+
+ // Push pointers to command data for all commands that match the
+ // entity
+ while (cIt != cEnd && entities[cIt] == targetEntity) {
+ filteredCommandIndices.push_back(cIt);
+ ++cIt;
+ }
+ ++eIt;
+ }
+
+ // Store result in cache
+ cacheForLeaf.filteredRenderCommandDataViews->indices = std::move(filteredCommandIndices);
+ }
+
+ // Split among the number of command updaters
+ const int jobCount = m_renderViewCommandUpdaterJobs.size();
+ const int commandCount = filteredCommandData->size();
+ const int idealPacketSize = std::min(std::max(10, commandCount), commandCount);
+ const int m = findIdealNumberOfWorkers(commandCount, idealPacketSize, jobCount);
+
+ for (int i = 0; i < m; ++i) {
+ // TO DO: Based on whether we had to update the commands
+ // we should be able to know what needs to be recomputed
+ // -> lights/standard uniforms ... might no have to be set over and over again
+ // if they are identical
+ const RenderViewCommandUpdaterJobPtrAlias &renderViewCommandUpdater = m_renderViewCommandUpdaterJobs.at(i);
+ const size_t count = (i == m - 1) ? commandCount - (i * idealPacketSize) : idealPacketSize;
+ renderViewCommandUpdater->setRenderablesSubView({filteredCommandData, size_t(i * idealPacketSize), count});
+ }
+ }
+ }
+
+private:
+ RenderViewInitializerJobPtrAlias m_renderViewJob;
+ FrustumCullingJobPtr m_frustumCullingJob;
+ FilterProximityDistanceJobPtr m_filterProximityJob;
+ std::vector<MaterialParameterGathererJobPtr> m_materialGathererJobs;
+ std::vector<RenderViewCommandUpdaterJobPtrAlias> m_renderViewCommandUpdaterJobs;
+ std::vector<RenderViewCommandBuilderJobPtrAlias> m_renderViewCommandBuilderJobs;
+ Renderer *m_renderer;
+ FrameGraphNode *m_leafNode;
+ RebuildFlagSet m_rebuildFlags;
+};
+
+template<class Renderer>
+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());
+ Q_ASSERT(m_renderer->cache()->leafNodeCache.contains(m_leafNode));
+ // The cache leaf should already have been created so we don't need to protect the access
+ auto &dataCacheForLeaf = m_renderer->cache()->leafNodeCache[m_leafNode];
+ // Save the filtered by layer subset into the cache
+ dataCacheForLeaf.filterEntitiesByLayer = std::move(m_filterEntityByLayerJob->filteredEntities());
+ }
+
+private:
+ FilterLayerEntityJobPtr m_filterEntityByLayerJob;
+ Renderer *m_renderer;
+ FrameGraphNode *m_leafNode;
+};
+
+template<class Renderer>
+class SyncMaterialParameterGatherer
+{
+public:
+ explicit SyncMaterialParameterGatherer(const std::vector<MaterialParameterGathererJobPtr> &materialParameterGathererJobs,
+ Renderer *renderer,
+ FrameGraphNode *leafNode)
+ : m_materialParameterGathererJobs(materialParameterGathererJobs)
+ , m_renderer(renderer)
+ , m_leafNode(leafNode)
+ {
+ }
+
+ void operator()()
+ {
+ // The cache leaf was created by SyncRenderViewPostInitialization on which we depend
+ // so we don't need to protect the access
+ QMutexLocker lock(m_renderer->cache()->mutex());
+ auto &dataCacheForLeaf = m_renderer->cache()->leafNodeCache[m_leafNode];
+ dataCacheForLeaf.materialParameterGatherer.clear();
+
+ for (const auto &materialGatherer : m_materialParameterGathererJobs) {
+ const MaterialParameterGathererData &source = materialGatherer->materialToPassAndParameter();
+ for (auto it = std::begin(source); it != std::end(source); ++it) {
+ Q_ASSERT(!dataCacheForLeaf.materialParameterGatherer.contains(it.key()));
+ dataCacheForLeaf.materialParameterGatherer.insert(it.key(), it.value());
+ }
+ }
+ }
+
+private:
+ std::vector<MaterialParameterGathererJobPtr> m_materialParameterGathererJobs;
+ Renderer *m_renderer;
+ FrameGraphNode *m_leafNode;
+};
+
+} // Render
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // RENDERSYNCJOBS_H
diff --git a/src/render/jobs/renderviewjobutils.cpp b/src/render/jobs/renderviewjobutils.cpp
index 369ad2f66..11c7cbd98 100644
--- a/src/render/jobs/renderviewjobutils.cpp
+++ b/src/render/jobs/renderviewjobutils.cpp
@@ -225,6 +225,24 @@ bool ParameterInfo::operator<(const int otherNameId) const Q_DECL_NOEXCEPT
return nameId < otherNameId;
}
+int findIdealNumberOfWorkers(int elementCount, int packetSize, int maxJobCount)
+{
+ if (elementCount == 0 || packetSize == 0)
+ return 0;
+ return std::min(std::max(elementCount / packetSize, 1), maxJobCount);
+}
+
+std::vector<Entity *> entitiesInSubset(const std::vector<Entity *> &entities, const std::vector<Entity *> &subset)
+{
+ std::vector<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;
+}
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/src/render/jobs/renderviewjobutils_p.h b/src/render/jobs/renderviewjobutils_p.h
index 0ef7ab00d..db46a114a 100644
--- a/src/render/jobs/renderviewjobutils_p.h
+++ b/src/render/jobs/renderviewjobutils_p.h
@@ -143,6 +143,12 @@ Q_3DRENDERSHARED_PRIVATE_EXPORT void addStatesToRenderStateSet(RenderStateSet *s
const QList<Qt3DCore::QNodeId> stateIds,
RenderStateManager *manager);
+Q_3DRENDERSHARED_PRIVATE_EXPORT int findIdealNumberOfWorkers(int elementCount, int packetSize = 100, int maxJobCount = 1)
+;
+
+Q_3DRENDERSHARED_PRIVATE_EXPORT std::vector<Entity *> entitiesInSubset(const std::vector<Entity *> &entities,
+const std::vector<Entity *> &subset);
+
} // namespace Render
} // namespace Qt3DRender
diff --git a/tests/auto/render/opengl/renderviewbuilder/tst_renderviewbuilder.cpp b/tests/auto/render/opengl/renderviewbuilder/tst_renderviewbuilder.cpp
index 5c378c6d1..6627e3c08 100644
--- a/tests/auto/render/opengl/renderviewbuilder/tst_renderviewbuilder.cpp
+++ b/tests/auto/render/opengl/renderviewbuilder/tst_renderviewbuilder.cpp
@@ -54,6 +54,7 @@
#include <Qt3DRender/private/managers_p.h>
#include <Qt3DRender/private/filterentitybycomponentjob_p.h>
#include <Qt3DRender/private/qrenderaspect_p.h>
+#include <Qt3DRender/private/renderviewjobutils_p.h>
QT_BEGIN_NAMESPACE
@@ -675,7 +676,7 @@ private Q_SLOTS:
std::sort(renderableEntity.begin(), renderableEntity.end());
// WHEN
- renderableEntity = Qt3DRender::Render::OpenGL::RenderViewBuilder::entitiesInSubset(renderableEntity, filteredEntity);
+ renderableEntity = Qt3DRender::Render::entitiesInSubset(renderableEntity, filteredEntity);
// THEN
QCOMPARE(renderableEntity.size(), 100);