1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-12-05 01:34:33 +00:00

speeds up optimizer (#3162)

We can expect marginally improved loading times with this PR. Drawable, Transform and Node counts in stats panels are expected to remain unchanged - this PR does not add new scene graph optimisations, it just increases the speed with which we apply existing ones.

1. We add explicit `NodeVisitor::apply` overrides for commonly encountered node types to avoid additional virtual function calls per node associated with the default `apply` implementation.
2. We skip pushing `StateSet`s when  `_mergeAlphaBlending` is enabled or the `StateSet` contains no relevant state.
3. We add a specialised variant of `CollectLowestTransformsVisitor::addTransform` accepting `MatrixTransform` to avoid matrix copies and multiplications.
This commit is contained in:
Bo Svensson 2021-10-10 16:09:15 +00:00 committed by GitHub
parent b61140b8ba
commit 031871cd48
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 30 deletions

View file

@ -171,7 +171,7 @@ class CollectLowestTransformsVisitor : public BaseOptimizerVisitor
setTraversalMode(osg::NodeVisitor::TRAVERSE_PARENTS); setTraversalMode(osg::NodeVisitor::TRAVERSE_PARENTS);
} }
void apply(osg::Node& node) override void apply(osg::Group& node) override
{ {
if (node.getNumParents()) if (node.getNumParents())
{ {
@ -180,7 +180,7 @@ class CollectLowestTransformsVisitor : public BaseOptimizerVisitor
else else
{ {
// for all current objects mark a nullptr transform for them. // for all current objects mark a nullptr transform for them.
registerWithCurrentObjects(0); registerWithCurrentObjects(static_cast<osg::Transform*>(nullptr));
} }
} }
@ -198,15 +198,19 @@ class CollectLowestTransformsVisitor : public BaseOptimizerVisitor
// for all current objects associated this transform with them. // for all current objects associated this transform with them.
registerWithCurrentObjects(&transform); registerWithCurrentObjects(&transform);
} }
void apply(osg::MatrixTransform& transform) override
void apply(osg::Geode& geode) override
{ {
traverse(geode); // for all current objects associated this transform with them.
registerWithCurrentObjects(&transform);
} }
void apply(osg::Billboard& geode) override void apply(osg::Node& node) override
{
traverse(node);
}
void apply(osg::Geometry& geode) override
{ {
traverse(geode);
} }
void collectDataFor(osg::Node* node) void collectDataFor(osg::Node* node)
@ -293,7 +297,19 @@ class CollectLowestTransformsVisitor : public BaseOptimizerVisitor
ObjectStruct():_canBeApplied(true),_moreThanOneMatrixRequired(false) {} ObjectStruct():_canBeApplied(true),_moreThanOneMatrixRequired(false) {}
void add(osg::Transform* transform, bool canOptimize) inline const osg::Matrix& getMatrix(osg::MatrixTransform* transform)
{
return transform->getMatrix();
}
osg::Matrix getMatrix(osg::Transform* transform)
{
osg::Matrix matrix;
transform->computeLocalToWorldMatrix(matrix, 0);
return matrix;
}
template<typename T>
void add(T* transform, bool canOptimize)
{ {
if (transform) if (transform)
{ {
@ -301,12 +317,10 @@ class CollectLowestTransformsVisitor : public BaseOptimizerVisitor
else if (transform->getReferenceFrame()!=osg::Transform::RELATIVE_RF) _moreThanOneMatrixRequired=true; else if (transform->getReferenceFrame()!=osg::Transform::RELATIVE_RF) _moreThanOneMatrixRequired=true;
else else
{ {
if (_transformSet.empty()) transform->computeLocalToWorldMatrix(_firstMatrix,0); if (_transformSet.empty()) _firstMatrix = getMatrix(transform);
else else
{ {
osg::Matrix matrix; if (_firstMatrix!=getMatrix(transform)) _moreThanOneMatrixRequired=true;
transform->computeLocalToWorldMatrix(matrix,0);
if (_firstMatrix!=matrix) _moreThanOneMatrixRequired=true;
} }
} }
} }
@ -327,8 +341,8 @@ class CollectLowestTransformsVisitor : public BaseOptimizerVisitor
TransformSet _transformSet; TransformSet _transformSet;
}; };
template <typename T>
void registerWithCurrentObjects(osg::Transform* transform) void registerWithCurrentObjects(T* transform)
{ {
for(ObjectList::iterator itr=_currentObjectList.begin(); for(ObjectList::iterator itr=_currentObjectList.begin();
itr!=_currentObjectList.end(); itr!=_currentObjectList.end();
@ -633,19 +647,23 @@ osg::Array* cloneArray(osg::Array* array, osg::VertexBufferObject*& vbo, const o
return array; return array;
} }
void Optimizer::FlattenStaticTransformsVisitor::apply(osg::Drawable& drawable) void Optimizer::FlattenStaticTransformsVisitor::apply(osg::Geometry& geometry)
{ {
osg::Geometry *geometry = drawable.asGeometry(); if(isOperationPermissibleForObject(&geometry))
if((geometry) && (isOperationPermissibleForObject(&drawable)))
{ {
osg::VertexBufferObject* vbo = nullptr; osg::VertexBufferObject* vbo = nullptr;
if(geometry->getVertexArray() && geometry->getVertexArray()->referenceCount() > 1) if(geometry.getVertexArray() && geometry.getVertexArray()->referenceCount() > 1)
geometry->setVertexArray(cloneArray(geometry->getVertexArray(), vbo, geometry)); geometry.setVertexArray(cloneArray(geometry.getVertexArray(), vbo, &geometry));
if(geometry->getNormalArray() && geometry->getNormalArray()->referenceCount() > 1) if(geometry.getNormalArray() && geometry.getNormalArray()->referenceCount() > 1)
geometry->setNormalArray(cloneArray(geometry->getNormalArray(), vbo, geometry)); geometry.setNormalArray(cloneArray(geometry.getNormalArray(), vbo, &geometry));
if(geometry->getTexCoordArray(7) && geometry->getTexCoordArray(7)->referenceCount() > 1) // tangents if(geometry.getTexCoordArray(7) && geometry.getTexCoordArray(7)->referenceCount() > 1) // tangents
geometry->setTexCoordArray(7, cloneArray(geometry->getTexCoordArray(7), vbo, geometry)); geometry.setTexCoordArray(7, cloneArray(geometry.getTexCoordArray(7), vbo, &geometry));
} }
_drawableSet.insert(&geometry);
}
void Optimizer::FlattenStaticTransformsVisitor::apply(osg::Drawable& drawable)
{
_drawableSet.insert(&drawable); _drawableSet.insert(&drawable);
} }
@ -673,6 +691,11 @@ void Optimizer::FlattenStaticTransformsVisitor::apply(osg::Transform& transform)
_transformStack.pop_back(); _transformStack.pop_back();
} }
void Optimizer::FlattenStaticTransformsVisitor::apply(osg::MatrixTransform& transform)
{
apply(static_cast<osg::Transform&>(transform));
}
bool Optimizer::FlattenStaticTransformsVisitor::removeTransforms(osg::Node* nodeWeCannotRemove) bool Optimizer::FlattenStaticTransformsVisitor::removeTransforms(osg::Node* nodeWeCannotRemove)
{ {
CollectLowestTransformsVisitor cltv(_optimizer); CollectLowestTransformsVisitor cltv(_optimizer);
@ -1112,10 +1135,13 @@ bool isAbleToMerge(const osg::Geometry& g1, const osg::Geometry& g2)
} }
void Optimizer::MergeGeometryVisitor::pushStateSet(osg::StateSet *stateSet) bool Optimizer::MergeGeometryVisitor::pushStateSet(osg::StateSet *stateSet)
{ {
if (_mergeAlphaBlending || !stateSet || stateSet->getRenderBinMode() & osg::StateSet::INHERIT_RENDERBIN_DETAILS)
return false;
_stateSetStack.push_back(stateSet); _stateSetStack.push_back(stateSet);
checkAlphaBlendingActive(); checkAlphaBlendingActive();
return true;
} }
void Optimizer::MergeGeometryVisitor::popStateSet() void Optimizer::MergeGeometryVisitor::popStateSet()
@ -1145,15 +1171,14 @@ void Optimizer::MergeGeometryVisitor::checkAlphaBlendingActive()
void Optimizer::MergeGeometryVisitor::apply(osg::Group &group) void Optimizer::MergeGeometryVisitor::apply(osg::Group &group)
{ {
if (group.getStateSet()) bool pushed = pushStateSet(group.getStateSet());
pushStateSet(group.getStateSet());
if (!_alphaBlendingActive || _mergeAlphaBlending) if (!_alphaBlendingActive || _mergeAlphaBlending)
mergeGroup(group); mergeGroup(group);
traverse(group); traverse(group);
if (group.getStateSet()) if (pushed)
popStateSet(); popStateSet();
} }

View file

@ -285,9 +285,11 @@ class Optimizer
BaseOptimizerVisitor(optimizer, FLATTEN_STATIC_TRANSFORMS) {} BaseOptimizerVisitor(optimizer, FLATTEN_STATIC_TRANSFORMS) {}
void apply(osg::Node& geode) override; void apply(osg::Node& geode) override;
void apply(osg::Geometry& drawable) override;
void apply(osg::Drawable& drawable) override; void apply(osg::Drawable& drawable) override;
void apply(osg::Billboard& geode) override; void apply(osg::Billboard& geode) override;
void apply(osg::Transform& transform) override; void apply(osg::Transform& transform) override final;
void apply(osg::MatrixTransform& transform) override;
bool removeTransforms(osg::Node* nodeWeCannotRemove); bool removeTransforms(osg::Node* nodeWeCannotRemove);
@ -316,6 +318,7 @@ class Optimizer
BaseOptimizerVisitor(optimizer, FLATTEN_STATIC_TRANSFORMS) {} BaseOptimizerVisitor(optimizer, FLATTEN_STATIC_TRANSFORMS) {}
void apply(osg::MatrixTransform& transform) override; void apply(osg::MatrixTransform& transform) override;
void apply(osg::Geometry&) override { }
bool removeTransforms(osg::Node* nodeWeCannotRemove); bool removeTransforms(osg::Node* nodeWeCannotRemove);
@ -338,6 +341,7 @@ class Optimizer
BaseOptimizerVisitor(optimizer, REMOVE_REDUNDANT_NODES) {} BaseOptimizerVisitor(optimizer, REMOVE_REDUNDANT_NODES) {}
void apply(osg::Group& group) override; void apply(osg::Group& group) override;
void apply(osg::Geometry&) override { }
void removeEmptyNodes(); void removeEmptyNodes();
@ -358,6 +362,7 @@ class Optimizer
void apply(osg::Transform& transform) override; void apply(osg::Transform& transform) override;
void apply(osg::LOD& lod) override; void apply(osg::LOD& lod) override;
void apply(osg::Switch& switchNode) override; void apply(osg::Switch& switchNode) override;
void apply(osg::Geometry&) override { }
bool isOperationPermissible(osg::Node& node); bool isOperationPermissible(osg::Node& node);
@ -376,6 +381,7 @@ class Optimizer
bool isOperationPermissible(osg::Group& node); bool isOperationPermissible(osg::Group& node);
void apply(osg::Geometry&) override { }
void apply(osg::Group& group) override; void apply(osg::Group& group) override;
void apply(osg::LOD& lod) override; void apply(osg::LOD& lod) override;
void apply(osg::Switch& switchNode) override; void apply(osg::Switch& switchNode) override;
@ -409,10 +415,10 @@ class Optimizer
return _targetMaximumNumberOfVertices; return _targetMaximumNumberOfVertices;
} }
void pushStateSet(osg::StateSet* stateSet); bool pushStateSet(osg::StateSet* stateSet);
void popStateSet(); void popStateSet();
void checkAlphaBlendingActive(); void checkAlphaBlendingActive();
void apply(osg::Geometry&) override { }
void apply(osg::Group& group) override; void apply(osg::Group& group) override;
void apply(osg::Billboard&) override { /* don't do anything*/ } void apply(osg::Billboard&) override { /* don't do anything*/ }