summaryrefslogtreecommitdiffstats
path: root/src/render/renderers/opengl/renderer/renderviewbuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/render/renderers/opengl/renderer/renderviewbuilder.cpp')
-rw-r--r--src/render/renderers/opengl/renderer/renderviewbuilder.cpp74
1 files changed, 40 insertions, 34 deletions
diff --git a/src/render/renderers/opengl/renderer/renderviewbuilder.cpp b/src/render/renderers/opengl/renderer/renderviewbuilder.cpp
index 96fa55c47..9f7589ecc 100644
--- a/src/render/renderers/opengl/renderer/renderviewbuilder.cpp
+++ b/src/render/renderers/opengl/renderer/renderviewbuilder.cpp
@@ -50,10 +50,18 @@ namespace Render {
// 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 = std::max(std::min(4, QThread::idealThreadCount()), 2);
+const int RenderViewBuilder::m_optimalParallelJobCount = QThread::idealThreadCount();
namespace {
+int findIdealNumberOfWorkers(int elementCount, int packetSize = 100)
+{
+ if (elementCount == 0 || packetSize == 0)
+ return 0;
+ return std::min(std::max(elementCount / packetSize, 1), RenderViewBuilder::optimalJobCount());
+}
+
+
class SyncPreCommandBuilding
{
public:
@@ -82,16 +90,16 @@ public:
lock.unlock();
- // Split among the number of command builders
- int i = 0;
- const int m = RenderViewBuilder::optimalJobCount() - 1;
- const int packetSize = entities.size() / RenderViewBuilder::optimalJobCount();
- while (i < m) {
+ // Split among the ideal number of command builders
+ const int idealPacketSize = std::min(std::max(100, entities.size() / RenderViewBuilder::optimalJobCount()), entities.size());
+ // Try to split work into an ideal number of workers
+ const int m = findIdealNumberOfWorkers(entities.size(), idealPacketSize);
+
+ for (int i = 0; i < m; ++i) {
const RenderViewCommandBuilderJobPtr renderViewCommandBuilder = m_renderViewCommandBuilderJobs.at(i);
- renderViewCommandBuilder->setEntities(entities.mid(i * packetSize, packetSize));
- ++i;
+ const int count = (i == m - 1) ? entities.size() - (i * idealPacketSize) : idealPacketSize;
+ renderViewCommandBuilder->setEntities(entities, i * idealPacketSize, count);
}
- m_renderViewCommandBuilderJobs.at(i)->setEntities(entities.mid(i * packetSize, packetSize + entities.size() % (m + 1)));
}
private:
@@ -117,22 +125,20 @@ public:
// Append all the commands and sort them
RenderView *rv = m_renderViewJob->renderView();
- int totalCommandCount = 0;
- for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewCommandUpdaterJobs))
- totalCommandCount += renderViewCommandBuilder->commands().size();
+ const EntityRenderCommandData *commandData = m_renderViewCommandUpdaterJobs.first()->renderables();
- QVector<RenderCommand> commands;
- commands.reserve(totalCommandCount);
+ if (commandData != nullptr) {
+ const QVector<RenderCommand> commands = std::move(commandData->commands);
- // Reduction
- for (const auto &renderViewCommandBuilder : qAsConst(m_renderViewCommandUpdaterJobs))
- commands += std::move(renderViewCommandBuilder->commands());
+ // TO DO: Cache the EntityRenderCommandData so that it can be reused if nothing in the scene has changed
+ delete commandData;
- rv->setCommands(commands);
+ rv->setCommands(commands);
- // TO DO: Find way to store commands once or at least only when required
- // Sort the commands
- rv->sort();
+ // TO DO: Find way to store commands once or at least only when required
+ // Sort the commands
+ rv->sort();
+ }
// Enqueue our fully populated RenderView with the RenderThread
m_renderer->enqueueRenderView(rv, m_renderViewJob->submitOrderIndex());
@@ -279,12 +285,12 @@ public:
commandData += std::move(renderViewCommandBuilder->commandData());
}
+
// Store new cache
RendererCache::LeafNodeData &writableCacheForLeaf = cache->leafNodeCache[m_leafNode];
writableCacheForLeaf.renderCommandData = std::move(commandData);
}
const EntityRenderCommandData commandData = dataCacheForLeaf.renderCommandData;
-
const QVector<Entity *> filteredEntities = dataCacheForLeaf.filterEntitiesByLayer;
QVector<Entity *> renderableEntities = isDraw ? cache->renderableEntities : cache->computeEntities;
QVector<LightSource> lightSources = cache->gatheredLights;
@@ -316,8 +322,8 @@ public:
// Filter out Render commands for which the Entity wasn't selected because
// of frustum, proximity or layer filtering
- EntityRenderCommandData filteredCommandData;
- filteredCommandData.reserve(renderableEntities.size());
+ EntityRenderCommandData *filteredCommandData = new EntityRenderCommandData();
+ filteredCommandData->reserve(renderableEntities.size());
// Because dataCacheForLeaf.renderableEntities or computeEntities are sorted
// What we get out of EntityRenderCommandData is also sorted by Entity
auto eIt = std::cbegin(renderableEntities);
@@ -335,24 +341,24 @@ public:
// Push pointers to command data for all commands that match the
// entity
while (cIt != cEnd && commandData.entities.at(cIt) == targetEntity) {
- filteredCommandData.push_back(commandData.entities.at(cIt),
- commandData.commands.at(cIt),
- commandData.passesData.at(cIt));
+ filteredCommandData->push_back(commandData.entities.at(cIt),
+ commandData.commands.at(cIt),
+ commandData.passesData.at(cIt));
++cIt;
}
++eIt;
}
// Split among the number of command builders
- int i = 0;
- const int m = RenderViewBuilder::optimalJobCount() - 1;
- const int packetSize = filteredCommandData.size() / RenderViewBuilder::optimalJobCount();
- while (i < m) {
+ // The idealPacketSize is at least 100 entities per worker
+ const int idealPacketSize = std::min(std::max(100, filteredCommandData->size() / RenderViewBuilder::optimalJobCount()), filteredCommandData->size());
+ const int m = findIdealNumberOfWorkers(filteredCommandData->size(), idealPacketSize);
+
+ for (int i = 0; i < m; ++i) {
const RenderViewCommandUpdaterJobPtr renderViewCommandBuilder = m_renderViewCommandUpdaterJobs.at(i);
- renderViewCommandBuilder->setRenderables(filteredCommandData.mid(i * packetSize, packetSize));
- ++i;
+ const int count = (i == m - 1) ? filteredCommandData->size() - (i * idealPacketSize) : idealPacketSize;
+ renderViewCommandBuilder->setRenderables(filteredCommandData, i * idealPacketSize, count);
}
- m_renderViewCommandUpdaterJobs.at(i)->setRenderables(filteredCommandData.mid(i * packetSize, packetSize + filteredCommandData.size() % (m + 1)));
}
}