Merge branch 'optimize_merge_geometry' into 'master'

Optimize geometry merging

See merge request OpenMW/openmw!4086
i-have-no-land-and-i-must-scream
psi29a 8 months ago
commit 1cde82201e

@ -38,6 +38,7 @@
#include <numeric>
#include <iterator>
#include <cassert>
#include <components/sceneutil/depth.hpp>
@ -1197,6 +1198,67 @@ bool containsSharedPrimitives(const osg::Geometry* geom)
return false;
}
// clang-format on
namespace
{
unsigned getArraySizeOrZero(const osg::Array* array)
{
return array == nullptr ? 0 : array->getNumElements();
}
void fillArraySizes(const std::vector<osg::ref_ptr<osg::Array>>& arrays, std::vector<unsigned>& sizes)
{
sizes.reserve(arrays.size());
for (const auto& array : arrays)
sizes.push_back(getArraySizeOrZero(array));
}
void initArraySizes(const osg::Geometry& geometry, Optimizer::GeometryArraySizes& sizes)
{
sizes.mVertex = getArraySizeOrZero(geometry.getVertexArray());
sizes.mNormal = getArraySizeOrZero(geometry.getNormalArray());
sizes.mColor = getArraySizeOrZero(geometry.getColorArray());
sizes.mSecondaryColor = getArraySizeOrZero(geometry.getSecondaryColorArray());
sizes.mFogCoord = getArraySizeOrZero(geometry.getFogCoordArray());
sizes.mTexCoord.clear();
sizes.mVertexAttrib.clear();
fillArraySizes(geometry.getTexCoordArrayList(), sizes.mTexCoord);
fillArraySizes(geometry.getVertexAttribArrayList(), sizes.mVertexAttrib);
}
void addArraySize(const osg::Array* array, unsigned& size)
{
if (array != nullptr)
size += array->getNumElements();
}
void addArraySizes(const std::vector<osg::ref_ptr<osg::Array>>& dst,
const std::vector<osg::ref_ptr<osg::Array>>& src, std::vector<unsigned>& sizes)
{
assert(sizes.size() == dst.size());
for (std::size_t i = 0, n = std::min(dst.size(), src.size()); i < n; ++i)
if (osg::Array* const array = src[i])
sizes[i] += array->getNumElements();
}
void addArraysSizes(const osg::Geometry& dst, const osg::Geometry& src, Optimizer::GeometryArraySizes& sizes)
{
addArraySize(src.getVertexArray(), sizes.mVertex);
addArraySize(src.getNormalArray(), sizes.mNormal);
addArraySize(src.getColorArray(), sizes.mColor);
addArraySize(src.getSecondaryColorArray(), sizes.mSecondaryColor);
addArraySize(src.getFogCoordArray(), sizes.mFogCoord);
addArraySizes(dst.getTexCoordArrayList(), src.getTexCoordArrayList(), sizes.mTexCoord);
addArraySizes(dst.getVertexAttribArrayList(), src.getVertexAttribArrayList(), sizes.mVertexAttrib);
}
}
// clang-format off
bool Optimizer::MergeGeometryVisitor::mergeGroup(osg::Group& group)
{
if (!isOperationPermissibleForObject(&group)) return false;
@ -1346,6 +1408,9 @@ bool Optimizer::MergeGeometryVisitor::mergeGroup(osg::Group& group)
group.addChild(*itr);
}
// Place outside the loop to keep vectors allocated
GeometryArraySizes sizes;
// now do the merging of geometries
for(MergeList::iterator mitr = mergeList.begin();
mitr != mergeList.end();
@ -1362,12 +1427,18 @@ bool Optimizer::MergeGeometryVisitor::mergeGroup(osg::Group& group)
}
DuplicateList::iterator ditr = duplicateList.begin();
osg::ref_ptr<osg::Geometry> lhs = *ditr++;
initArraySizes(*lhs, sizes);
for (auto it = ditr; it != duplicateList.end(); ++it)
addArraysSizes(*lhs, **it, sizes);
group.addChild(lhs.get());
for(;
ditr != duplicateList.end();
++ditr)
{
mergeGeometry(*lhs, **ditr);
mergeGeometry(*lhs, **ditr, sizes);
}
}
}
@ -1665,7 +1736,7 @@ class MergeArrayVisitor : public osg::ArrayVisitor
void apply(osg::Vec4sArray& rhs) override { _merge(rhs); }
};
bool Optimizer::MergeGeometryVisitor::mergeGeometry(osg::Geometry& lhs,osg::Geometry& rhs)
bool Optimizer::MergeGeometryVisitor::mergeGeometry(osg::Geometry& lhs, osg::Geometry& rhs, const GeometryArraySizes& sizes)
{
MergeArrayVisitor merger;
osg::VertexBufferObject* vbo = nullptr;
@ -1675,6 +1746,7 @@ bool Optimizer::MergeGeometryVisitor::mergeGeometry(osg::Geometry& lhs,osg::Geom
base = lhs.getVertexArray()->getNumElements();
if (lhs.getVertexArray()->referenceCount() > 1)
lhs.setVertexArray(cloneArray(lhs.getVertexArray(), vbo, &lhs));
lhs.getVertexArray()->reserveArray(sizes.mVertex);
if (!merger.merge(lhs.getVertexArray(),rhs.getVertexArray()))
{
OSG_DEBUG << "MergeGeometry: vertex array not merged. Some data may be lost." <<std::endl;
@ -1691,6 +1763,7 @@ bool Optimizer::MergeGeometryVisitor::mergeGeometry(osg::Geometry& lhs,osg::Geom
{
if (lhs.getNormalArray()->referenceCount() > 1)
lhs.setNormalArray(cloneArray(lhs.getNormalArray(), vbo, &lhs));
lhs.getNormalArray()->reserveArray(sizes.mNormal);
if (!merger.merge(lhs.getNormalArray(),rhs.getNormalArray()))
{
OSG_DEBUG << "MergeGeometry: normal array not merged. Some data may be lost." <<std::endl;
@ -1706,6 +1779,7 @@ bool Optimizer::MergeGeometryVisitor::mergeGeometry(osg::Geometry& lhs,osg::Geom
{
if (lhs.getColorArray()->referenceCount() > 1)
lhs.setColorArray(cloneArray(lhs.getColorArray(), vbo, &lhs));
lhs.getColorArray()->reserveArray(sizes.mColor);
if (!merger.merge(lhs.getColorArray(),rhs.getColorArray()))
{
OSG_DEBUG << "MergeGeometry: color array not merged. Some data may be lost." <<std::endl;
@ -1720,6 +1794,7 @@ bool Optimizer::MergeGeometryVisitor::mergeGeometry(osg::Geometry& lhs,osg::Geom
{
if (lhs.getSecondaryColorArray()->referenceCount() > 1)
lhs.setSecondaryColorArray(cloneArray(lhs.getSecondaryColorArray(), vbo, &lhs));
lhs.getSecondaryColorArray()->reserveArray(static_cast<unsigned>(sizes.mSecondaryColor));
if (!merger.merge(lhs.getSecondaryColorArray(),rhs.getSecondaryColorArray()))
{
OSG_DEBUG << "MergeGeometry: secondary color array not merged. Some data may be lost." <<std::endl;
@ -1734,6 +1809,7 @@ bool Optimizer::MergeGeometryVisitor::mergeGeometry(osg::Geometry& lhs,osg::Geom
{
if (lhs.getFogCoordArray()->referenceCount() > 1)
lhs.setFogCoordArray(cloneArray(lhs.getFogCoordArray(), vbo, &lhs));
lhs.getFogCoordArray()->reserveArray(sizes.mFogCoord);
if (!merger.merge(lhs.getFogCoordArray(),rhs.getFogCoordArray()))
{
OSG_DEBUG << "MergeGeometry: fog coord array not merged. Some data may be lost." <<std::endl;
@ -1751,7 +1827,9 @@ bool Optimizer::MergeGeometryVisitor::mergeGeometry(osg::Geometry& lhs,osg::Geom
if (!lhs.getTexCoordArray(unit)) continue;
if (lhs.getTexCoordArray(unit)->referenceCount() > 1)
lhs.setTexCoordArray(unit, cloneArray(lhs.getTexCoordArray(unit), vbo, &lhs));
if (!merger.merge(lhs.getTexCoordArray(unit),rhs.getTexCoordArray(unit)))
osg::Array* const lhsArray = lhs.getTexCoordArray(unit);
lhsArray->reserveArray(sizes.mTexCoord[unit]);
if (!merger.merge(lhsArray, rhs.getTexCoordArray(unit)))
{
OSG_DEBUG << "MergeGeometry: tex coord array not merged. Some data may be lost." <<std::endl;
}
@ -1762,7 +1840,9 @@ bool Optimizer::MergeGeometryVisitor::mergeGeometry(osg::Geometry& lhs,osg::Geom
if (!lhs.getVertexAttribArray(unit)) continue;
if (lhs.getVertexAttribArray(unit)->referenceCount() > 1)
lhs.setVertexAttribArray(unit, cloneArray(lhs.getVertexAttribArray(unit), vbo, &lhs));
if (!merger.merge(lhs.getVertexAttribArray(unit),rhs.getVertexAttribArray(unit)))
osg::Array* const lhsArray = lhs.getVertexAttribArray(unit);
lhsArray->reserveArray(sizes.mVertexAttrib[unit]);
if (!merger.merge(lhsArray, rhs.getVertexAttribArray(unit)))
{
OSG_DEBUG << "MergeGeometry: vertex attrib array not merged. Some data may be lost." <<std::endl;
}

@ -390,6 +390,17 @@ class Optimizer
void apply(osg::Sequence& sequenceNode) override;
};
struct GeometryArraySizes
{
unsigned mVertex = 0;
unsigned mNormal = 0;
unsigned mColor = 0;
unsigned mSecondaryColor = 0;
unsigned mFogCoord = 0;
std::vector<unsigned> mTexCoord;
std::vector<unsigned> mVertexAttrib;
};
class MergeGeometryVisitor : public BaseOptimizerVisitor
{
public:
@ -427,7 +438,7 @@ class Optimizer
bool mergeGroup(osg::Group& group);
static bool mergeGeometry(osg::Geometry& lhs,osg::Geometry& rhs);
static bool mergeGeometry(osg::Geometry& lhs, osg::Geometry& rhs, const GeometryArraySizes& sizes);
static bool mergePrimitive(osg::DrawArrays& lhs,osg::DrawArrays& rhs);
static bool mergePrimitive(osg::DrawArrayLengths& lhs,osg::DrawArrayLengths& rhs);

Loading…
Cancel
Save