Change container get methods (HbrMesh::GetVertices, etc) to take

output iterators instead of std::vector - eases prman integration
for cases where std::list makes more sense.

Block allocate face children array in common case (<= 4 children).

Other, minor consistency edits.
This commit is contained in:
Julian Fong 2012-08-20 12:58:00 -07:00
parent 2bbf5fb27e
commit 59edf56416
7 changed files with 198 additions and 73 deletions

View File

@ -115,6 +115,33 @@ inline bool operator< (const HbrFacePath& x, const HbrFacePath& y) {
}
}
// A simple wrapper around an array of four children. Used to block
// allocate pointers to children of HbrFace in the common case
template <class T>
class HbrFaceChildren {
public:
HbrFace<T> *& operator[](const int index) {
return children[index];
}
const HbrFace<T> *& operator[](const int index) const {
return children[index];
}
private:
friend class HbrAllocator<HbrFaceChildren<T> >;
// Used by block allocator
HbrFaceChildren<T>*& GetNext() { return (HbrFaceChildren<T>*&) children; }
HbrFaceChildren() {}
~HbrFaceChildren() {}
HbrFace<T> *children[4];
};
template <class T> class HbrFace {
private:
@ -161,8 +188,13 @@ public:
// Return the child with the indicated index
HbrFace<T>* GetChild(int index) const {
if (!children || index < 0 || index >= mesh->GetSubdivision()->GetFaceChildrenCount(nvertices)) return 0;
return children[index];
int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(nvertices);
if (!children.children || index < 0 || index >= nchildren) return 0;
if (nchildren > 4) {
return children.extrachildren[index];
} else {
return (*children.children)[index];
}
}
// Subdivide the face into a vertex if needed and return
@ -265,10 +297,19 @@ public:
const HbrFace<T>* f = this, *p = GetParent();
while (p) {
int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(p->nvertices);
for (int i = 0; i < nchildren; ++i) {
if (p->children[i] == f) {
path.remainder.push_back(i);
break;
if (nchildren > 4) {
for (int i = 0; i < nchildren; ++i) {
if (p->children.extrachildren[i] == f) {
path.remainder.push_back(i);
break;
}
}
} else {
for (int i = 0; i < nchildren; ++i) {
if ((*p->children.children)[i] == f) {
path.remainder.push_back(i);
break;
}
}
}
f = p;
@ -312,7 +353,7 @@ private:
int nvertices;
// Halfedge array for this face
// HbrHalfedge::GetIndex() relies on this being size 4
// HbrHalfedge::getIndex() relies on this being size 4
HbrHalfedge<T> edges[4];
// Edge storage if this face is not a triangle or quad
@ -321,8 +362,13 @@ private:
// Pointer to parent face
HbrFace<T>* parent;
// Children (pointer) array
HbrFace<T>** children;
// Pointer to children array. If there are four children or less,
// we use the HbrFaceChildren pointer, otherwise we use
// extrachildren
union {
HbrFaceChildren<T>* children;
HbrFace<T>** extrachildren;
} children;
// Subdivided vertex child
HbrVertex<T>* vchild;
@ -368,12 +414,13 @@ namespace OPENSUBDIV_VERSION {
template <class T>
HbrFace<T>::HbrFace()
: mesh(0), id(-1), uindex(-1), ptexindex(-1), nvertices(0), extraedges(0), parent(0), children(0), vchild(0), fvarbits(0),
: mesh(0), id(-1), uindex(-1), ptexindex(-1), nvertices(0), extraedges(0), parent(0), vchild(0), fvarbits(0),
#ifdef HBRSTITCH
stitchEdges(0),
stitchDatas(0),
#endif
edits(0), clientData(0), depth(0), hole(0), coarse(0), protect(0), collected(0), hasVertexEdits(0), initialized(0), destroyed(0) {
children.children = 0;
}
template <class T>
@ -385,7 +432,7 @@ HbrFace<T>::Initialize(HbrMesh<T>* m, HbrFace<T>* _parent, int childindex, int f
ptexindex = -1;
nvertices = nv;
extraedges = 0;
children = 0;
children.children = 0;
vchild = 0;
fvarbits = 0;
#ifdef HBRSTITCH
@ -434,7 +481,7 @@ HbrFace<T>::Initialize(HbrMesh<T>* m, HbrFace<T>* _parent, int childindex, int f
}
// We also ignore the edge array and allocate extra storage -
// this simplifies GetNext and GetPrev math in HbrHalfede
// this simplifies GetNext and GetPrev math in HbrHalfedge
extraedges = new HbrHalfedge<T>[nv];
} else {
@ -501,16 +548,27 @@ HbrFace<T>::Destroy() {
#endif
// Remove children's references to self
if (children) {
if (children.children) {
int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(nvertices);
for (i = 0; i < nchildren; ++i) {
if (children[i]) {
children[i]->parent = 0;
children[i] = 0;
if (nchildren > 4) {
for (i = 0; i < nchildren; ++i) {
if (children.extrachildren[i]) {
children.extrachildren[i]->parent = 0;
children.extrachildren[i] = 0;
}
}
delete[] children.extrachildren;
children.extrachildren = 0;
} else {
for (i = 0; i < nchildren; ++i) {
if ((*children.children)[i]) {
(*children.children)[i]->parent = 0;
(*children.children)[i] = 0;
}
}
mesh->DeleteFaceChildren(children.children);
children.children = 0;
}
}
delete[] children;
children = 0;
}
// Deleting the incident edges from the vertices in this way is
@ -542,20 +600,36 @@ HbrFace<T>::Destroy() {
// Remove parent's reference to self
if (parent) {
bool parentHasOtherKids = false;
assert(parent->children);
int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(parent->nvertices);
for (i = 0; i < nchildren; ++i) {
if (parent->children[i] == this) {
parent->children[i] = 0;
} else if (parent->children[i]) parentHasOtherKids = true;
}
// After cleaning the parent's reference to self, the parent
// may be able to clean itself up
if (!parentHasOtherKids) {
delete[] parent->children;
parent->children = 0;
if (parent->GarbageCollectable()) {
mesh->DeleteFace(parent);
if (nchildren > 4) {
for (i = 0; i < nchildren; ++i) {
if (parent->children.extrachildren[i] == this) {
parent->children.extrachildren[i] = 0;
} else if (parent->children.extrachildren[i]) parentHasOtherKids = true;
}
// After cleaning the parent's reference to self, the parent
// may be able to clean itself up
if (!parentHasOtherKids) {
delete[] parent->children.extrachildren;
parent->children.extrachildren = 0;
if (parent->GarbageCollectable()) {
mesh->DeleteFace(parent);
}
}
} else {
for (i = 0; i < nchildren; ++i) {
if ((*parent->children.children)[i] == this) {
(*parent->children.children)[i] = 0;
} else if ((*parent->children.children)[i]) parentHasOtherKids = true;
}
// After cleaning the parent's reference to self, the parent
// may be able to clean itself up
if (!parentHasOtherKids) {
mesh->DeleteFaceChildren(parent->children.children);
parent->children.children = 0;
if (parent->GarbageCollectable()) {
mesh->DeleteFace(parent);
}
}
}
parent = 0;
@ -622,16 +696,27 @@ HbrFace<T>::GetVertex(int index) const {
template <class T>
void
HbrFace<T>::SetChild(int index, HbrFace<T>* face) {
// Construct the children array if it doesn't already exist
int i;
if (!children) {
int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(nvertices);
children = new HbrFace<T>*[nchildren];
for (i = 0; i < nchildren; ++i) {
children[i] = 0;
int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(nvertices);
// Construct the children array if it doesn't already exist
if (!children.children) {
int i;
if (nchildren > 4) {
children.extrachildren = new HbrFace<T>*[nchildren];
for (i = 0; i < nchildren; ++i) {
children.extrachildren[i] = 0;
}
} else {
children.children = mesh->NewFaceChildren();
for (i = 0; i < nchildren; ++i) {
(*children.children)[i] = 0;
}
}
children[index] = face;
}
if (nchildren > 4) {
children.extrachildren[index] = face;
} else {
(*children.children)[index] = face;
}
face->parent = this;
}
@ -738,7 +823,7 @@ HbrFace<T>::ClearUsage() {
template <class T>
bool
HbrFace<T>::GarbageCollectable() const {
if (children || protect) return false;
if (children.children || protect) return false;
for (int i = 0; i < nvertices; ++i) {
HbrHalfedge<T>* edge = GetEdge(i);
HbrVertex<T>* vertex = edge->GetOrgVertex();

View File

@ -57,7 +57,7 @@
#ifndef HBRFVARDATA_H
#define HBRFVARDATA_H
#include <string.h>
#include <cstring>
#include <cmath>
#include "../version.h"

View File

@ -380,10 +380,9 @@ private:
HbrHalfedge<T>* opposite;
HbrFace<T>* incidentFace;
// Index of incident vertex
HbrVertex<T>* incidentVertex;
// Index of child vertex
// Child vertex
HbrVertex<T>* vchild;
float sharpness;

View File

@ -161,7 +161,7 @@ using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#include "../hbr/face.h"
#include <string.h>
#include <cstring>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {

View File

@ -57,13 +57,14 @@
#ifndef HBRMESH_H
#define HBRMESH_H
#if PRMAN
#ifdef PRMAN
#include "libtarget/TgMalloc.h" // only for alloca
#include "libtarget/TgThread.h"
#endif
#include <algorithm>
#include <cstring>
#include <iterator>
#include <vector>
#include <set>
#include <iostream>
@ -138,14 +139,20 @@ public:
// Ask for face with the indicated ID
HbrFace<T>* GetFace(int id) const;
// Returns a collection of all vertices in the mesh
void GetVertices(std::vector<HbrVertex<T>*>& vertices) const;
// Returns a collection of all vertices in the mesh. This function
// requires an output iterator; to get the vertices into a
// std::vector, use GetVertices(std::back_inserter(myvector))
template <typename OutputIterator>
void GetVertices(OutputIterator vertices) const;
// Applies operator to all vertices
void ApplyOperatorAllVertices(HbrVertexOperator<T> &op) const;
// Returns a collection of all faces in the mesh
void GetFaces(std::vector<HbrFace<T>*>& faces) const;
// Returns a collection of all faces in the mesh. This function
// requires an output iterator; to get the faces into a
// std::vector, use GetFaces(std::back_inserter(myvector))
template <typename OutputIterator>
void GetFaces(OutputIterator faces) const;
// Returns the subdivision method
HbrSubdivision<T>* GetSubdivision() const { return subdivision; }
@ -250,16 +257,36 @@ public:
}
}
// Whether the mesh is in "transient" mode, i.e. all
// vertices/faces that are created should be deemed temporary
// When mode is true, the mesh is put in a "transient" mode,
// i.e. all subsequent intermediate vertices/faces that are
// created by subdivision are deemed temporary. This transient
// data can be entirely freed by a subsequent call to
// FreeTransientData(). Essentially, the mesh is checkpointed and
// restored. This is useful when space is at a premium and
// subdivided results are cached elsewhere. On the other hand,
// repeatedly putting the mesh in and out of transient mode and
// performing the same evaluations comes at a significant compute
// cost.
void SetTransientMode(bool mode) {
m_transientMode = mode;
}
// Frees transient subdivision data; returns the mesh to a
// checkpointed state prior to a call to SetTransientMode.
void FreeTransientData();
// Create new face children block for use by HbrFace
HbrFaceChildren<T>* NewFaceChildren() {
return m_faceChildrenAllocator.Allocate();
}
// Recycle face children block used by HbrFace
void DeleteFaceChildren(HbrFaceChildren<T>* facechildren) {
m_faceChildrenAllocator.Deallocate(facechildren);
}
private:
#if PRMAN
#ifdef PRMAN
// This code is intended to be shared with PRman which provides its own
// TgSpinLock mutex. Other clients are responsible for providing a Mutex
// object with public Lock() and Unlock() functions.
@ -339,6 +366,9 @@ private:
const size_t m_vertexSize;
HbrAllocator<HbrVertex<T> > m_vertexAllocator;
// Allocator for face children blocks used by HbrFace
HbrAllocator<HbrFaceChildren<T> > m_faceChildrenAllocator;
// Memory used by this mesh alone, plus all its faces and vertices
size_t m_memory;
@ -405,6 +435,7 @@ HbrMesh<T>::HbrMesh(HbrSubdivision<T>* s, int _fvarcount, const int *_fvarindice
sizeof(HbrHalfedge<T>*) + // for incidentEdges[1]
totalfvarwidth * sizeof(float) + sizeof(HbrFVarData<T>)),
m_vertexAllocator(&m_memory, 512, 0, 0, m_vertexSize),
m_faceChildrenAllocator(&m_memory, 512, 0, 0),
m_memory(0),
m_numCoarseFaces(-1),
hasVertexEdits(0),
@ -683,7 +714,7 @@ HbrMesh<T>::Finish() {
}
std::vector<HbrVertex<T>*> vertexlist;
GetVertices(vertexlist);
GetVertices(std::back_inserter(vertexlist));
for (typename std::vector<HbrVertex<T>*>::iterator vi = vertexlist.begin();
vi != vertexlist.end(); ++vi) {
HbrVertex<T>* vertex = *vi;
@ -835,13 +866,14 @@ HbrMesh<T>::GetFace(int id) const {
}
template <class T>
template <typename OutputIterator>
void
HbrMesh<T>::GetVertices(std::vector<HbrVertex<T>*>& lvertices) const {
HbrMesh<T>::GetVertices(OutputIterator lvertices) const {
m_mutex.Lock();
for (int vi = 0; vi < nvsets; ++vi) {
HbrVertex<T>** vset = vertices[vi];
for (int i = 0; i < vsetsize; ++i) {
if (vset[i]) lvertices.push_back(vset[i]);
if (vset[i]) *lvertices++ = vset[i];
}
}
m_mutex.Unlock();
@ -861,10 +893,11 @@ HbrMesh<T>::ApplyOperatorAllVertices(HbrVertexOperator<T> &op) const {
}
template <class T>
template <typename OutputIterator>
void
HbrMesh<T>::GetFaces(std::vector<HbrFace<T>*>& lfaces) const {
HbrMesh<T>::GetFaces(OutputIterator lfaces) const {
for (int i = 0; i < nfaces; ++i) {
if (faces[i]) lfaces.push_back(faces[i]);
if (faces[i]) *lfaces++ = faces[i];
}
}

View File

@ -254,7 +254,7 @@ HbrSubdivision<T>::SubdivideCreaseWeight(HbrHalfedge<T>* edge, HbrVertex<T>* ver
// the vertex (other than this crease edge)
std::vector<HbrHalfedge<T>*> edges;
vertex->GuaranteeNeighbors();
vertex->GetSurroundingEdges(edges);
vertex->GetSurroundingEdges(std::back_inserter(edges));
int n = 0;
for (typename std::vector<HbrHalfedge<T>*>::iterator ei = edges.begin(); ei != edges.end(); ++ei) {

View File

@ -219,18 +219,24 @@ public:
// incident halfedge cycles)
bool IsSingular() const { return nIncidentEdges > 1; }
// Collect the ring of edges around this vertex. Note well:
// not all edges in this list will have an orientation where
// the origin of the edge is this vertex!
void GetSurroundingEdges(std::vector<HbrHalfedge<T>*>& edges) const;
// Collect the ring of edges around this vertex. Note well: not
// all edges in this list will have an orientation where the
// origin of the edge is this vertex! This function requires an
// output iterator; to get the edges into a std::vector, use
// GetSurroundingEdges(std::back_inserter(myvector))
template <typename OutputIterator>
void GetSurroundingEdges(OutputIterator edges) const;
// Apply an edge operator to each edge in the ring of edges
// around this vertex
void ApplyOperatorSurroundingEdges(HbrHalfedgeOperator<T> &op) const;
// Collect the ring of vertices around this vertex (the ones
// that share an edge with this vertex)
void GetSurroundingVertices(std::vector<HbrVertex<T>*>& vertices) const;
// Collect the ring of vertices around this vertex (the ones that
// share an edge with this vertex). This function requires an
// output iterator; to get the vertices into a std::vector, use
// GetSurroundingVertices(std::back_inserter(myvector))
template <typename OutputIterator>
void GetSurroundingVertices(OutputIterator vertices) const;
// Apply a vertex operator to each vertex in the ring of vertices
// around this vertex
@ -1286,18 +1292,19 @@ HbrVertex<T>::GetFractionalMask() const {
}
template <class T>
template <typename OutputIterator>
void
HbrVertex<T>::GetSurroundingEdges(std::vector<HbrHalfedge<T>*>& edges) const {
HbrVertex<T>::GetSurroundingEdges(OutputIterator edges) const {
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *next;
edge = start;
while (edge) {
edges.push_back(edge);
*edges++ = edge;
next = GetNextEdge(edge);
if (next == start) {
break;
} else if (!next) {
// Special case for the last edge in a cycle.
edges.push_back(edge->GetPrev());
*edges++ = edge->GetPrev();
break;
} else {
edge = next;
@ -1325,12 +1332,13 @@ HbrVertex<T>::ApplyOperatorSurroundingEdges(HbrHalfedgeOperator<T> &op) const {
}
template <class T>
template <typename OutputIterator>
void
HbrVertex<T>::GetSurroundingVertices(std::vector<HbrVertex<T>*>& vertices) const {
HbrVertex<T>::GetSurroundingVertices(OutputIterator vertices) const {
HbrHalfedge<T>* start = GetIncidentEdge(), *edge, *next;
edge = start;
while (edge) {
vertices.push_back(edge->GetDestVertex());
*vertices++ = edge->GetDestVertex();
next = GetNextEdge(edge);
if (next == start) {
break;
@ -1338,7 +1346,7 @@ HbrVertex<T>::GetSurroundingVertices(std::vector<HbrVertex<T>*>& vertices) const
// Special case for the last edge in a cycle: the last
// vertex on that cycle is not the destination of an
// outgoing halfedge
vertices.push_back(edge->GetPrev()->GetOrgVertex());
*vertices++ = edge->GetPrev()->GetOrgVertex();
break;
} else {
edge = next;