diff options
author | Paul Lemire <paul.lemire@kdab.com> | 2016-10-17 17:40:23 +0200 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2017-01-24 08:40:31 +0000 |
commit | e3ecccb973cdfcf8452da71e20f42d5ffdf551e6 (patch) | |
tree | d5a9728cfc12f1773f078855db1201f54eed0c5b | |
parent | aa7ba870f3597088fc447f36e3024220ac03680f (diff) |
Renderer: now handle indirect draw calls
Change-Id: I8b109425a6a8d49cb7008f9dbed3b6c8cb913235
Reviewed-by: Kevin Ottens <kevin.ottens@kdab.com>
-rw-r--r-- | src/render/backend/rendercommand.cpp | 2 | ||||
-rw-r--r-- | src/render/backend/rendercommand_p.h | 4 | ||||
-rw-r--r-- | src/render/backend/renderer.cpp | 150 | ||||
-rw-r--r-- | src/render/graphicshelpers/graphicscontext.cpp | 2 |
4 files changed, 136 insertions, 22 deletions
diff --git a/src/render/backend/rendercommand.cpp b/src/render/backend/rendercommand.cpp index eabb2a2d4..044ef035c 100644 --- a/src/render/backend/rendercommand.cpp +++ b/src/render/backend/rendercommand.cpp @@ -60,7 +60,9 @@ RenderCommand::RenderCommand() , m_indexOffset(0) , m_indexAttributeByteOffset(0) , m_indexAttributeDataType(GL_UNSIGNED_SHORT) + , m_indirectAttributeByteOffset(0) , m_drawIndexed(false) + , m_drawIndirect(false) , m_primitiveRestartEnabled(false) , m_isValid(false) { diff --git a/src/render/backend/rendercommand_p.h b/src/render/backend/rendercommand_p.h index 012cdbe9a..4b2966fc6 100644 --- a/src/render/backend/rendercommand_p.h +++ b/src/render/backend/rendercommand_p.h @@ -84,6 +84,8 @@ public: HGeometry m_geometry; HGeometryRenderer m_geometryRenderer; + HBuffer m_indirectDrawBuffer; // Reference to indirect draw buffer (valid only m_drawIndirect == true) + // A QAttribute pack might be interesting // This is a temporary fix in the meantime, to remove the hacked methods in Technique QVector<int> m_attributes; @@ -118,7 +120,9 @@ public: int m_indexOffset; uint m_indexAttributeByteOffset; GLint m_indexAttributeDataType; + uint m_indirectAttributeByteOffset; bool m_drawIndexed; + bool m_drawIndirect; bool m_primitiveRestartEnabled; bool m_isValid; }; diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index 08ee7f428..47759ad4e 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -794,6 +794,75 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView // Prepare the ShaderParameterPack based on the active uniforms of the shader shader->prepareUniforms(command->m_parameterPack); + // TO DO: The step below could be performed by the RenderCommand builder job + { // Scoped to show extent + command->m_isValid = !command->m_attributes.empty(); + if (!command->m_isValid) + continue; + + // Update the draw command with what's going to be needed for the drawing + uint primitiveCount = rGeometryRenderer->vertexCount(); + uint estimatedCount = 0; + Attribute *indexAttribute = nullptr; + Attribute *indirectAttribute = nullptr; + + const QVector<Qt3DCore::QNodeId> attributeIds = rGeometry->attributes(); + for (Qt3DCore::QNodeId attributeId : attributeIds) { + Attribute *attribute = m_nodesManager->attributeManager()->lookupResource(attributeId); + switch (attribute->attributeType()) { + case QAttribute::IndexAttribute: + indexAttribute = attribute; + break; + case QAttribute::DrawIndirectAttribute: + indirectAttribute = attribute; + break; + case QAttribute::VertexAttribute: { + if (command->m_attributes.contains(attribute->nameId())) + estimatedCount = qMax(attribute->count(), estimatedCount); + break; + } + default: + Q_UNREACHABLE(); + break; + } + } + + 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(); + } + + // 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()); + } else { + // Use the count specified by the GeometryRender + // If not specify use the indexAttribute count if present + // Otherwise tries to use the count from the attribute with the highest count + if (primitiveCount == 0) { + if (indexAttribute) + primitiveCount = indexAttribute->count(); + else + primitiveCount = estimatedCount; + } + } + + 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); Q_ASSERT(shader); @@ -1291,29 +1360,66 @@ QAbstractFrameAdvanceService *Renderer::frameAdvanceService() const // Called by executeCommands void Renderer::performDraw(RenderCommand *command) { - if (command->m_primitiveType == QGeometryRenderer::Patches) - m_graphicsContext->setVerticesPerPatch(command->m_verticesPerPatch); + // Indirect Draw Calls + if (command->m_drawIndirect) { - if (command->m_primitiveRestartEnabled) - m_graphicsContext->enablePrimitiveRestart(command->m_restartIndexValue); - - // TO DO: Add glMulti Draw variants - if (command->m_drawIndexed) { - Profiling::GLTimeRecorder recorder(Profiling::DrawElement); - m_graphicsContext->drawElementsInstancedBaseVertexBaseInstance(command->m_primitiveType, - command->m_primitiveCount, - command->m_indexAttributeDataType, - reinterpret_cast<void*>(quintptr(command->m_indexAttributeByteOffset)), - command->m_instanceCount, - command->m_indexOffset, - command->m_firstVertex); - } else { - Profiling::GLTimeRecorder recorder(Profiling::DrawArray); - m_graphicsContext->drawArraysInstancedBaseInstance(command->m_primitiveType, - command->m_firstInstance, - command->m_primitiveCount, - command->m_instanceCount, - command->m_firstVertex); + // Bind the indirect draw buffer + Buffer *indirectDrawBuffer = m_nodesManager->bufferManager()->data(command->m_indirectDrawBuffer); + if (Q_UNLIKELY(indirectDrawBuffer == nullptr)) { + qWarning() << "Invalid Indirect Draw Buffer - failed to retrieve Buffer"; + return; + } + + // Get GLBuffer from Buffer; + GLBuffer *indirectDrawGLBuffer = m_graphicsContext->glBufferForRenderBuffer(indirectDrawBuffer); + if (Q_UNLIKELY(indirectDrawGLBuffer == nullptr)) { + qWarning() << "Invalid Indirect Draw Buffer - failed to retrieve GLBuffer"; + return; + } + + // Bind GLBuffer + const bool successfullyBound = indirectDrawGLBuffer->bind(m_graphicsContext.data(), GLBuffer::DrawIndirectBuffer); + + if (Q_LIKELY(successfullyBound)) { + // TO DO: Handle multi draw variants if attribute count > 1 + if (command->m_drawIndexed) { + m_graphicsContext->drawElementsIndirect(command->m_primitiveType, + command->m_indexAttributeDataType, + reinterpret_cast<void*>(quintptr(command->m_indirectAttributeByteOffset))); + } else { + m_graphicsContext->drawArraysIndirect(command->m_primitiveType, + reinterpret_cast<void*>(quintptr(command->m_indirectAttributeByteOffset))); + } + } else { + qWarning() << "Failed to bind IndirectDrawBuffer"; + } + + } else { // Direct Draw Calls + // TO DO: Add glMulti Draw variants + if (command->m_primitiveType == QGeometryRenderer::Patches) + m_graphicsContext->setVerticesPerPatch(command->m_verticesPerPatch); + + if (command->m_primitiveRestartEnabled) + m_graphicsContext->enablePrimitiveRestart(command->m_restartIndexValue); + + // TO DO: Add glMulti Draw variants + if (command->m_drawIndexed) { + Profiling::GLTimeRecorder recorder(Profiling::DrawElement); + m_graphicsContext->drawElementsInstancedBaseVertexBaseInstance(command->m_primitiveType, + command->m_primitiveCount, + command->m_indexAttributeDataType, + reinterpret_cast<void*>(quintptr(command->m_indexAttributeByteOffset)), + command->m_instanceCount, + command->m_indexOffset, + command->m_firstVertex); + } else { + Profiling::GLTimeRecorder recorder(Profiling::DrawArray); + m_graphicsContext->drawArraysInstancedBaseInstance(command->m_primitiveType, + command->m_firstInstance, + command->m_primitiveCount, + command->m_instanceCount, + command->m_firstVertex); + } } #if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG) diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp index f7ba5c3c4..4214bcb76 100644 --- a/src/render/graphicshelpers/graphicscontext.cpp +++ b/src/render/graphicshelpers/graphicscontext.cpp @@ -125,6 +125,8 @@ GLBuffer::Type bufferTypeToGLBufferType(QBuffer::BufferType type) return GLBuffer::UniformBuffer; case QBuffer::ShaderStorageBuffer: return GLBuffer::ShaderStorageBuffer; + case QBuffer::DrawIndirectBuffer: + return GLBuffer::DrawIndirectBuffer; default: Q_UNREACHABLE(); } |