Browse Source

SceneTools: make orderClusterParents() use one allocation instead of 4.

Mmm. I wonder how much will future mosra hate me for making this code so
obfuscated.
pull/542/merge
Vladimír Vondruš 4 years ago
parent
commit
eb2e4ff25d
  1. 31
      src/Magnum/SceneTools/OrderClusterParents.cpp

31
src/Magnum/SceneTools/OrderClusterParents.cpp

@ -26,6 +26,7 @@
#include "OrderClusterParents.h" #include "OrderClusterParents.h"
#include <Corrade/Containers/Array.h> #include <Corrade/Containers/Array.h>
#include <Corrade/Containers/ArrayTuple.h>
#include <Corrade/Containers/Optional.h> #include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/Pair.h> #include <Corrade/Containers/Pair.h>
@ -45,7 +46,6 @@ Containers::Array<Containers::Pair<UnsignedInt, Int>> orderClusterParents(const
} }
void orderClusterParentsInto(const Trade::SceneData& scene, const Containers::StridedArrayView1D<UnsignedInt>& mappingDestination, const Containers::StridedArrayView1D<Int>& parentDestination) { void orderClusterParentsInto(const Trade::SceneData& scene, const Containers::StridedArrayView1D<UnsignedInt>& mappingDestination, const Containers::StridedArrayView1D<Int>& parentDestination) {
#ifndef CORRADE_NO_ASSERT
const Containers::Optional<UnsignedInt> parentFieldId = scene.findFieldId(Trade::SceneField::Parent); const Containers::Optional<UnsignedInt> parentFieldId = scene.findFieldId(Trade::SceneField::Parent);
CORRADE_ASSERT(parentFieldId, CORRADE_ASSERT(parentFieldId,
"SceneTools::orderClusterParentsInto(): the scene has no hierarchy", ); "SceneTools::orderClusterParentsInto(): the scene has no hierarchy", );
@ -54,15 +54,34 @@ void orderClusterParentsInto(const Trade::SceneData& scene, const Containers::St
"SceneTools::orderClusterParentsInto(): expected mapping destination view with" << parentFieldSize << "elements but got" << mappingDestination.size(), ); "SceneTools::orderClusterParentsInto(): expected mapping destination view with" << parentFieldSize << "elements but got" << mappingDestination.size(), );
CORRADE_ASSERT(parentDestination.size() == scene.fieldSize(*parentFieldId), CORRADE_ASSERT(parentDestination.size() == scene.fieldSize(*parentFieldId),
"SceneTools::orderClusterParentsInto(): expected parent destination view with" << parentFieldSize << "elements but got" << parentDestination.size(), ); "SceneTools::orderClusterParentsInto(): expected parent destination view with" << parentFieldSize << "elements but got" << parentDestination.size(), );
#endif
/* Convert the parent list to a child list to sort them toplogically */ /* Allocate a single storage for all temporary data */
const Containers::Array<Containers::Pair<UnsignedInt, Int>> parents = scene.parentsAsArray(); Containers::ArrayView<Containers::Pair<UnsignedInt, Int>> parents;
Containers::ArrayView<UnsignedInt> childrenOffsets;
Containers::ArrayView<UnsignedInt> children;
Containers::ArrayView<Int> parentsToProcess;
Containers::ArrayTuple storage{
/* Output of scene.parentsInto() */
{NoInit, parentFieldSize, parents},
/* Running children offset (+1) for each node including root (+1), plus
one more element when we shift the array by one below */
{ValueInit, std::size_t(scene.mappingBound() + 3), childrenOffsets},
{NoInit, parentFieldSize, children},
/* List of parents to process. Can't reuse mappingDestination because
this includes one more element for root objects. */
{NoInit, parentFieldSize + 1, parentsToProcess}
};
/* Convert the parent list to a child list to sort them toplogically.
Explicit slice() template parameters needed by GCC 4.8 and MSVC 2015 */
scene.parentsInto(
stridedArrayView(parents).slice<UnsignedInt>(&Containers::Pair<UnsignedInt, Int>::first),
stridedArrayView(parents).slice<Int>(&Containers::Pair<UnsignedInt, Int>::second)
);
/* Children offset for each node including root. First calculate the count /* Children offset for each node including root. First calculate the count
of children for each, skipping the first element (parent.second() can be of children for each, skipping the first element (parent.second() can be
-1, accounting for that as well)... */ -1, accounting for that as well)... */
Containers::Array<UnsignedInt> childrenOffsets{DirectInit, scene.mappingBound() + 3, 0u};
for(const Containers::Pair<UnsignedInt, Int>& parent: parents) { for(const Containers::Pair<UnsignedInt, Int>& parent: parents) {
CORRADE_INTERNAL_ASSERT(parent.first() < scene.mappingBound() && (parent.second() == -1 || UnsignedInt(parent.second()) < scene.mappingBound())); CORRADE_INTERNAL_ASSERT(parent.first() < scene.mappingBound() && (parent.second() == -1 || UnsignedInt(parent.second()) < scene.mappingBound()));
++childrenOffsets[parent.second() + 2]; ++childrenOffsets[parent.second() + 2];
@ -84,7 +103,6 @@ void orderClusterParentsInto(const Trade::SceneData& scene, const Containers::St
now `[childrenOffsets[i + 1], childrenOffsets[i + 2])` contains a range now `[childrenOffsets[i + 1], childrenOffsets[i + 2])` contains a range
in which the `children` array below contains a list of children for in which the `children` array below contains a list of children for
`i`. */ `i`. */
Containers::Array<UnsignedInt> children{NoInit, parents.size()};
for(const Containers::Pair<UnsignedInt, Int>& parent: parents) for(const Containers::Pair<UnsignedInt, Int>& parent: parents)
children[childrenOffsets[parent.second() + 2]++] = parent.first(); children[childrenOffsets[parent.second() + 2]++] = parent.first();
@ -92,7 +110,6 @@ void orderClusterParentsInto(const Trade::SceneData& scene, const Containers::St
other) and build a list of (id, parent id) where a parent is always other) and build a list of (id, parent id) where a parent is always
before its children */ before its children */
std::size_t outputOffset = 0; std::size_t outputOffset = 0;
Containers::Array<Int> parentsToProcess{NoInit, parents.size() + 1};
parentsToProcess[0] = -1; parentsToProcess[0] = -1;
for(std::size_t i = 0; i != outputOffset + 1; ++i) { for(std::size_t i = 0; i != outputOffset + 1; ++i) {
const Int objectId = parentsToProcess[i]; const Int objectId = parentsToProcess[i];

Loading…
Cancel
Save