diff options
Diffstat (limited to 'src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp')
-rw-r--r-- | src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp | 137 |
1 files changed, 81 insertions, 56 deletions
diff --git a/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp b/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp index 8ed32ff10..b0ac76199 100644 --- a/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp +++ b/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp @@ -49,18 +49,13 @@ namespace Qt3DRender { namespace Render { namespace OpenGL { -// 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) +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), RenderViewBuilder::optimalJobCount()); + return std::min(std::max(elementCount / packetSize, 1), maxJobCount); } @@ -93,9 +88,10 @@ public: lock.unlock(); // Split among the ideal number of command builders - const int idealPacketSize = std::min(std::max(100, entities.size() / RenderViewBuilder::optimalJobCount()), entities.size()); + const int jobCount = m_renderViewCommandBuilderJobs.size(); + const int idealPacketSize = std::min(std::max(10, entities.size() / jobCount), entities.size()); // Try to split work into an ideal number of workers - const int m = findIdealNumberOfWorkers(entities.size(), idealPacketSize); + const int m = findIdealNumberOfWorkers(entities.size(), idealPacketSize, jobCount); for (int i = 0; i < m; ++i) { const RenderViewCommandBuilderJobPtr renderViewCommandBuilder = m_renderViewCommandBuilderJobs.at(i); @@ -352,9 +348,9 @@ public: } // 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); + const int jobCount = m_renderViewCommandUpdaterJobs.size(); + const int idealPacketSize = std::min(std::max(10, filteredCommandData->size() / jobCount), filteredCommandData->size()); + const int m = findIdealNumberOfWorkers(filteredCommandData->size(), idealPacketSize, jobCount); for (int i = 0; i < m; ++i) { const RenderViewCommandUpdaterJobPtr renderViewCommandBuilder = m_renderViewCommandUpdaterJobs.at(i); @@ -474,6 +470,10 @@ RenderViewBuilder::RenderViewBuilder(Render::FrameGraphNode *leafNode, int rende , m_syncFilterEntityByLayerJob() , m_filterProximityJob(Render::FilterProximityDistanceJobPtr::create()) { + // 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 + m_optimalParallelJobCount = QThread::idealThreadCount(); } RenderViewInitializerJobPtr RenderViewBuilder::renderViewJob() const @@ -558,17 +558,16 @@ void RenderViewBuilder::prepareJobs() m_frustumCullingJob->setRoot(m_renderer->sceneRoot()); if (m_renderCommandCacheNeedsToBeRebuilt) { - - m_renderViewCommandBuilderJobs.reserve(RenderViewBuilder::m_optimalParallelJobCount); - for (auto i = 0; i < RenderViewBuilder::m_optimalParallelJobCount; ++i) { + m_renderViewCommandBuilderJobs.reserve(m_optimalParallelJobCount); + for (auto i = 0; i < m_optimalParallelJobCount; ++i) { auto renderViewCommandBuilder = Render::OpenGL::RenderViewCommandBuilderJobPtr::create(); m_renderViewCommandBuilderJobs.push_back(renderViewCommandBuilder); } m_syncRenderViewPreCommandBuildingJob = CreateSynchronizerJobPtr(SyncPreCommandBuilding(m_renderViewJob, - m_renderViewCommandBuilderJobs, - m_renderer, - m_leafNode), - JobTypes::SyncRenderViewPreCommandBuilding); + m_renderViewCommandBuilderJobs, + m_renderer, + m_leafNode), + JobTypes::SyncRenderViewPreCommandBuilding); } m_renderViewJob->setRenderer(m_renderer); @@ -577,8 +576,8 @@ void RenderViewBuilder::prepareJobs() // 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) { + m_renderViewCommandUpdaterJobs.reserve(m_optimalParallelJobCount); + for (auto i = 0; i < m_optimalParallelJobCount; ++i) { auto renderViewCommandUpdater = Render::OpenGL::RenderViewCommandUpdaterJobPtr::create(); renderViewCommandUpdater->setRenderer(m_renderer); m_renderViewCommandUpdaterJobs.push_back(renderViewCommandUpdater); @@ -587,22 +586,23 @@ void RenderViewBuilder::prepareJobs() if (m_materialGathererCacheNeedsToBeRebuilt) { // Since Material gathering is an heavy task, we split it const QVector<HMaterial> materialHandles = m_renderer->nodeManagers()->materialManager()->activeHandles(); - const int elementsPerJob = materialHandles.size() / RenderViewBuilder::m_optimalParallelJobCount; - const int lastRemaingElements = materialHandles.size() % RenderViewBuilder::m_optimalParallelJobCount; - m_materialGathererJobs.reserve(RenderViewBuilder::m_optimalParallelJobCount); - for (auto i = 0; i < RenderViewBuilder::m_optimalParallelJobCount; ++i) { - auto materialGatherer = MaterialParameterGathererJobPtr::create(); - materialGatherer->setNodeManagers(m_renderer->nodeManagers()); - if (i == RenderViewBuilder::m_optimalParallelJobCount - 1) - materialGatherer->setHandles(materialHandles.mid(i * elementsPerJob, elementsPerJob + lastRemaingElements)); - else - materialGatherer->setHandles(materialHandles.mid(i * elementsPerJob, elementsPerJob)); - m_materialGathererJobs.push_back(materialGatherer); + if (materialHandles.count()) { + const int elementsPerJob = qMax(materialHandles.size() / m_optimalParallelJobCount, 1); + m_materialGathererJobs.reserve(m_optimalParallelJobCount); + int elementCount = 0; + while (elementCount < materialHandles.size()) { + auto materialGatherer = MaterialParameterGathererJobPtr::create(); + materialGatherer->setNodeManagers(m_renderer->nodeManagers()); + materialGatherer->setHandles(materialHandles.mid(elementCount, elementsPerJob)); + m_materialGathererJobs.push_back(materialGatherer); + + elementCount += elementsPerJob; + } } m_syncMaterialGathererJob = CreateSynchronizerJobPtr(SyncMaterialParameterGatherer(m_materialGathererJobs, - m_renderer, - m_leafNode), - JobTypes::SyncMaterialGatherer); + m_renderer, + m_leafNode), + JobTypes::SyncMaterialGatherer); } if (m_layerCacheNeedsToBeRebuilt) { @@ -615,29 +615,29 @@ void RenderViewBuilder::prepareJobs() } m_syncRenderViewPreCommandUpdateJob = CreateSynchronizerJobPtr(SyncRenderViewPreCommandUpdate(m_renderViewJob, - m_frustumCullingJob, - m_filterProximityJob, - m_materialGathererJobs, - m_renderViewCommandUpdaterJobs, - m_renderViewCommandBuilderJobs, - m_renderer, - m_leafNode, - m_renderCommandCacheNeedsToBeRebuilt), - JobTypes::SyncRenderViewPreCommandUpdate); + m_frustumCullingJob, + m_filterProximityJob, + m_materialGathererJobs, + m_renderViewCommandUpdaterJobs, + m_renderViewCommandBuilderJobs, + m_renderer, + m_leafNode, + m_renderCommandCacheNeedsToBeRebuilt), + JobTypes::SyncRenderViewPreCommandUpdate); m_syncRenderViewPostCommandUpdateJob = CreateSynchronizerJobPtr(SyncRenderViewPostCommandUpdate(m_renderViewJob, - m_renderViewCommandUpdaterJobs, - m_renderer), - JobTypes::SyncRenderViewPostCommandUpdate); + m_renderViewCommandUpdaterJobs, + m_renderer), + JobTypes::SyncRenderViewPostCommandUpdate); m_syncRenderViewPostInitializationJob = CreateSynchronizerJobPtr(SyncRenderViewPostInitialization(m_renderViewJob, - m_frustumCullingJob, - m_filterEntityByLayerJob, - m_filterProximityJob, - m_materialGathererJobs, - m_renderViewCommandUpdaterJobs, - m_renderViewCommandBuilderJobs), - JobTypes::SyncRenderViewInitialization); + m_frustumCullingJob, + m_filterEntityByLayerJob, + m_filterProximityJob, + m_materialGathererJobs, + m_renderViewCommandUpdaterJobs, + m_renderViewCommandBuilderJobs), + JobTypes::SyncRenderViewInitialization); } QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const @@ -793,9 +793,34 @@ bool RenderViewBuilder::renderCommandCacheNeedsToBeRebuilt() const return m_renderCommandCacheNeedsToBeRebuilt; } -int RenderViewBuilder::optimalJobCount() +int RenderViewBuilder::defaultJobCount() +{ + static int jobCount = 0; + if (jobCount) + return jobCount; + + const QByteArray maxThreadCount = qgetenv("QT3D_MAX_THREAD_COUNT"); + if (!maxThreadCount.isEmpty()) { + bool conversionOK = false; + const int maxThreadCountValue = maxThreadCount.toInt(&conversionOK); + if (conversionOK) { + jobCount = maxThreadCountValue; + return jobCount; + } + } + + jobCount = QThread::idealThreadCount(); + return jobCount; +} + +int RenderViewBuilder::optimalJobCount() const +{ + return m_optimalParallelJobCount; +} + +void RenderViewBuilder::setOptimalJobCount(int v) { - return RenderViewBuilder::m_optimalParallelJobCount; + m_optimalParallelJobCount = v; } QVector<Entity *> RenderViewBuilder::entitiesInSubset(const QVector<Entity *> &entities, const QVector<Entity *> &subset) |