diff options
Diffstat (limited to 'src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp')
-rw-r--r-- | src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp | 466 |
1 files changed, 1 insertions, 465 deletions
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 |