Bug 1783717 - Faster allocation of TexturePacker children. r=aosmond,gfx-reviewers

Rather than allocating TexturePacker children individually, allocate an array
of all the children at once to cut the number of memory allocations in half.

Depends on D154118

Differential Revision: https://phabricator.services.mozilla.com/D154182
This commit is contained in:
Lee Salzman 2022-08-10 02:57:26 +00:00
Родитель 119e3df4ef
Коммит 681687a77b
2 изменённых файлов: 41 добавлений и 42 удалений

Просмотреть файл

@ -24,7 +24,7 @@
namespace mozilla::gfx {
// Inserts (allocated) a rectangle of the requested size into the tree.
// Inserts (allocates) a rectangle of the requested size into the tree.
Maybe<IntPoint> TexturePacker::Insert(const IntSize& aSize) {
// Check if the available space could possibly fit the requested size. If
// not, there is no reason to continue searching within this sub-tree.
@ -32,17 +32,17 @@ Maybe<IntPoint> TexturePacker::Insert(const IntSize& aSize) {
mBounds.width < aSize.width || mBounds.height < aSize.height) {
return Nothing();
}
if (mChildren[0]) {
if (mChildren) {
// If this node has children, then try to insert into each of the children
// in turn.
Maybe<IntPoint> inserted = mChildren[0]->Insert(aSize);
Maybe<IntPoint> inserted = mChildren[0].Insert(aSize);
if (!inserted) {
inserted = mChildren[1]->Insert(aSize);
inserted = mChildren[1].Insert(aSize);
}
// If the insertion succeeded, adjust the available state to reflect the
// remaining space in the children.
if (inserted) {
mAvailable = std::max(mChildren[0]->mAvailable, mChildren[1]->mAvailable);
mAvailable = std::max(mChildren[0].mAvailable, mChildren[1].mAvailable);
if (!mAvailable) {
DiscardChildren();
}
@ -60,29 +60,29 @@ Maybe<IntPoint> TexturePacker::Insert(const IntSize& aSize) {
// most excess space beyond the requested size and split it so that at least
// one of the children matches the requested size for that axis.
if (mBounds.width - aSize.width > mBounds.height - aSize.height) {
mChildren[0].reset(new TexturePacker(
IntRect(mBounds.x, mBounds.y, aSize.width, mBounds.height)));
mChildren[1].reset(new TexturePacker(
IntRect(mBounds.x + aSize.width, mBounds.y, mBounds.width - aSize.width,
mBounds.height)));
mChildren.reset(new TexturePacker[2]{
TexturePacker(
IntRect(mBounds.x, mBounds.y, aSize.width, mBounds.height)),
TexturePacker(IntRect(mBounds.x + aSize.width, mBounds.y,
mBounds.width - aSize.width, mBounds.height))});
} else {
mChildren[0].reset(new TexturePacker(
IntRect(mBounds.x, mBounds.y, mBounds.width, aSize.height)));
mChildren[1].reset(new TexturePacker(
IntRect(mBounds.x, mBounds.y + aSize.height, mBounds.width,
mBounds.height - aSize.height)));
mChildren.reset(new TexturePacker[2]{
TexturePacker(
IntRect(mBounds.x, mBounds.y, mBounds.width, aSize.height)),
TexturePacker(IntRect(mBounds.x, mBounds.y + aSize.height,
mBounds.width, mBounds.height - aSize.height))});
}
// After splitting, try to insert into the first child, which should usually
// be big enough to accomodate the request. Adjust the available state to the
// remaining space.
Maybe<IntPoint> inserted = mChildren[0]->Insert(aSize);
mAvailable = std::max(mChildren[0]->mAvailable, mChildren[1]->mAvailable);
Maybe<IntPoint> inserted = mChildren[0].Insert(aSize);
mAvailable = std::max(mChildren[0].mAvailable, mChildren[1].mAvailable);
return inserted;
}
// Removes (frees) a rectangle with the given bounds from the tree.
bool TexturePacker::Remove(const IntRect& aBounds) {
if (!mChildren[0]) {
if (!mChildren) {
// If there are no children, we encountered a leaf node. Non-zero available
// state means that this node was already removed previously. Also, if the
// bounds don't contain the request, and assuming the tree was previously
@ -107,22 +107,24 @@ bool TexturePacker::Remove(const IntRect& aBounds) {
int split = aBounds.x - mBounds.x > mBounds.XMost() - aBounds.XMost()
? aBounds.x
: aBounds.XMost();
mChildren[0].reset(new TexturePacker(
IntRect(mBounds.x, mBounds.y, split - mBounds.x, mBounds.height),
false));
mChildren[1].reset(new TexturePacker(
IntRect(split, mBounds.y, mBounds.XMost() - split, mBounds.height),
false));
mChildren.reset(new TexturePacker[2]{
TexturePacker(
IntRect(mBounds.x, mBounds.y, split - mBounds.x, mBounds.height),
false),
TexturePacker(IntRect(split, mBounds.y, mBounds.XMost() - split,
mBounds.height),
false)});
} else {
int split = aBounds.y - mBounds.y > mBounds.YMost() - aBounds.YMost()
? aBounds.y
: aBounds.YMost();
mChildren[0].reset(new TexturePacker(
IntRect(mBounds.x, mBounds.y, mBounds.width, split - mBounds.y),
false));
mChildren[1].reset(new TexturePacker(
IntRect(mBounds.x, split, mBounds.width, mBounds.YMost() - split),
false));
mChildren.reset(new TexturePacker[2]{
TexturePacker(
IntRect(mBounds.x, mBounds.y, mBounds.width, split - mBounds.y),
false),
TexturePacker(
IntRect(mBounds.x, split, mBounds.width, mBounds.YMost() - split),
false)});
}
}
// We've encountered a branch node. Determine which of the two child nodes
@ -130,16 +132,16 @@ bool TexturePacker::Remove(const IntRect& aBounds) {
// children were split on and then whether the removed bounds on that axis
// are past the start of the second child. Proceed to recurse into that
// child node for removal.
bool next = mChildren[0]->mBounds.x < mChildren[1]->mBounds.x
? aBounds.x >= mChildren[1]->mBounds.x
: aBounds.y >= mChildren[1]->mBounds.y;
bool removed = mChildren[next ? 1 : 0]->Remove(aBounds);
bool next = mChildren[0].mBounds.x < mChildren[1].mBounds.x
? aBounds.x >= mChildren[1].mBounds.x
: aBounds.y >= mChildren[1].mBounds.y;
bool removed = mChildren[next ? 1 : 0].Remove(aBounds);
if (removed) {
if (mChildren[0]->IsFullyAvailable() && mChildren[1]->IsFullyAvailable()) {
if (mChildren[0].IsFullyAvailable() && mChildren[1].IsFullyAvailable()) {
DiscardChildren();
mAvailable = std::min(mBounds.width, mBounds.height);
} else {
mAvailable = std::max(mChildren[0]->mAvailable, mChildren[1]->mAvailable);
mAvailable = std::max(mChildren[0].mAvailable, mChildren[1].mAvailable);
}
}
return removed;

Просмотреть файл

@ -31,17 +31,14 @@ class TexturePacker {
const IntRect& GetBounds() const { return mBounds; }
private:
bool IsLeaf() const { return !mChildren[0]; }
bool IsLeaf() const { return !mChildren; }
bool IsFullyAvailable() const { return IsLeaf() && mAvailable > 0; }
void DiscardChildren() {
mChildren[0] = nullptr;
mChildren[1] = nullptr;
}
void DiscardChildren() { mChildren.reset(); }
// If applicable, the two children produced by picking a single axis split
// within the node's bounds and subdividing the bounds there.
UniquePtr<TexturePacker> mChildren[2];
UniquePtr<TexturePacker[]> mChildren;
// The bounds enclosing this node and any children within it.
IntRect mBounds;
// For a leaf node, specifies the size of the smallest dimension available to