diff options
author | Paul Lemire <paul.lemire350@gmail.com> | 2016-05-16 13:44:43 +0200 |
---|---|---|
committer | Sean Harmer <sean.harmer@kdab.com> | 2016-07-03 08:54:20 +0000 |
commit | b246d17fb3e45848ddbfd581d7cb87b9575f7e86 (patch) | |
tree | a644489ff9ca0dfba9edac1af302c1d0d1dff1ad /src/render/backend/renderview.cpp | |
parent | 4d94fa74e3422766f8e84e2192d731310b87bd95 (diff) |
Split RenderViewJobs
Change-Id: I6c4f8970b14e39085480c029b8acdfcdbfc6fa8d
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
Diffstat (limited to 'src/render/backend/renderview.cpp')
-rw-r--r-- | src/render/backend/renderview.cpp | 365 |
1 files changed, 114 insertions, 251 deletions
diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp index ceab4e3e8..8759e8a88 100644 --- a/src/render/backend/renderview.cpp +++ b/src/render/backend/renderview.cpp @@ -100,34 +100,6 @@ int LIGHT_COLOR_NAMES[MAX_LIGHTS]; int LIGHT_INTENSITY_NAMES[MAX_LIGHTS]; QString LIGHT_STRUCT_NAMES[MAX_LIGHTS]; -bool isEntityInLayers(const Entity *entity, bool hasLayerFilter, const Qt3DCore::QNodeIdVector &filterLayerIds) -{ - if (hasLayerFilter && filterLayerIds.isEmpty()) - return false; - else if (filterLayerIds.isEmpty()) - return true; - - const QVector<Layer *> entityLayers = entity->renderComponents<Layer>(); - for (const Layer *entityLayer : entityLayers) { - if (!entityLayer->isEnabled()) - continue; - - if (filterLayerIds.contains(entityLayer->peerId())) - return true; - } - return false; -} - -bool isEntityFrustumCulled(const Entity *entity, const Plane *planes) -{ - const Sphere *s = entity->worldBoundingVolumeWithChildren(); - for (int i = 0; i < 6; ++i) { - if (QVector3D::dotProduct(s->center(), planes[i].normal) + planes[i].d < -s->radius()) - return true; - } - return false; -} - } // anonymous namespace bool wasInitialized = false; @@ -166,22 +138,22 @@ QUniformValue RenderView::modelMatrix(const QMatrix4x4 &model) const QUniformValue RenderView::viewMatrix(const QMatrix4x4 &) const { - return QUniformValue(QVariant::fromValue(*m_data->m_viewMatrix)); + return QUniformValue(QVariant::fromValue(m_data.m_viewMatrix)); } QUniformValue RenderView::projectionMatrix(const QMatrix4x4 &) const { - return QUniformValue(QVariant::fromValue(m_data->m_renderCamera->projection())); + return QUniformValue(QVariant::fromValue(m_data.m_renderCamera->projection())); } QUniformValue RenderView::modelViewMatrix(const QMatrix4x4 &model) const { - return QUniformValue(QVariant::fromValue(*m_data->m_viewMatrix * model)); + return QUniformValue(QVariant::fromValue(m_data.m_viewMatrix * model)); } QUniformValue RenderView::modelViewProjectionMatrix(const QMatrix4x4 &model) const { - return QUniformValue(QVariant::fromValue(*m_data->m_viewProjectionMatrix * model)); + return QUniformValue(QVariant::fromValue(m_data.m_viewProjectionMatrix * model)); } QUniformValue RenderView::inverseModelMatrix(const QMatrix4x4 &model) const @@ -191,25 +163,25 @@ QUniformValue RenderView::inverseModelMatrix(const QMatrix4x4 &model) const QUniformValue RenderView::inverseViewMatrix(const QMatrix4x4 &) const { - return QUniformValue(QVariant::fromValue(m_data->m_viewMatrix->inverted())); + return QUniformValue(QVariant::fromValue(m_data.m_viewMatrix.inverted())); } QUniformValue RenderView::inverseProjectionMatrix(const QMatrix4x4 &) const { QMatrix4x4 projection; - if (m_data->m_renderCamera) - projection = m_data->m_renderCamera->projection(); + if (m_data.m_renderCamera) + projection = m_data.m_renderCamera->projection(); return QUniformValue(QVariant::fromValue(projection.inverted())); } QUniformValue RenderView::inverseModelViewMatrix(const QMatrix4x4 &model) const { - return QUniformValue(QVariant::fromValue((*m_data->m_viewMatrix * model).inverted())); + return QUniformValue(QVariant::fromValue((m_data.m_viewMatrix * model).inverted())); } QUniformValue RenderView::inverseModelViewProjectionMatrix(const QMatrix4x4 &model) const { - return QUniformValue(QVariant::fromValue((*m_data->m_viewProjectionMatrix * model).inverted(0))); + return QUniformValue(QVariant::fromValue((m_data.m_viewProjectionMatrix * model).inverted(0))); } QUniformValue RenderView::modelNormalMatrix(const QMatrix4x4 &model) const @@ -219,7 +191,7 @@ QUniformValue RenderView::modelNormalMatrix(const QMatrix4x4 &model) const QUniformValue RenderView::modelViewNormalMatrix(const QMatrix4x4 &model) const { - return QUniformValue(QVariant::fromValue((*m_data->m_viewMatrix * model).normalMatrix())); + return QUniformValue(QVariant::fromValue((m_data.m_viewMatrix * model).normalMatrix())); } // TODO: Move this somewhere global where GraphicsContext::setViewport() can use it too @@ -236,7 +208,7 @@ QUniformValue RenderView::viewportMatrix(const QMatrix4x4 &model) const // TODO: Can we avoid having to pass the model matrix in to these functions? Q_UNUSED(model); QMatrix4x4 viewportMatrix; - viewportMatrix.viewport(resolveViewport(*m_viewport, m_surfaceSize)); + viewportMatrix.viewport(resolveViewport(m_viewport, m_surfaceSize)); return QUniformValue(QVariant::fromValue(viewportMatrix)); } @@ -245,7 +217,7 @@ QUniformValue RenderView::inverseViewportMatrix(const QMatrix4x4 &model) const { Q_UNUSED(model); QMatrix4x4 viewportMatrix; - viewportMatrix.viewport(resolveViewport(*m_viewport, m_surfaceSize)); + viewportMatrix.viewport(resolveViewport(m_viewport, m_surfaceSize)); QMatrix4x4 inverseViewportMatrix = viewportMatrix.inverted(); return QUniformValue(QVariant::fromValue(inverseViewportMatrix)); @@ -262,15 +234,13 @@ QUniformValue RenderView::time(const QMatrix4x4 &model) const QUniformValue RenderView::eyePosition(const QMatrix4x4 &model) const { Q_UNUSED(model); - return QUniformValue(QVariant::fromValue(m_data->m_eyePos)); + return QUniformValue(QVariant::fromValue(m_data.m_eyePos)); } RenderView::RenderView() : m_renderer(nullptr) , m_devicePixelRatio(1.) - , m_allocator(nullptr) - , m_data(nullptr) - , m_viewport(nullptr) + , m_viewport(QRectF(0.0f, 0.0f, 1.0f, 1.0f)) , m_surface(nullptr) , m_clearBuffer(QClearBuffers::None) , m_globalClearColorBuffer(nullptr) @@ -302,45 +272,11 @@ RenderView::RenderView() RenderView::~RenderView() { - if (m_allocator == nullptr) // Mainly needed for unit tests - return; - + delete m_stateSet; for (RenderCommand *command : qAsConst(m_commands)) { - - if (command->m_stateSet != nullptr) // We do not delete the RenderState as that is stored statically - m_allocator->deallocate<RenderStateSet>(command->m_stateSet); - - // Deallocate RenderCommand - m_allocator->deallocate<RenderCommand>(command); + delete command->m_stateSet; + delete command; } - - // Deallocate viewMatrix/viewProjectionMatrix - m_allocator->deallocate<QMatrix4x4>(m_data->m_viewMatrix); - m_allocator->deallocate<QMatrix4x4>(m_data->m_viewProjectionMatrix); - // Deallocate viewport rect - m_allocator->deallocate<QRectF>(m_viewport); - // Deallocate m_data - m_allocator->deallocate<InnerData>(m_data); - // Deallocate m_stateSet - if (m_stateSet) - m_allocator->deallocate<RenderStateSet>(m_stateSet); -} - -// We need to overload the delete operator so that when the Renderer deletes the list of RenderViews, each RenderView -// can clear itself with the frame allocator and deletes its RenderViews -void RenderView::operator delete(void *ptr) -{ - RenderView *rView = static_cast<RenderView *>(ptr); - if (rView != nullptr && rView->m_allocator != nullptr) - rView->m_allocator->deallocateRawMemory(rView, sizeof(RenderView)); -} - -// Since placement new is used we need a matching operator delete, at least MSVC complains otherwise -void RenderView::operator delete(void *ptr, void *) -{ - RenderView *rView = static_cast<RenderView *>(ptr); - if (rView != nullptr && rView->m_allocator != nullptr) - rView->m_allocator->deallocateRawMemory(rView, sizeof(RenderView)); } void RenderView::sort() @@ -395,48 +331,7 @@ void RenderView::setRenderer(Renderer *renderer) { m_renderer = renderer; m_manager = renderer->nodeManagers(); - m_data->m_uniformBlockBuilder.shaderDataManager = m_manager->shaderDataManager(); -} - -// Returns an array of Passes with the accompanying Parameter list -RenderPassList RenderView::passesAndParameters(ParameterInfoList *parameters, Entity *node, bool useDefaultMaterial) -{ - // Find the material, effect, technique and set of render passes to use - Material *material = nullptr; - Effect *effect = nullptr; - if ((material = node->renderComponent<Material>()) != nullptr && material->isEnabled()) - effect = m_renderer->nodeManagers()->effectManager()->lookupResource(material->effect()); - Technique *technique = findTechniqueForEffect(m_renderer, m_data->m_techniqueFilter, 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); - - RenderPassList passes; - if (Q_LIKELY(technique)) { - passes = findRenderPassesForTechnique(m_manager, m_data->m_passFilter, 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; + m_data.m_uniformBlockBuilder.shaderDataManager = m_manager->shaderDataManager(); } void RenderView::gatherLights(Entity *node) @@ -488,145 +383,113 @@ void RenderView::addClearBuffers(const ClearBuffers *cb) { } } -// TODO: Convert into a job that caches lookup of entities for layers -static void findEntitiesInLayers(Entity *e, bool hasLayerFilter, const Qt3DCore::QNodeIdVector &filterLayerIds, QVector<Entity *> &entities) -{ - // Bail if sub-tree is disabled - if (!e->isEnabled()) - return; - - // Check this entity - if (isEntityInLayers(e, hasLayerFilter, filterLayerIds)) - entities.push_back(e); - - // Recurse to children - const auto children = e->children(); - for (Entity *child : children) - findEntitiesInLayers(child, hasLayerFilter, filterLayerIds, entities); -} - // Tries to order renderCommand by shader so as to minimize shader changes -void RenderView::buildRenderCommands(Entity *rootEntity, const Plane *planes) +void RenderView::buildRenderCommands() { -#if defined(QT3D_RENDER_VIEW_JOB_TIMINGS) - QElapsedTimer timer; - timer.start(); -#endif - // Filter the entities according to the layers for this renderview - QVector<Entity *> entities; - const int entityCount = m_renderer->nodeManagers()->renderNodesManager()->count(); - entities.reserve(entityCount); - findEntitiesInLayers(rootEntity, hasLayerFilter(), layerFilter(), entities); -#if defined(QT3D_RENDER_VIEW_JOB_TIMINGS) - qDebug() << "Found" << entities.size() << "entities in layers" << m_data->m_layers - << "in" << timer.nsecsElapsed() / 1.0e6 << "ms"; -#endif - - for (Entity *entity : qAsConst(entities)) { - if (m_compute) { - // 1) Look for Compute Entities if Entity -> components [ ComputeJob, Material ] - // when the RenderView is part of a DispatchCompute branch - buildComputeRenderCommands(entity); - } else { - // 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(entity, planes); - } + if (m_compute) { + // 1) Look for Compute Entities if Entity -> components [ ComputeJob, Material ] + // when the RenderView is part of a DispatchCompute branch + buildComputeRenderCommands(); + } else { + // 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(); } } -void RenderView::buildDrawRenderCommands(Entity *node, const Plane *planes) +// If we are there, we know that entity had a GeometryRenderer + Material +void RenderView::buildDrawRenderCommands() { - if (m_frustumCulling && isEntityFrustumCulled(node, planes)) - return; - - GeometryRenderer *geometryRenderer = nullptr; - HGeometryRenderer geometryRendererHandle = node->componentHandle<GeometryRenderer, 16>(); - if (!geometryRendererHandle.isNull() - && (geometryRenderer = m_manager->geometryRendererManager()->data(geometryRendererHandle)) != nullptr - && geometryRenderer->isEnabled() - && !geometryRenderer->geometryId().isNull()) { - + for (Entity *node : qAsConst(m_renderables)) { + GeometryRenderer *geometryRenderer = nullptr; + HGeometryRenderer geometryRendererHandle = node->componentHandle<GeometryRenderer, 16>(); // There is a geometry renderer with geometry - ParameterInfoList parameters; - const RenderPassList passes = passesAndParameters(¶meters, node, true); - - // 1 RenderCommand per RenderPass pass on an Entity with a Mesh - for (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 = geometryRendererHandle; - // 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->hasRenderStates()) { - command->m_stateSet = m_allocator->allocate<RenderStateSet>(); - addToRenderStateSet(command->m_stateSet, pass, m_manager->renderStateManager()); - - // Merge per pass stateset with global stateset - // so that the local stateset only overrides - if (m_stateSet != nullptr) - command->m_stateSet->merge(m_stateSet); - command->m_changeCost = m_renderer->defaultRenderState()->changeCost(command->m_stateSet); - } + if ((geometryRenderer = m_manager->geometryRendererManager()->data(geometryRendererHandle)) != nullptr + && geometryRenderer->isEnabled() + && !geometryRenderer->geometryId().isNull()) { + + const Qt3DCore::QNodeId materialComponentId = node->componentUuid<Material>(); + const QVector<RenderPassParameterData> renderPassData = m_parameters.value(materialComponentId); + + // 1 RenderCommand per RenderPass pass on an Entity with a Mesh + for (const RenderPassParameterData &passData : renderPassData) { + // Add the RenderPass Parameters + RenderCommand *command = new 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 = geometryRendererHandle; + // 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 + RenderPass *pass = passData.pass; + if (pass->hasRenderStates()) { + command->m_stateSet = new RenderStateSet(); + addToRenderStateSet(command->m_stateSet, pass, m_manager->renderStateManager()); + + // Merge per pass stateset with global stateset + // so that the local stateset only overrides + if (m_stateSet != 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(); - } + // 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); + ParameterInfoList globalParameters = passData.parameterInfo; + setShaderAndUniforms(command, pass, globalParameters, *(node->worldTransform()), activeLightSources); - buildSortingKey(command); - m_commands.append(command); + buildSortingKey(command); + m_commands.append(command); + } } } } -void RenderView::buildComputeRenderCommands(Entity *node) +void RenderView::buildComputeRenderCommands() { // 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/ - ComputeCommand *computeJob = nullptr; - if (node->componentHandle<ComputeCommand, 16>() != HComputeCommand() - && (computeJob = node->renderComponent<ComputeCommand>()) != nullptr - && computeJob->isEnabled()) { - - ParameterInfoList parameters; - const RenderPassList passes = passesAndParameters(¶meters, node, true); - - for (RenderPass *pass : passes) { - // Add the RenderPass Parameters - ParameterInfoList globalParameters = parameters; - parametersFromParametersProvider(&globalParameters, m_manager->parameterManager(), pass); - - RenderCommand *command = m_allocator->allocate<RenderCommand>(); - command->m_type = RenderCommand::Compute; - command->m_workGroups[0] = std::max(m_workGroups[0], computeJob->x()); - command->m_workGroups[1] = std::max(m_workGroups[1], computeJob->y()); - command->m_workGroups[2] = std::max(m_workGroups[2], computeJob->z()); - setShaderAndUniforms(command, - pass, - globalParameters, - *(node->worldTransform()), - QVector<LightSource>()); - m_commands.append(command); + for (Entity *node : qAsConst(m_computables)) { + ComputeCommand *computeJob = nullptr; + if ((computeJob = node->renderComponent<ComputeCommand>()) != nullptr + && computeJob->isEnabled()) { + + const Qt3DCore::QNodeId materialComponentId = node->componentUuid<Material>(); + const QVector<RenderPassParameterData> renderPassData = m_parameters.value(materialComponentId); + + // 1 RenderCommand per RenderPass pass on an Entity with a Mesh + for (const RenderPassParameterData &passData : renderPassData) { + // Add the RenderPass Parameters + ParameterInfoList globalParameters = passData.parameterInfo; + RenderPass *pass = passData.pass; + parametersFromParametersProvider(&globalParameters, m_manager->parameterManager(), pass); + + RenderCommand *command = new RenderCommand(); + command->m_type = RenderCommand::Compute; + command->m_workGroups[0] = std::max(m_workGroups[0], computeJob->x()); + command->m_workGroups[1] = std::max(m_workGroups[1], computeJob->y()); + command->m_workGroups[2] = std::max(m_workGroups[2], computeJob->z()); + setShaderAndUniforms(command, + pass, + globalParameters, + *(node->worldTransform()), + QVector<LightSource>()); + m_commands.append(command); + } } } } @@ -750,19 +613,19 @@ void RenderView::setShaderStorageValue(ShaderParameterPack &uniformPack, void RenderView::setDefaultUniformBlockShaderDataValue(ShaderParameterPack &uniformPack, Shader *shader, ShaderData *shaderData, const QString &structName) { - m_data->m_uniformBlockBuilder.activeUniformNamesToValue.clear(); + m_data.m_uniformBlockBuilder.activeUniformNamesToValue.clear(); // updates transformed properties; - shaderData->updateViewTransform(*m_data->m_viewMatrix); + shaderData->updateViewTransform(m_data.m_viewMatrix); // Force to update the whole block - m_data->m_uniformBlockBuilder.updatedPropertiesOnly = false; + m_data.m_uniformBlockBuilder.updatedPropertiesOnly = false; // Retrieve names and description of each active uniforms in the uniform block - m_data->m_uniformBlockBuilder.uniforms = shader->activeUniformsForUniformBlock(-1); + m_data.m_uniformBlockBuilder.uniforms = shader->activeUniformsForUniformBlock(-1); // Build name-value map for the block - m_data->m_uniformBlockBuilder.buildActiveUniformNameValueMapStructHelper(shaderData, structName); + m_data.m_uniformBlockBuilder.buildActiveUniformNameValueMapStructHelper(shaderData, structName); // Set uniform values for each entrie of the block name-value map - QHash<int, QVariant>::const_iterator activeValuesIt = m_data->m_uniformBlockBuilder.activeUniformNamesToValue.constBegin(); - const QHash<int, QVariant>::const_iterator activeValuesEnd = m_data->m_uniformBlockBuilder.activeUniformNamesToValue.constEnd(); + QHash<int, QVariant>::const_iterator activeValuesIt = m_data.m_uniformBlockBuilder.activeUniformNamesToValue.constBegin(); + const QHash<int, QVariant>::const_iterator activeValuesEnd = m_data.m_uniformBlockBuilder.activeUniformNamesToValue.constEnd(); while (activeValuesIt != activeValuesEnd) { setUniformValue(uniformPack, activeValuesIt.key(), activeValuesIt.value()); @@ -773,13 +636,13 @@ void RenderView::setDefaultUniformBlockShaderDataValue(ShaderParameterPack &unif void RenderView::buildSortingKey(RenderCommand *command) { // Build a bitset key depending on the SortingCriterion - int sortCount = m_data->m_sortingTypes.count(); + int sortCount = m_data.m_sortingTypes.count(); // If sortCount == 0, no sorting is applied // Handle at most 4 filters at once for (int i = 0; i < sortCount && i < 4; i++) { - switch (m_data->m_sortingTypes.at(i)) { + switch (m_data.m_sortingTypes.at(i)) { case QSortPolicy::StateChangeCost: command->m_sortingType.sorts[i] = command->m_changeCost; // State change cost break; |