summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2015-12-08 18:58:17 +0100
committerPaul Lemire <paul.lemire@kdab.com>2016-01-13 16:08:56 +0000
commit32ff2d08a03d533ab157f57513937a0e3085c924 (patch)
tree8983070f9d4616a1bfe15fbe71bae7c38f6383c2
parentd7e9c7a9844b658d93c3f1ac47e96f069162de3d (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.h2
-rw-r--r--src/render/backend/rendercommand.cpp6
-rw-r--r--src/render/backend/renderer.cpp4
-rw-r--r--src/render/backend/renderview.cpp242
-rw-r--r--src/render/backend/renderview_p.h4
-rw-r--r--src/render/graphicshelpers/graphicscontext.cpp10
-rw-r--r--src/render/io/glbuffer_p.h2
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(&parameters, m_renderer->nodeManagers()->parameterManager(),
- m_data->m_passFilter);
- if (m_data->m_techniqueFilter)
- parametersFromParametersProvider(&parameters, 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(&parameters, 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(&parameters, 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
{