Bug 1351426 - Part 3: Refactor BSPTree to use list instead of deque and use arena for memory allocations r=kip

MozReview-Commit-ID: F4ezRzbGihI

--HG--
extra : rebase_source : 85c91cac817a733e5b062285d4951996270feabf
This commit is contained in:
Miko Mynttinen 2017-04-10 16:35:56 +02:00
parent 496fccc821
commit ec2807c91a
4 changed files with 76 additions and 48 deletions

View File

@ -9,21 +9,14 @@
namespace mozilla {
namespace layers {
LayerPolygon PopFront(std::deque<LayerPolygon>& aLayers)
{
LayerPolygon layer = Move(aLayers.front());
aLayers.pop_front();
return layer;
}
void
BSPTree::BuildDrawOrder(const UniquePtr<BSPTreeNode>& aNode,
BSPTree::BuildDrawOrder(BSPTreeNode* aNode,
nsTArray<LayerPolygon>& aLayers) const
{
const gfx::Point4D& normal = aNode->First().GetNormal();
UniquePtr<BSPTreeNode> *front = &aNode->front;
UniquePtr<BSPTreeNode> *back = &aNode->back;
BSPTreeNode* front = aNode->front;
BSPTreeNode* back = aNode->back;
// Since the goal is to return the draw order from back to front, we reverse
// the traversal order if the current polygon is facing towards the camera.
@ -33,8 +26,8 @@ BSPTree::BuildDrawOrder(const UniquePtr<BSPTreeNode>& aNode,
std::swap(front, back);
}
if (*front) {
BuildDrawOrder(*front, aLayers);
if (front) {
BuildDrawOrder(front, aLayers);
}
for (LayerPolygon& layer : aNode->layers) {
@ -45,22 +38,27 @@ BSPTree::BuildDrawOrder(const UniquePtr<BSPTreeNode>& aNode,
}
}
if (*back) {
BuildDrawOrder(*back, aLayers);
if (back) {
BuildDrawOrder(back, aLayers);
}
}
void
BSPTree::BuildTree(UniquePtr<BSPTreeNode>& aRoot,
std::deque<LayerPolygon>& aLayers)
BSPTree::BuildTree(BSPTreeNode* aRoot,
std::list<LayerPolygon>& aLayers)
{
MOZ_ASSERT(!aLayers.empty());
aRoot->layers.push_back(Move(aLayers.front()));
aLayers.pop_front();
if (aLayers.empty()) {
return;
}
const gfx::Polygon& plane = aRoot->First();
std::deque<LayerPolygon> backLayers, frontLayers;
std::list<LayerPolygon> backLayers, frontLayers;
for (LayerPolygon& layerPolygon : aLayers) {
const Maybe<gfx::Polygon>& geometry = layerPolygon.geometry;
@ -88,22 +86,22 @@ BSPTree::BuildTree(UniquePtr<BSPTreeNode>& aRoot,
Layer *layer = layerPolygon.layer;
if (backPoints.Length() >= 3) {
backLayers.push_back(LayerPolygon(layer, Move(backPoints), normal));
backLayers.emplace_back(layer, Move(backPoints), normal);
}
if (frontPoints.Length() >= 3) {
frontLayers.push_back(LayerPolygon(layer, Move(frontPoints), normal));
frontLayers.emplace_back(layer, Move(frontPoints), normal);
}
}
}
if (!backLayers.empty()) {
aRoot->back.reset(new BSPTreeNode(PopFront(backLayers)));
aRoot->back = new (mPool) BSPTreeNode(mListPointers);
BuildTree(aRoot->back, backLayers);
}
if (!frontLayers.empty()) {
aRoot->front.reset(new BSPTreeNode(PopFront(frontLayers)));
aRoot->front = new (mPool) BSPTreeNode(mListPointers);
BuildTree(aRoot->front, frontLayers);
}
}

View File

@ -6,12 +6,13 @@
#ifndef MOZILLA_LAYERS_BSPTREE_H
#define MOZILLA_LAYERS_BSPTREE_H
#include "mozilla/ArenaAllocator.h"
#include "mozilla/gfx/Polygon.h"
#include "mozilla/Move.h"
#include "mozilla/UniquePtr.h"
#include "nsTArray.h"
#include <deque>
#include <list>
namespace mozilla {
namespace layers {
@ -25,37 +26,59 @@ struct LayerPolygon {
LayerPolygon(Layer *aLayer,
gfx::Polygon&& aGeometry)
: layer(aLayer), geometry(Some(aGeometry)) {}
: layer(aLayer), geometry(Some(Move(aGeometry))) {}
LayerPolygon(Layer *aLayer,
nsTArray<gfx::Point4D>&& aPoints,
const gfx::Point4D& aNormal)
: layer(aLayer), geometry(Some(gfx::Polygon(Move(aPoints), aNormal))) {}
: layer(aLayer)
{
geometry.emplace(Move(aPoints), aNormal);
}
Layer *layer;
Maybe<gfx::Polygon> geometry;
};
LayerPolygon PopFront(std::deque<LayerPolygon>& aLayers);
/**
* Allocate BSPTreeNodes from a memory arena to improve performance with
* complex scenes.
* The arena size of 4096 bytes was selected as an arbitrary power of two.
* Depending on the platform, this size accommodates roughly 100 BSPTreeNodes.
*/
typedef mozilla::ArenaAllocator<4096, 8> BSPTreeArena;
/**
* Aliases the container type used to store layers within BSPTreeNodes.
*/
typedef std::list<LayerPolygon> LayerList;
// Represents a node in a BSP tree. The node contains at least one layer with
// associated geometry that is used as a splitting plane, and at most two child
// nodes that represent the splitting planes that further subdivide the space.
struct BSPTreeNode {
explicit BSPTreeNode(LayerPolygon&& layer)
explicit BSPTreeNode(nsTArray<LayerList*>& aListPointers)
: front(nullptr), back(nullptr)
{
layers.push_back(Move(layer));
// Store the layer list pointer to free memory when BSPTree is destroyed.
aListPointers.AppendElement(&layers);
}
const gfx::Polygon& First() const
{
MOZ_ASSERT(layers[0].geometry);
return *layers[0].geometry;
MOZ_ASSERT(!layers.empty());
MOZ_ASSERT(layers.front().geometry);
return *layers.front().geometry;
}
UniquePtr<BSPTreeNode> front;
UniquePtr<BSPTreeNode> back;
std::deque<LayerPolygon> layers;
static void* operator new(size_t aSize, BSPTreeArena& mPool)
{
return mPool.Allocate(aSize);
}
BSPTreeNode* front;
BSPTreeNode* back;
LayerList layers;
};
// BSPTree class takes a list of layers as an input and uses binary space
@ -67,19 +90,23 @@ struct BSPTreeNode {
// ftp://ftp.sgi.com/other/bspfaq/faq/bspfaq.html
class BSPTree {
public:
// This constructor takes the ownership of layers in the given list.
explicit BSPTree(std::deque<LayerPolygon>& aLayers)
/**
* The constructor modifies layers in the given list.
*/
explicit BSPTree(std::list<LayerPolygon>& aLayers)
{
MOZ_ASSERT(!aLayers.empty());
mRoot.reset(new BSPTreeNode(PopFront(aLayers)));
mRoot = new (mPool) BSPTreeNode(mListPointers);
BuildTree(mRoot, aLayers);
}
// Returns the root node of the BSP tree.
const UniquePtr<BSPTreeNode>& GetRoot() const
~BSPTree()
{
return mRoot;
for (LayerList* listPtr : mListPointers) {
listPtr->~LayerList();
}
}
// Builds and returns the back-to-front draw order for the created BSP tree.
@ -91,14 +118,17 @@ public:
}
private:
UniquePtr<BSPTreeNode> mRoot;
BSPTreeArena mPool;
BSPTreeNode* mRoot;
nsTArray<LayerList*> mListPointers;
// BuildDrawOrder and BuildTree are called recursively. The depth of the
// recursion depends on the amount of polygons and their intersections.
void BuildDrawOrder(const UniquePtr<BSPTreeNode>& aNode,
void BuildDrawOrder(BSPTreeNode* aNode,
nsTArray<LayerPolygon>& aLayers) const;
void BuildTree(UniquePtr<BSPTreeNode>& aRoot,
std::deque<LayerPolygon>& aLayers);
void BuildTree(BSPTreeNode* aRoot,
std::list<LayerPolygon>& aLayers);
};
} // namespace layers

View File

@ -50,7 +50,7 @@
#include "mozilla/Compression.h"
#include "TreeTraversal.h" // for ForEachNode
#include <deque>
#include <list>
#include <set>
uint8_t gLayerManagerLayerBuilder;
@ -1158,8 +1158,7 @@ ContainerLayer::Collect3DContextLeaves(nsTArray<Layer*>& aToSort)
static nsTArray<LayerPolygon>
SortLayersWithBSPTree(nsTArray<Layer*>& aArray)
{
std::deque<LayerPolygon> inputLayers;
nsTArray<LayerPolygon> orderedLayers;
std::list<LayerPolygon> inputLayers;
// Build a list of polygons to be sorted.
for (Layer* layer : aArray) {
@ -1189,12 +1188,13 @@ SortLayersWithBSPTree(nsTArray<Layer*>& aArray)
}
if (inputLayers.empty()) {
return orderedLayers;
return nsTArray<LayerPolygon>();
}
// Build a BSP tree from the list of polygons.
BSPTree tree(inputLayers);
orderedLayers = Move(tree.GetDrawOrder());
nsTArray<LayerPolygon> orderedLayers(tree.GetDrawOrder());
// Transform the polygons back to layer space.
for (LayerPolygon& layerPolygon : orderedLayers) {

View File

@ -21,7 +21,7 @@ namespace {
static void RunTest(std::deque<MozPolygon> aPolygons,
std::deque<MozPolygon> aExpected)
{
std::deque<LayerPolygon> layers;
std::list<LayerPolygon> layers;
for (MozPolygon& polygon : aPolygons) {
layers.push_back(LayerPolygon(nullptr, Move(polygon)));
}