diff --git a/components/sceneutil/optimizer.cpp b/components/sceneutil/optimizer.cpp index 2646291053..7822f17448 100644 --- a/components/sceneutil/optimizer.cpp +++ b/components/sceneutil/optimizer.cpp @@ -38,6 +38,7 @@ #include #include +#include #include @@ -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>& arrays, std::vector& 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>& dst, + const std::vector>& src, std::vector& 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 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." <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." <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." <referenceCount() > 1) lhs.setSecondaryColorArray(cloneArray(lhs.getSecondaryColorArray(), vbo, &lhs)); + lhs.getSecondaryColorArray()->reserveArray(static_cast(sizes.mSecondaryColor)); if (!merger.merge(lhs.getSecondaryColorArray(),rhs.getSecondaryColorArray())) { OSG_DEBUG << "MergeGeometry: secondary color array not merged. Some data may be lost." <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." <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." <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." < mTexCoord; + std::vector 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);