diff options
author | Paul Lemire <paul.lemire@kdab.com> | 2015-12-08 18:58:17 +0100 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2016-01-13 16:08:56 +0000 |
commit | 32ff2d08a03d533ab157f57513937a0e3085c924 (patch) | |
tree | 8983070f9d4616a1bfe15fbe71bae7c38f6383c2 | |
parent | d7e9c7a9844b658d93c3f1ac47e96f069162de3d (diff) |
RenderView: sliglty modified to later accommodate compute calls
Change-Id: Ic821747677c9d2f117494d2ecfd89f47f982fa3f
Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
-rw-r--r-- | src/render/backend/managers_p.h | 2 | ||||
-rw-r--r-- | src/render/backend/rendercommand.cpp | 6 | ||||
-rw-r--r-- | src/render/backend/renderer.cpp | 4 | ||||
-rw-r--r-- | src/render/backend/renderview.cpp | 242 | ||||
-rw-r--r-- | src/render/backend/renderview_p.h | 4 | ||||
-rw-r--r-- | src/render/graphicshelpers/graphicscontext.cpp | 10 | ||||
-rw-r--r-- | src/render/io/glbuffer_p.h | 2 |
7 files changed, 155 insertions, 115 deletions
diff --git a/src/render/backend/managers_p.h b/src/render/backend/managers_p.h index 927e6c5e9..94089795c 100644 --- a/src/render/backend/managers_p.h +++ b/src/render/backend/managers_p.h @@ -284,7 +284,7 @@ public: class GLBufferManager : public Qt3DCore::QResourceManager< GLBuffer, - ShaderDataShaderUboKey, + BufferShaderKey, 16, Qt3DCore::ArrayAllocatingPolicy, Qt3DCore::ObjectLevelLockingPolicy> diff --git a/src/render/backend/rendercommand.cpp b/src/render/backend/rendercommand.cpp index 6def67187..a0eb657b0 100644 --- a/src/render/backend/rendercommand.cpp +++ b/src/render/backend/rendercommand.cpp @@ -43,7 +43,11 @@ namespace Qt3DRender { namespace Render { RenderCommand::RenderCommand() - : m_sortBackToFront(false) + : m_instancesCount(0) + , m_stateSet(Q_NULLPTR) + , m_depth(0.0f) + , m_changeCost(0) + , m_sortBackToFront(false) { m_sortingType.global = 0; } diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index e2d4ef768..98110061d 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -700,6 +700,7 @@ bool Renderer::submitRenderViews() // Clear BackBuffer m_graphicsContext->clearBackBuffer(renderView->clearBuffer()); + // Set the Viewport m_graphicsContext->setViewport(renderView->viewport()); @@ -869,6 +870,9 @@ void Renderer::executeCommands(const QVector<RenderCommand *> &commands) //// Update program uniforms m_graphicsContext->setUniforms(command->m_uniforms); + //// Bind SSBO Buffers + // Note: how does that behave regarding VAO + //// Draw Calls // Set state RenderStateSet *localState = command->m_stateSet; diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp index 5c423167c..280a83e29 100644 --- a/src/render/backend/renderview.cpp +++ b/src/render/backend/renderview.cpp @@ -394,6 +394,47 @@ void RenderView::setRenderer(Renderer *renderer) m_data->m_uniformBlockBuilder.shaderDataManager = m_manager->shaderDataManager(); } +// Returns an array of Passes with the accompanying Parameter list +RenderRenderPassList RenderView::passesAndParameters(ParameterInfoList *parameters, Entity *node, bool useDefaultMaterial) +{ + // Find the material, effect, technique and set of render passes to use + Material *material = Q_NULLPTR; + Effect *effect = Q_NULLPTR; + if ((material = node->renderComponent<Material>()) != Q_NULLPTR && material->isEnabled()) + effect = m_renderer->nodeManagers()->effectManager()->lookupResource(material->effect()); + Technique *technique = findTechniqueForEffect(m_renderer, this, effect); + + // Order set: + // 1 Pass Filter + // 2 Technique Filter + // 3 Material + // 4 Effect + // 5 Technique + // 6 RenderPass + + // Add Parameters define in techniqueFilter and passFilter + // passFilter have priority over techniqueFilter + if (m_data->m_passFilter) + parametersFromParametersProvider(parameters, m_renderer->nodeManagers()->parameterManager(), + m_data->m_passFilter); + if (m_data->m_techniqueFilter) + parametersFromParametersProvider(parameters, m_renderer->nodeManagers()->parameterManager(), + m_data->m_techniqueFilter); + // Get the parameters for our selected rendering setup (override what was defined in the technique/pass filter) + parametersFromMaterialEffectTechnique(parameters, m_manager->parameterManager(), material, effect, technique); + + RenderRenderPassList passes; + if (technique) { + passes = findRenderPassesForTechnique(m_manager, this, technique); + } else if (useDefaultMaterial) { + material = m_manager->data<Material, MaterialManager>(m_renderer->defaultMaterialHandle()); + effect = m_manager->data<Effect, EffectManager>(m_renderer->defaultEffectHandle()); + technique = m_manager->data<Technique, TechniqueManager>(m_renderer->defaultTechniqueHandle()); + passes << m_manager->data<RenderPass, RenderPassManager>(m_renderer->defaultRenderPassHandle()); + } + return passes; +} + void RenderView::gatherLights(Entity *node) { const QList<Light *> lights = node->renderComponents<Light>(); @@ -426,114 +467,93 @@ void RenderView::buildRenderCommands(Entity *node, const Plane *planes) if (!node->isEnabled()) return; - if (m_frustumCulling && isEntityFrustumCulled(node, planes)) - return; - // Build renderCommand for current node if (isEntityInLayers(node, m_data->m_layers)) { - GeometryRenderer *geometryRenderer = Q_NULLPTR; - if (node->componentHandle<GeometryRenderer, 16>() != HGeometryRenderer() - && (geometryRenderer = node->renderComponent<GeometryRenderer>()) != Q_NULLPTR - && geometryRenderer->isEnabled()) { - - // There is a geometry renderer - if (geometryRenderer != Q_NULLPTR && !geometryRenderer->geometryId().isNull()) { - // TO DO: Perform culling here - // As shaders may be deforming, transforming the mesh - // We might want to make that optional or dependent on an explicit bounding box item - - // Find the material, effect, technique and set of render passes to use - Material *material = Q_NULLPTR; - Effect *effect = Q_NULLPTR; - if ((material = node->renderComponent<Material>()) != Q_NULLPTR && material->isEnabled()) - effect = m_renderer->nodeManagers()->effectManager()->lookupResource(material->effect()); - Technique *technique = findTechniqueForEffect(m_renderer, this, effect); - - ParameterInfoList parameters; - // Order set: - // 1 Pass Filter - // 2 Technique Filter - // 3 Material - // 4 Effect - // 5 Technique - // 6 RenderPass - - // Add Parameters define in techniqueFilter and passFilter - // passFilter have priority over techniqueFilter - if (m_data->m_passFilter) - parametersFromParametersProvider(¶meters, m_renderer->nodeManagers()->parameterManager(), - m_data->m_passFilter); - if (m_data->m_techniqueFilter) - parametersFromParametersProvider(¶meters, m_renderer->nodeManagers()->parameterManager(), - m_data->m_techniqueFilter); - - RenderRenderPassList passes; - if (technique) { - passes = findRenderPassesForTechnique(m_manager, this, technique); - } else { - material = m_manager->data<Material, MaterialManager>(m_renderer->defaultMaterialHandle()); - effect = m_manager->data<Effect, EffectManager>(m_renderer->defaultEffectHandle()); - technique = m_manager->data<Technique, TechniqueManager>(m_renderer->defaultTechniqueHandle()); - passes << m_manager->data<RenderPass, RenderPassManager>(m_renderer->defaultRenderPassHandle()); - } + // 1) Look for Compute Entities if Entity -> components [ ComputeJob, Material ] + // when the RenderView is part of a DispatchCompute branch + buildComputeRenderCommands(node); - // Get the parameters for our selected rendering setup (override what was defined in the technique/pass filter) - parametersFromMaterialEffectTechnique(¶meters, m_manager->parameterManager(), material, effect, technique); - - // 1 RenderCommand per RenderPass pass on an Entity with a Mesh - m_commands.reserve(m_commands.size() + passes.size()); - Q_FOREACH (RenderPass *pass, passes) { - - // Add the RenderPass Parameters - ParameterInfoList globalParameters = parameters; - parametersFromParametersProvider(&globalParameters, m_manager->parameterManager(), pass); - - RenderCommand *command = m_allocator->allocate<RenderCommand>(); - command->m_depth = m_data->m_eyePos.distanceToPoint(node->worldBoundingVolume()->center()); - - command->m_geometry = m_manager->lookupHandle<Geometry, GeometryManager, HGeometry>(geometryRenderer->geometryId()); - command->m_geometryRenderer = node->componentHandle<GeometryRenderer, 16>(); - command->m_instancesCount = 0; - command->m_stateSet = Q_NULLPTR; - command->m_changeCost = 0; - // For RenderPass based states we use the globally set RenderState - // if no renderstates are defined as part of the pass. That means: - // RenderPass { renderStates: [] } will use the states defined by - // StateSet in the FrameGraph - if (!pass->renderStates().isEmpty()) - command->m_stateSet = buildRenderStateSet(pass->renderStates(), m_allocator); - if (command->m_stateSet != Q_NULLPTR) { - // Merge per pass stateset with global stateset - // so that the local stateset only overrides - if (m_stateSet != Q_NULLPTR) - command->m_stateSet->merge(m_stateSet); - command->m_changeCost = m_renderer->defaultRenderState()->changeCost(command->m_stateSet); - } + // 2) Look for Drawable Entities if Entity -> components [ GeometryRenderer, Material ] + // when the RenderView is not part of a DispatchCompute branch + // Investigate if it's worth doing as separate jobs + buildDrawRenderCommands(node, planes); - // Pick which lights to take in to account. - // For now decide based on the distance by taking the MAX_LIGHTS closest lights. - // Replace with more sophisticated mechanisms later. - std::sort(m_lightSources.begin(), m_lightSources.end(), LightSourceCompare(node)); - QVector<LightSource> activeLightSources; // NB! the total number of lights here may still exceed MAX_LIGHTS - activeLightSources.reserve(m_lightSources.count()); - int lightCount = 0; - for (int i = 0; i < m_lightSources.count() && lightCount < MAX_LIGHTS; ++i) { - activeLightSources.append(m_lightSources[i]); - lightCount += m_lightSources[i].lights.count(); - } + // Note: in theory going to both code paths is possible but + // would most likely be the result of the user not knowing what he's doing + } + + // Traverse children + Q_FOREACH (Entity *child, node->children()) + buildRenderCommands(child, planes); +} - setShaderAndUniforms(command, pass, globalParameters, *(node->worldTransform()), activeLightSources); +void RenderView::buildDrawRenderCommands(Entity *node, const Plane *planes) +{ + if (m_frustumCulling && isEntityFrustumCulled(node, planes)) + return; - buildSortingKey(command); - m_commands.append(command); + GeometryRenderer *geometryRenderer = Q_NULLPTR; + if (node->componentHandle<GeometryRenderer, 16>() != HGeometryRenderer() + && (geometryRenderer = node->renderComponent<GeometryRenderer>()) != Q_NULLPTR + && geometryRenderer->isEnabled()) { + + ParameterInfoList parameters; + RenderRenderPassList passes = passesAndParameters(¶meters, node, true); + // There is a geometry renderer + if (geometryRenderer != Q_NULLPTR && !geometryRenderer->geometryId().isNull()) { + + // 1 RenderCommand per RenderPass pass on an Entity with a Mesh + Q_FOREACH (RenderPass *pass, passes) { + // Add the RenderPass Parameters + ParameterInfoList globalParameters = parameters; + parametersFromParametersProvider(&globalParameters, m_manager->parameterManager(), pass); + + RenderCommand *command = m_allocator->allocate<RenderCommand>(); + command->m_depth = m_data->m_eyePos.distanceToPoint(node->worldBoundingVolume()->center()); + command->m_geometry = m_manager->lookupHandle<Geometry, GeometryManager, HGeometry>(geometryRenderer->geometryId()); + command->m_geometryRenderer = node->componentHandle<GeometryRenderer, 16>(); + // For RenderPass based states we use the globally set RenderState + // if no renderstates are defined as part of the pass. That means: + // RenderPass { renderStates: [] } will use the states defined by + // StateSet in the FrameGraph + if (!pass->renderStates().isEmpty()) { + command->m_stateSet = buildRenderStateSet(pass->renderStates(), m_allocator); + // Merge per pass stateset with global stateset + // so that the local stateset only overrides + if (m_stateSet != Q_NULLPTR) + command->m_stateSet->merge(m_stateSet); + command->m_changeCost = m_renderer->defaultRenderState()->changeCost(command->m_stateSet); } + + // Pick which lights to take in to account. + // For now decide based on the distance by taking the MAX_LIGHTS closest lights. + // Replace with more sophisticated mechanisms later. + std::sort(m_lightSources.begin(), m_lightSources.end(), LightSourceCompare(node)); + QVector<LightSource> activeLightSources; // NB! the total number of lights here may still exceed MAX_LIGHTS + int lightCount = 0; + for (int i = 0; i < m_lightSources.count() && lightCount < MAX_LIGHTS; ++i) { + activeLightSources.append(m_lightSources[i]); + lightCount += m_lightSources[i].lights.count(); + } + + setShaderAndUniforms(command, pass, globalParameters, *(node->worldTransform()), activeLightSources); + + buildSortingKey(command); + m_commands.append(command); } } } +} - // Traverse children - Q_FOREACH (Entity *child, node->children()) - buildRenderCommands(child, planes); +void RenderView::buildComputeRenderCommands(Entity *node) +{ + // TO DO: Complete + Q_UNUSED(node) + // If the RenderView contains only a ComputeDispatch then it cares about + // A ComputeDispatch is also implicitely a NoDraw operation + // enabled flag + // layer component + // material/effect/technique/parameters/filters/ } const AttachmentPack &RenderView::attachmentPack() const @@ -577,18 +597,16 @@ void RenderView::setUniformBlockValue(QUniformPack &uniformPack, Shader *shader, ShaderData *shaderData = Q_NULLPTR; if (static_cast<QMetaType::Type>(value.type()) == qNodeIdTypeId && - (shaderData = m_manager->shaderDataManager()->lookupResource(value.value<Qt3DCore::QNodeId>())) != Q_NULLPTR) { + (shaderData = m_manager->shaderDataManager()->lookupResource(value.value<Qt3DCore::QNodeId>())) != Q_NULLPTR) { // UBO are indexed by <ShaderId, ShaderDataId> so that a same QShaderData can be used among different shaders // while still making sure that if they have a different layout everything will still work // If two shaders define the same block with the exact same layout, in that case the UBO could be shared // but how do we know that ? We'll need to compare ShaderUniformBlocks - // For now a UBO is unique to a Shader and a ShaderData - // later we might want to make them shareable across Shaders but - // that will require checking that all Shaders have the same layout for a given - // uniform block - ShaderDataShaderUboKey uboKey(shaderData->peerUuid(), - shader->peerUuid()); + // Note: we assume that if a buffer is shared accross multiple shaders + // then it implies that they share the same layout + BufferShaderKey uboKey(shaderData->peerUuid(), + shader->peerUuid()); BlockToUBO uniformBlockUBO; uniformBlockUBO.m_blockIndex = block.m_index; @@ -697,9 +715,10 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass, // Builds the QUniformPack, sets shader standard uniforms and store attributes name / glname bindings // If a parameter is defined and not found in the bindings it is assumed to be a binding of Uniform type with the glsl name // equals to the parameter name - const QVector<QString> &uniformNames = shader->uniformsNames(); - const QVector<QString> &attributeNames = shader->attributesNames(); - const QVector<QString> &uniformBlockNames = shader->uniformBlockNames(); + const QVector<QString> uniformNames = shader->uniformsNames(); + const QVector<QString> attributeNames = shader->attributesNames(); + const QVector<QString> uniformBlockNames = shader->uniformBlockNames(); + const QVector<QString> shaderStorageBlockNames = shader->storageBlockNames(); // Set fragData Name and index // Later on we might want to relink the shader if attachments have changed @@ -712,7 +731,7 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass, } } - if (!uniformNames.isEmpty() || !attributeNames.isEmpty()) { + if (!uniformNames.isEmpty() || !attributeNames.isEmpty() || !shaderStorageBlockNames.isEmpty()) { // Set default standard uniforms without bindings Q_FOREACH (const QString &uniformName, uniformNames) { @@ -764,11 +783,16 @@ void RenderView::setShaderAndUniforms(RenderCommand *command, RenderPass *rPass, const ShaderUniformBlock &block = shader->uniformBlock(it->name); setUniformBlockValue(command->m_uniforms, shader, block, it->value); it = parameters.erase(it); + } else if (shaderStorageBlockNames.indexOf(it->name) != -1) { // Parameters is a SSBO + const ShaderStorageBlock block = shader->storageBlock(it->name); + // TO DO: Do whatever is needed + Q_UNUSED(block) + it = parameters.erase(it); } else { // Parameter is a struct const QVariant &v = it->value; ShaderData *shaderData = Q_NULLPTR; if (static_cast<QMetaType::Type>(v.type()) == qNodeIdTypeId && - (shaderData = m_manager->shaderDataManager()->lookupResource(v.value<Qt3DCore::QNodeId>())) != Q_NULLPTR) { + (shaderData = m_manager->shaderDataManager()->lookupResource(v.value<Qt3DCore::QNodeId>())) != Q_NULLPTR) { // Try to check if we have a struct or array matching a QShaderData parameter setDefaultUniformBlockShaderDataValue(command->m_uniforms, shader, shaderData, it->name); it = parameters.erase(it); diff --git a/src/render/backend/renderview_p.h b/src/render/backend/renderview_p.h index 59da14b60..e99c60fc3 100644 --- a/src/render/backend/renderview_p.h +++ b/src/render/backend/renderview_p.h @@ -213,7 +213,11 @@ public: inline void setClearBuffer(QClearBuffer::BufferType clearBuffer) Q_DECL_NOEXCEPT { m_clearBuffer = clearBuffer; } inline QClearBuffer::BufferType clearBuffer() const Q_DECL_NOEXCEPT { return m_clearBuffer; } + RenderRenderPassList passesAndParameters(ParameterInfoList *parameter, Entity *node, bool useDefaultMaterials = true); + void buildRenderCommands(Entity *preprocessedTreeRoot, const Plane *planes); + void buildDrawRenderCommands(Entity *node, const Plane *planes); + void buildComputeRenderCommands(Entity *node); QVector<RenderCommand *> commands() const { return m_commands; } void gatherLights(Entity *preprocessedTreeRoot); diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp index 8fa9bba61..19415d0b8 100644 --- a/src/render/graphicshelpers/graphicscontext.cpp +++ b/src/render/graphicshelpers/graphicscontext.cpp @@ -359,7 +359,6 @@ void GraphicsContext::activateShader(Shader *shader) } if (m_activeShader != Q_NULLPTR && m_activeShader->dna() == shader->dna()) { - // no op } else { m_activeShader = shader; @@ -894,8 +893,8 @@ void GraphicsContext::setUniforms(QUniformPack &uniforms) for (int i = 0; i < blockToUbos.length(); ++i) { const ShaderUniformBlock &block = m_activeShader->uniformBlock(blockToUbos[i].m_blockIndex); if (block.m_index != -1 && block.m_size > 0) { - ubo = manager->lookupResource<GLBuffer, GLBufferManager>(ShaderDataShaderUboKey(blockToUbos[i].m_shaderDataID, - m_activeShader->peerUuid())); + ubo = manager->lookupResource<GLBuffer, GLBufferManager>(BufferShaderKey(blockToUbos[i].m_shaderDataID, + m_activeShader->peerUuid())); // bind Uniform Block of index ubos[i].m_index to binding point i bindUniformBlock(m_activeShader->getOrCreateProgram(this)->programId(), block.m_index, i); // bind the UBO to the binding point i @@ -909,6 +908,11 @@ void GraphicsContext::setUniforms(QUniformPack &uniforms) } // update the ubo if needed + + // TO DO: Maybe QShaderData should act as a QBuffer data provider + // and internally update a QBuffer which we would then reupload + // and the ShaderData updates could then be done in some jobs + // rather than at render time ? if (blockToUbos[i].m_needsUpdate) { if (!ubo->isBound()) ubo->bind(this, GLBuffer::UniformBuffer); diff --git a/src/render/io/glbuffer_p.h b/src/render/io/glbuffer_p.h index b89c9f7e0..9d47a52db 100644 --- a/src/render/io/glbuffer_p.h +++ b/src/render/io/glbuffer_p.h @@ -59,7 +59,7 @@ namespace Render { class GraphicsContext; -typedef QPair<Qt3DCore::QNodeId, Qt3DCore::QNodeId> ShaderDataShaderUboKey; +typedef QPair<Qt3DCore::QNodeId, Qt3DCore::QNodeId> BufferShaderKey; class GLBuffer { |