From 59edf56416a9b1de260303e10e1dc9187750be7f Mon Sep 17 00:00:00 2001 From: Julian Fong Date: Mon, 20 Aug 2012 12:58:00 -0700 Subject: [PATCH] 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. --- opensubdiv/hbr/face.h | 169 ++++++++++++++++++++++-------- opensubdiv/hbr/fvarData.h | 2 +- opensubdiv/hbr/halfedge.h | 3 +- opensubdiv/hbr/hierarchicalEdit.h | 2 +- opensubdiv/hbr/mesh.h | 59 ++++++++--- opensubdiv/hbr/subdivision.h | 2 +- opensubdiv/hbr/vertex.h | 34 +++--- 7 files changed, 198 insertions(+), 73 deletions(-) diff --git a/opensubdiv/hbr/face.h b/opensubdiv/hbr/face.h index 4bd5db02..586496f8 100644 --- a/opensubdiv/hbr/face.h +++ b/opensubdiv/hbr/face.h @@ -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 HbrFaceChildren { +public: + HbrFace *& operator[](const int index) { + return children[index]; + } + + const HbrFace *& operator[](const int index) const { + return children[index]; + } + + +private: + friend class HbrAllocator >; + + // Used by block allocator + HbrFaceChildren*& GetNext() { return (HbrFaceChildren*&) children; } + + HbrFaceChildren() {} + + ~HbrFaceChildren() {} + + HbrFace *children[4]; +}; + template class HbrFace { private: @@ -161,8 +188,13 @@ public: // Return the child with the indicated index HbrFace* 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* 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 edges[4]; // Edge storage if this face is not a triangle or quad @@ -321,8 +362,13 @@ private: // Pointer to parent face HbrFace* parent; - // Children (pointer) array - HbrFace** children; + // Pointer to children array. If there are four children or less, + // we use the HbrFaceChildren pointer, otherwise we use + // extrachildren + union { + HbrFaceChildren* children; + HbrFace** extrachildren; + } children; // Subdivided vertex child HbrVertex* vchild; @@ -368,12 +414,13 @@ namespace OPENSUBDIV_VERSION { template HbrFace::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 @@ -385,7 +432,7 @@ HbrFace::Initialize(HbrMesh* m, HbrFace* _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::Initialize(HbrMesh* m, HbrFace* _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[nv]; } else { @@ -501,16 +548,27 @@ HbrFace::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::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::GetVertex(int index) const { template void HbrFace::SetChild(int index, HbrFace* face) { - // Construct the children array if it doesn't already exist - int i; - if (!children) { - int nchildren = mesh->GetSubdivision()->GetFaceChildrenCount(nvertices); - children = new HbrFace*[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*[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::ClearUsage() { template bool HbrFace::GarbageCollectable() const { - if (children || protect) return false; + if (children.children || protect) return false; for (int i = 0; i < nvertices; ++i) { HbrHalfedge* edge = GetEdge(i); HbrVertex* vertex = edge->GetOrgVertex(); diff --git a/opensubdiv/hbr/fvarData.h b/opensubdiv/hbr/fvarData.h index bf3c07e2..d7ecf1c5 100644 --- a/opensubdiv/hbr/fvarData.h +++ b/opensubdiv/hbr/fvarData.h @@ -57,7 +57,7 @@ #ifndef HBRFVARDATA_H #define HBRFVARDATA_H -#include +#include #include #include "../version.h" diff --git a/opensubdiv/hbr/halfedge.h b/opensubdiv/hbr/halfedge.h index b7fd735e..6650346e 100644 --- a/opensubdiv/hbr/halfedge.h +++ b/opensubdiv/hbr/halfedge.h @@ -380,10 +380,9 @@ private: HbrHalfedge* opposite; HbrFace* incidentFace; - // Index of incident vertex HbrVertex* incidentVertex; - // Index of child vertex + // Child vertex HbrVertex* vchild; float sharpness; diff --git a/opensubdiv/hbr/hierarchicalEdit.h b/opensubdiv/hbr/hierarchicalEdit.h index 1aa23266..ef941262 100644 --- a/opensubdiv/hbr/hierarchicalEdit.h +++ b/opensubdiv/hbr/hierarchicalEdit.h @@ -161,7 +161,7 @@ using namespace OPENSUBDIV_VERSION; } // end namespace OpenSubdiv #include "../hbr/face.h" -#include +#include namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { diff --git a/opensubdiv/hbr/mesh.h b/opensubdiv/hbr/mesh.h index f575c2b8..a140b593 100644 --- a/opensubdiv/hbr/mesh.h +++ b/opensubdiv/hbr/mesh.h @@ -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 #include +#include #include #include #include @@ -138,14 +139,20 @@ public: // Ask for face with the indicated ID HbrFace* GetFace(int id) const; - // Returns a collection of all vertices in the mesh - void GetVertices(std::vector*>& 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 + void GetVertices(OutputIterator vertices) const; // Applies operator to all vertices void ApplyOperatorAllVertices(HbrVertexOperator &op) const; - // Returns a collection of all faces in the mesh - void GetFaces(std::vector*>& 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 + void GetFaces(OutputIterator faces) const; // Returns the subdivision method HbrSubdivision* 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* NewFaceChildren() { + return m_faceChildrenAllocator.Allocate(); + } + + // Recycle face children block used by HbrFace + void DeleteFaceChildren(HbrFaceChildren* 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 > m_vertexAllocator; + // Allocator for face children blocks used by HbrFace + HbrAllocator > m_faceChildrenAllocator; + // Memory used by this mesh alone, plus all its faces and vertices size_t m_memory; @@ -405,6 +435,7 @@ HbrMesh::HbrMesh(HbrSubdivision* s, int _fvarcount, const int *_fvarindice sizeof(HbrHalfedge*) + // for incidentEdges[1] totalfvarwidth * sizeof(float) + sizeof(HbrFVarData)), 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::Finish() { } std::vector*> vertexlist; - GetVertices(vertexlist); + GetVertices(std::back_inserter(vertexlist)); for (typename std::vector*>::iterator vi = vertexlist.begin(); vi != vertexlist.end(); ++vi) { HbrVertex* vertex = *vi; @@ -835,13 +866,14 @@ HbrMesh::GetFace(int id) const { } template +template void -HbrMesh::GetVertices(std::vector*>& lvertices) const { +HbrMesh::GetVertices(OutputIterator lvertices) const { m_mutex.Lock(); for (int vi = 0; vi < nvsets; ++vi) { HbrVertex** 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::ApplyOperatorAllVertices(HbrVertexOperator &op) const { } template +template void -HbrMesh::GetFaces(std::vector*>& lfaces) const { +HbrMesh::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]; } } diff --git a/opensubdiv/hbr/subdivision.h b/opensubdiv/hbr/subdivision.h index e6c3afe1..f4f12b1d 100644 --- a/opensubdiv/hbr/subdivision.h +++ b/opensubdiv/hbr/subdivision.h @@ -254,7 +254,7 @@ HbrSubdivision::SubdivideCreaseWeight(HbrHalfedge* edge, HbrVertex* ver // the vertex (other than this crease edge) std::vector*> edges; vertex->GuaranteeNeighbors(); - vertex->GetSurroundingEdges(edges); + vertex->GetSurroundingEdges(std::back_inserter(edges)); int n = 0; for (typename std::vector*>::iterator ei = edges.begin(); ei != edges.end(); ++ei) { diff --git a/opensubdiv/hbr/vertex.h b/opensubdiv/hbr/vertex.h index dd126fc6..27f6a90d 100644 --- a/opensubdiv/hbr/vertex.h +++ b/opensubdiv/hbr/vertex.h @@ -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*>& 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 + void GetSurroundingEdges(OutputIterator edges) const; // Apply an edge operator to each edge in the ring of edges // around this vertex void ApplyOperatorSurroundingEdges(HbrHalfedgeOperator &op) const; - // Collect the ring of vertices around this vertex (the ones - // that share an edge with this vertex) - void GetSurroundingVertices(std::vector*>& 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 + 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::GetFractionalMask() const { } template +template void -HbrVertex::GetSurroundingEdges(std::vector*>& edges) const { +HbrVertex::GetSurroundingEdges(OutputIterator edges) const { HbrHalfedge* 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::ApplyOperatorSurroundingEdges(HbrHalfedgeOperator &op) const { } template +template void -HbrVertex::GetSurroundingVertices(std::vector*>& vertices) const { +HbrVertex::GetSurroundingVertices(OutputIterator vertices) const { HbrHalfedge* 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::GetSurroundingVertices(std::vector*>& 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;