summaryrefslogtreecommitdiffstats
path: root/src/render/renderers/opengl/renderer/renderer.cpp
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2019-09-27 14:31:21 +0200
committerPaul Lemire <paul.lemire@kdab.com>2019-10-21 13:35:38 +0200
commit7eb01e9532f080bef539808c0eb5e7c65cf34048 (patch)
tree5aadb0e7fcfb80a671641beb972345c4762f763a /src/render/renderers/opengl/renderer/renderer.cpp
parent7d8fd90a1d5e59b21b29da3e7fd0e593e3d94620 (diff)
Split RenderCommand generation and uniform update
In most cases, we can generate the RenderCommands once and reuse them in subsequent frames only updating the uniforms. We still have to copy the RenderCommands as the renderer renders while we start preparing the next frame. This is still faster than regenerating them entirely. Regenerating the entire commands will happen only when FrameGraph or Scene structure changes. That should rarely be happening on a per frame basis. Next step could be to look at how to only update commands for Entity with Parameters that have changed. Change-Id: I202870850a46fcd3946f81bffddb7027d192f374 Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
Diffstat (limited to 'src/render/renderers/opengl/renderer/renderer.cpp')
-rw-r--r--src/render/renderers/opengl/renderer/renderer.cpp103
1 files changed, 54 insertions, 49 deletions
diff --git a/src/render/renderers/opengl/renderer/renderer.cpp b/src/render/renderers/opengl/renderer/renderer.cpp
index 121a6aa8f..f17e66108 100644
--- a/src/render/renderers/opengl/renderer/renderer.cpp
+++ b/src/render/renderers/opengl/renderer/renderer.cpp
@@ -432,6 +432,9 @@ void Renderer::initialize()
m_waitForInitializationToBeCompleted.release(1);
// Allow the aspect manager to proceed
m_vsyncFrameAdvanceService->proceedToNextFrame();
+
+ // Force initial refresh
+ markDirty(AllDirty, nullptr);
}
/*!
@@ -860,13 +863,13 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView
QHash<HVao, bool> updatedTable;
for (RenderView *rv: renderViews) {
- const QVector<RenderCommand *> commands = rv->commands();
- for (RenderCommand *command : commands) {
+ QVector<RenderCommand> &commands = rv->commands();
+ for (RenderCommand &command : commands) {
// Update/Create VAO
- if (command->m_type == RenderCommand::Draw) {
- Geometry *rGeometry = m_nodesManager->data<Geometry, GeometryManager>(command->m_geometry);
- GeometryRenderer *rGeometryRenderer = m_nodesManager->data<GeometryRenderer, GeometryRendererManager>(command->m_geometryRenderer);
- Shader *shader = m_nodesManager->data<Shader, ShaderManager>(command->m_shader);
+ if (command.m_type == RenderCommand::Draw) {
+ Geometry *rGeometry = m_nodesManager->data<Geometry, GeometryManager>(command.m_geometry);
+ GeometryRenderer *rGeometryRenderer = m_nodesManager->data<GeometryRenderer, GeometryRendererManager>(command.m_geometryRenderer);
+ Shader *shader = m_nodesManager->data<Shader, ShaderManager>(command.m_shader);
// We should never have inserted a command for which these are null
// in the first place
@@ -879,15 +882,15 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView
// Create VAO or return already created instance associated with command shader/geometry
// (VAO is emulated if not supported)
- createOrUpdateVAO(command, &vaoHandle, &vao);
- command->m_vao = vaoHandle;
+ createOrUpdateVAO(&command, &vaoHandle, &vao);
+ command.m_vao = vaoHandle;
// Avoids redoing the same thing for the same VAO
if (!updatedTable.contains(vaoHandle)) {
updatedTable.insert(vaoHandle, true);
// Do we have any attributes that are dirty ?
- const bool requiresPartialVAOUpdate = requiresVAOAttributeUpdate(rGeometry, command);
+ const bool requiresPartialVAOUpdate = requiresVAOAttributeUpdate(rGeometry, &command);
// If true, we need to reupload all attributes to set the VAO
// Otherwise only dirty attributes will be updates
@@ -898,7 +901,7 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView
if (rGeometry->isDirty())
m_dirtyGeometry.push_back(rGeometry);
- if (!command->m_activeAttributes.isEmpty() && (requiresFullVAOUpdate || requiresPartialVAOUpdate)) {
+ if (!command.m_activeAttributes.isEmpty() && (requiresFullVAOUpdate || requiresPartialVAOUpdate)) {
Profiling::GLTimeRecorder recorder(Profiling::VAOUpload);
// Activate shader
m_submissionContext->activateShader(shader->dna());
@@ -906,7 +909,7 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView
vao->bind();
// Update or set Attributes and Buffers for the given rGeometry and Command
// Note: this fills m_dirtyAttributes as well
- if (updateVAOWithAttributes(rGeometry, command, shader, requiresFullVAOUpdate))
+ if (updateVAOWithAttributes(rGeometry, &command, shader, requiresFullVAOUpdate))
vao->setSpecified(true);
}
}
@@ -918,11 +921,11 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView
rGeometryRenderer->unsetDirty();
// Prepare the ShaderParameterPack based on the active uniforms of the shader
- shader->prepareUniforms(command->m_parameterPack);
+ shader->prepareUniforms(command.m_parameterPack);
{ // Scoped to show extent
- command->m_isValid = !command->m_activeAttributes.empty();
- if (!command->m_isValid)
+ command.m_isValid = !command.m_activeAttributes.empty();
+ if (!command.m_isValid)
continue;
// Update the draw command with what's going to be needed for the drawing
@@ -942,7 +945,7 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView
indirectAttribute = attribute;
break;
case QAttribute::VertexAttribute: {
- if (command->m_activeAttributes.contains(attribute->nameId()))
+ if (command.m_activeAttributes.contains(attribute->nameId()))
estimatedCount = qMax(attribute->count(), estimatedCount);
break;
}
@@ -952,20 +955,20 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView
}
}
- command->m_drawIndexed = (indexAttribute != nullptr);
- command->m_drawIndirect = (indirectAttribute != nullptr);
+ command.m_drawIndexed = (indexAttribute != nullptr);
+ command.m_drawIndirect = (indirectAttribute != nullptr);
// Update the draw command with all the information required for the drawing
- if (command->m_drawIndexed) {
- command->m_indexAttributeDataType = GraphicsContext::glDataTypeFromAttributeDataType(indexAttribute->vertexBaseType());
- command->m_indexAttributeByteOffset = indexAttribute->byteOffset() + rGeometryRenderer->indexBufferByteOffset();
+ if (command.m_drawIndexed) {
+ command.m_indexAttributeDataType = GraphicsContext::glDataTypeFromAttributeDataType(indexAttribute->vertexBaseType());
+ command.m_indexAttributeByteOffset = indexAttribute->byteOffset() + rGeometryRenderer->indexBufferByteOffset();
}
// Note: we only care about the primitiveCount when using direct draw calls
// For indirect draw calls it is assumed the buffer was properly set already
- if (command->m_drawIndirect) {
- command->m_indirectAttributeByteOffset = indirectAttribute->byteOffset();
- command->m_indirectDrawBuffer = m_nodesManager->bufferManager()->lookupHandle(indirectAttribute->bufferId());
+ if (command.m_drawIndirect) {
+ command.m_indirectAttributeByteOffset = indirectAttribute->byteOffset();
+ command.m_indirectDrawBuffer = m_nodesManager->bufferManager()->lookupHandle(indirectAttribute->bufferId());
} else {
// Use the count specified by the GeometryRender
// If not specify use the indexAttribute count if present
@@ -978,22 +981,22 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView
}
}
- command->m_primitiveCount = primitiveCount;
- command->m_primitiveType = rGeometryRenderer->primitiveType();
- command->m_primitiveRestartEnabled = rGeometryRenderer->primitiveRestartEnabled();
- command->m_restartIndexValue = rGeometryRenderer->restartIndexValue();
- command->m_firstInstance = rGeometryRenderer->firstInstance();
- command->m_instanceCount = rGeometryRenderer->instanceCount();
- command->m_firstVertex = rGeometryRenderer->firstVertex();
- command->m_indexOffset = rGeometryRenderer->indexOffset();
- command->m_verticesPerPatch = rGeometryRenderer->verticesPerPatch();
+ command.m_primitiveCount = primitiveCount;
+ command.m_primitiveType = rGeometryRenderer->primitiveType();
+ command.m_primitiveRestartEnabled = rGeometryRenderer->primitiveRestartEnabled();
+ command.m_restartIndexValue = rGeometryRenderer->restartIndexValue();
+ command.m_firstInstance = rGeometryRenderer->firstInstance();
+ command.m_instanceCount = rGeometryRenderer->instanceCount();
+ command.m_firstVertex = rGeometryRenderer->firstVertex();
+ command.m_indexOffset = rGeometryRenderer->indexOffset();
+ command.m_verticesPerPatch = rGeometryRenderer->verticesPerPatch();
} // scope
- } else if (command->m_type == RenderCommand::Compute) {
- Shader *shader = m_nodesManager->data<Shader, ShaderManager>(command->m_shader);
+ } else if (command.m_type == RenderCommand::Compute) {
+ Shader *shader = m_nodesManager->data<Shader, ShaderManager>(command.m_shader);
Q_ASSERT(shader);
// Prepare the ShaderParameterPack based on the active uniforms of the shader
- shader->prepareUniforms(command->m_parameterPack);
+ shader->prepareUniforms(command.m_parameterPack);
}
}
}
@@ -1834,6 +1837,7 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
const bool computeableDirty = dirtyBitsForFrame & AbstractRenderer::ComputeDirty;
const bool renderableDirty = dirtyBitsForFrame & AbstractRenderer::GeometryDirty;
const bool materialCacheNeedsToBeRebuilt = shadersDirty || materialDirty || frameGraphDirty;
+ const bool renderCommandsDirty = materialCacheNeedsToBeRebuilt || renderableDirty || computeableDirty;
// Rebuild Entity Layers list if layers are dirty
if (layersDirty)
@@ -1873,6 +1877,7 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
builder.setLightGathererCacheNeedsToBeRebuilt(lightsDirty);
builder.setMaterialGathererCacheNeedsToBeRebuilt(materialCacheNeedsToBeRebuilt);
builder.setLightGathererCacheNeedsToBeRebuilt(lightsDirty);
+ builder.setRenderCommandCacheNeedsToBeRebuilt(renderCommandsDirty);
builder.prepareJobs();
renderBinJobs.append(builder.buildJobHierachy());
@@ -2075,7 +2080,7 @@ bool Renderer::executeCommandsSubmission(const RenderView *rv)
bool allCommandsIssued = true;
// Render drawing commands
- const QVector<RenderCommand *> commands = rv->commands();
+ QVector<RenderCommand> commands = rv->commands();
// Use the graphicscontext to submit the commands to the underlying
// graphics API (OpenGL)
@@ -2084,18 +2089,18 @@ bool Renderer::executeCommandsSubmission(const RenderView *rv)
RenderStateSet *globalState = m_submissionContext->currentStateSet();
OpenGLVertexArrayObject *vao = nullptr;
- for (RenderCommand *command : qAsConst(commands)) {
+ for (RenderCommand &command : commands) {
- if (command->m_type == RenderCommand::Compute) { // Compute Call
- performCompute(rv, command);
+ if (command.m_type == RenderCommand::Compute) { // Compute Call
+ performCompute(rv, &command);
} else { // Draw Command
// Check if we have a valid command that can be drawn
- if (!command->m_isValid) {
+ if (!command.m_isValid) {
allCommandsIssued = false;
continue;
}
- vao = m_nodesManager->vaoManager()->data(command->m_vao);
+ vao = m_nodesManager->vaoManager()->data(command.m_vao);
// something may have went wrong when initializing the VAO
if (!vao->isSpecified()) {
@@ -2106,7 +2111,7 @@ bool Renderer::executeCommandsSubmission(const RenderView *rv)
{
Profiling::GLTimeRecorder recorder(Profiling::ShaderUpdate);
//// We activate the shader here
- if (!m_submissionContext->activateShader(command->m_shaderDna)) {
+ if (!m_submissionContext->activateShader(command.m_shaderDna)) {
allCommandsIssued = false;
continue;
}
@@ -2121,7 +2126,7 @@ bool Renderer::executeCommandsSubmission(const RenderView *rv)
{
Profiling::GLTimeRecorder recorder(Profiling::UniformUpdate);
//// Update program uniforms
- if (!m_submissionContext->setParameters(command->m_parameterPack)) {
+ if (!m_submissionContext->setParameters(command.m_parameterPack)) {
allCommandsIssued = false;
// If we have failed to set uniform (e.g unable to bind a texture)
// we won't perform the draw call which could show invalid content
@@ -2132,7 +2137,7 @@ bool Renderer::executeCommandsSubmission(const RenderView *rv)
//// OpenGL State
// TO DO: Make states not dependendent on their backend node for this step
// Set state
- RenderStateSet *localState = command->m_stateSet;
+ RenderStateSet *localState = command.m_stateSet.data();
{
@@ -2140,8 +2145,8 @@ bool Renderer::executeCommandsSubmission(const RenderView *rv)
// Merge the RenderCommand state with the globalState of the RenderView
// Or restore the globalState if no stateSet for the RenderCommand
if (localState != nullptr) {
- command->m_stateSet->merge(globalState);
- m_submissionContext->setCurrentStateSet(command->m_stateSet);
+ command.m_stateSet->merge(globalState);
+ m_submissionContext->setCurrentStateSet(localState);
} else {
m_submissionContext->setCurrentStateSet(globalState);
}
@@ -2151,7 +2156,7 @@ bool Renderer::executeCommandsSubmission(const RenderView *rv)
// at that point
//// Draw Calls
- performDraw(command);
+ performDraw(&command);
}
} // end of RenderCommands loop
@@ -2167,7 +2172,7 @@ bool Renderer::executeCommandsSubmission(const RenderView *rv)
}
bool Renderer::updateVAOWithAttributes(Geometry *geometry,
- RenderCommand *command,
+ const RenderCommand *command,
Shader *shader,
bool forceUpdate)
{
@@ -2227,7 +2232,7 @@ bool Renderer::updateVAOWithAttributes(Geometry *geometry,
}
bool Renderer::requiresVAOAttributeUpdate(Geometry *geometry,
- RenderCommand *command) const
+ const RenderCommand *command) const
{
const auto attributeIds = geometry->attributes();