minor API refactor of for EvalLimit :

- Replaced EvalData and EvalVertexData classes with a simpler DataStream class that only
  accesses a single data stream, binds and unbinds it

- DataStream has both an input and an output version which avoids much of the const-ness
  const-related ambiguity of the previous design pattern

- Vertex, varying and face-varying data now all have a dedicate struct (VertexData, VaryingData, FaceVaryingData)
  as a way of gathering the various data-streams required to perform sampling

- renamd some "Buffers" into "Tables" for better naming consistency with Far
This commit is contained in:
manuelk 2013-06-17 18:13:13 -07:00
parent 077f95b8f0
commit bbe4435b19
5 changed files with 310 additions and 257 deletions

View File

@ -442,19 +442,19 @@ updateGeom() {
// Bind/Unbind of the vertex buffers to the context needs to happen
// outside of the parallel loop
g_evalCtx->BindVertexBuffers( g_idesc, g_vertexData, g_odesc, g_Q, g_dQu, g_dQv );
g_evalCtx->GetVertexData().Bind( g_idesc, g_vertexData, g_odesc, g_Q, g_dQu, g_dQv );
// The varying data ends-up interleaved in the same g_Q output buffer because
// g_Q has a stride of 6 and g_vdesc sets the offset to 3, while g_odesc sets
// the offset to 0
switch (g_drawMode) {
case kVARYING : g_evalCtx->BindVaryingBuffers( g_idesc, g_varyingData, g_vdesc, g_Q ); break;
case kVARYING : g_evalCtx->GetVaryingData().Bind( g_idesc, g_varyingData, g_vdesc, g_Q ); break;
case kFACEVARYING : g_evalCtx->BindFaceVaryingBuffers( g_fvidesc, g_fvodesc, g_Q );
case kFACEVARYING : g_evalCtx->GetFaceVaryingData().Bind( g_fvidesc, g_fvodesc, g_Q );
case kUV :
default : g_evalCtx->UnbindVaryingBuffers(); break;
default : g_evalCtx->GetVaryingData().Unbind(); break;
}
#define USE_OPENMP
@ -490,7 +490,15 @@ updateGeom() {
}
}
g_evalCtx->UnbindVertexBuffers();
g_evalCtx->GetVertexData().Unbind();
switch (g_drawMode) {
case kVARYING : g_evalCtx->GetVaryingData().Unbind(); break;
case kFACEVARYING : g_evalCtx->GetFaceVaryingData().Unbind(); break;
default : break;
}
g_Q->BindVBO();

View File

@ -78,39 +78,6 @@ OsdCpuEvalLimitContext::Create(FarMesh<OsdVertex> const * farmesh, bool requireF
return new OsdCpuEvalLimitContext(farmesh, requireFVarData);
}
void
OsdCpuEvalLimitContext::EvalData::Unbind() {
_inDesc.Reset();
_inQ=0;
_outDesc.Reset();
_outQ = 0;
}
void
OsdCpuEvalLimitContext::EvalVertexData::Unbind() {
EvalData::Unbind();
_outdQu = _outdQv = 0;
}
void
OsdCpuEvalLimitContext::UnbindVertexBuffers() {
_vertexData.Unbind();
}
void
OsdCpuEvalLimitContext::UnbindVaryingBuffers() {
_varyingData.Unbind();
}
void
OsdCpuEvalLimitContext::UnbindFaceVaryingBuffers() {
_faceVaryingData.Unbind();
}
OsdCpuEvalLimitContext::OsdCpuEvalLimitContext(FarMesh<OsdVertex> const * farmesh, bool requireFVarData) :
OsdEvalLimitContext(farmesh) {
@ -122,9 +89,9 @@ OsdCpuEvalLimitContext::OsdCpuEvalLimitContext(FarMesh<OsdVertex> const * farmes
_patchArrays = patchTables->GetPatchArrayVector();
_vertexValenceBuffer = patchTables->GetVertexValenceTable();
_vertexValenceTable = patchTables->GetVertexValenceTable();
_quadOffsetBuffer = patchTables->GetQuadOffsetTable();
_quadOffsetTable = patchTables->GetQuadOffsetTable();
_maxValence = patchTables->GetMaxValence();
@ -165,5 +132,36 @@ OsdCpuEvalLimitContext::~OsdCpuEvalLimitContext() {
delete _patchMap;
}
void
OsdCpuEvalLimitContext::VertexData::Unbind() {
inDesc.Reset();
in.Unbind();
outDesc.Reset();
out.Unbind();
outDu.Unbind();
outDv.Unbind();
}
void
OsdCpuEvalLimitContext::VaryingData::Unbind() {
inDesc.Reset();
in.Unbind();
outDesc.Reset();
out.Unbind();
}
void
OsdCpuEvalLimitContext::FaceVaryingData::Unbind() {
inDesc.Reset();
outDesc.Reset();
out.Unbind();
}
} // end namespace OPENSUBDIV_VERSION
} // end namespace OpenSubdiv

View File

@ -87,185 +87,220 @@ public:
virtual ~OsdCpuEvalLimitContext();
/// Limit evaluation data descriptor
class EvalData {
/// A container able to bind vertex buffer data as input or output streams.
class DataStream {
public:
OsdVertexBufferDescriptor const & GetInputDesc() const {
return _inDesc;
/// Constructor
DataStream() : _data(0) { }
/// Binds the stream to the context (and moves the data to the appropriate
/// compute device)
///
/// @param data a valid OsdVertexBuffer
///
template <class BUFFER> void Bind( BUFFER * data ) {
_data = data ? data->BindCpuBuffer() : 0;
}
float const * GetInputData() const {
return _inQ;
}
OsdVertexBufferDescriptor const & GetOutputDesc() const {
return _outDesc;
}
float const * GetOutputData(int index=0) const {
return _outQ + index * _outDesc.stride;
}
template <class BUFFER>
void BindInputData( BUFFER * inQ ) {
_inQ = inQ ? inQ->BindCpuBuffer() : 0;
}
template <class BUFFER>
void BindOutputData( BUFFER * outQ ) {
_outQ = outQ ? outQ->BindCpuBuffer() : 0;
}
/// True if the stream has been bound
bool IsBound() const {
return _inQ and _outQ;
return (_data!=NULL);
}
private:
friend class OsdCpuEvalLimitContext;
EvalData() : _inQ(0), _outQ(0) { }
/// Unbinds the stream
void Unbind() {
_data=0;
}
OsdVertexBufferDescriptor _inDesc; // input data
float * _inQ;
OsdVertexBufferDescriptor _outDesc; // output data
float * _outQ;
/// Resets the descriptors & pointers
void Unbind();
protected:
float * _data;
};
/// Limit evaluation data descriptor with derivatives
class EvalVertexData : public EvalData {
/// \brief Input (const) data stream
class InputDataStream : public DataStream {
public:
float const * GetOutputDU(int index=0) const {
return _outdQu + index * _outDesc.stride;
/// Const accessor
float const * GetData() const {
return _data;
}
float const * GetOutputDV(int index=0) const {
return _outdQv + index * _outDesc.stride;
}
template <class BUFFER>
void BindOutputDerivData( BUFFER * outdQu, BUFFER * outdQv ) {
_outdQu = outdQu ? outdQu->BindCpuBuffer() : 0;
_outdQv = outdQv ? outdQv->BindCpuBuffer() : 0;
}
private:
friend class OsdCpuEvalLimitContext;
EvalVertexData() : _outdQu(0), _outdQv(0) { }
/// Resets the descriptors & pointers
void Unbind();
float * _outdQu, // U derivative of output data
* _outdQv; // V derivative of output data
};
/// \brief Output (const) data stream
class OutputDataStream : public DataStream {
public:
/// Non-cont accessor
float * GetData() {
return _data;
}
};
/// Vertex-interpolated streams
struct VertexData {
/// input vertex-interpolated data descriptor
OsdVertexBufferDescriptor inDesc;
/// Binds the vertex-interpolated data buffers.
///
/// @param inDesc vertex buffer data descriptor shared by all input data buffers
///
/// @param inQ input vertex data
///
/// @param outDesc vertex buffer data descriptor shared by all output data buffers
///
/// @param outQ output vertex data
///
/// @param outdQu optional output derivative along "u" of the vertex data
///
/// @param outdQv optional output derivative along "v" of the vertex data
///
template<class VERTEX_BUFFER, class OUTPUT_BUFFER>
void BindVertexBuffers( OsdVertexBufferDescriptor const & inDesc, VERTEX_BUFFER *inQ,
OsdVertexBufferDescriptor const & outDesc, OUTPUT_BUFFER *outQ,
OUTPUT_BUFFER *outdQu=0,
OUTPUT_BUFFER *outdQv=0) {
_vertexData._inDesc = inDesc;
_vertexData.BindInputData( inQ );
_vertexData._outDesc = outDesc;
_vertexData.BindOutputData( outQ );
_vertexData.BindOutputDerivData( outdQu, outdQv );
}
/// input vertex-interpolated data stream
InputDataStream in;
/// Unbind the vertex data buffers
void UnbindVertexBuffers();
/// output vertex-interpolated data descriptor
OsdVertexBufferDescriptor outDesc;
/// output vertex-interpolated data stream and parametric derivative streams
OutputDataStream out,
outDu,
outDv;
/// Binds the vertex-interpolated data streams
///
/// @param iDesc data descriptor shared by all input data buffers
///
/// @param inQ input vertex data
///
/// @param oDesc data descriptor shared by all output data buffers
///
/// @param outQ output vertex data
///
/// @param outdQu output derivative along "u" of the vertex data (optional)
///
/// @param outdQv output derivative along "v" of the vertex data (optional)
///
template<class VERTEX_BUFFER, class OUTPUT_BUFFER>
void Bind( OsdVertexBufferDescriptor const & iDesc, VERTEX_BUFFER *inQ,
OsdVertexBufferDescriptor const & oDesc, OUTPUT_BUFFER *outQ,
OUTPUT_BUFFER *outdQu=0,
OUTPUT_BUFFER *outdQv=0) {
inDesc = iDesc;
in.Bind( inQ );
outDesc = oDesc;
out.Bind( outQ );
outDu.Bind( outdQu );
outDv.Bind( outdQv );
}
/// True if both the mandatory input and output streams have been bound
bool IsBound() const {
return in.IsBound() and out.IsBound();
}
/// Unbind the vertex data streams
void Unbind();
};
/// Returns an Eval data descriptor of the vertex-interpolated data currently
/// bound to this EvalLimitContext.
EvalVertexData const & GetVertexData() const {
VertexData & GetVertexData() {
return _vertexData;
}
/// Binds the varying-interpolated data buffers.
///
/// @param inDesc varying buffer data descriptor shared by all input data buffers
///
/// @param inQ input varying data
///
/// @param outDesc varying buffer data descriptor shared by all output data buffers
///
/// @param outQ output varying data
///
template<class VARYING_BUFFER, class OUTPUT_BUFFER>
void BindVaryingBuffers( OsdVertexBufferDescriptor const & inDesc, VARYING_BUFFER *inQ,
OsdVertexBufferDescriptor const & outDesc, OUTPUT_BUFFER *outQ) {
_varyingData._inDesc = inDesc;
_varyingData.BindInputData( inQ );
_varyingData._outDesc = outDesc;
_varyingData.BindOutputData( outQ );
}
/// Unbind the varying data buffers
void UnbindVaryingBuffers();
/// Varying-interpolated streams
struct VaryingData {
/// input varying-interpolated data descriptor
OsdVertexBufferDescriptor inDesc;
/// input varying-interpolated data stream
InputDataStream in;
/// output varying-interpolated data descriptor
OsdVertexBufferDescriptor outDesc;
/// output varying-interpolated data stream
OutputDataStream out;
/// Binds the varying-interpolated data streams
///
/// @param iDesc data descriptor shared by all input data buffers
///
/// @param inQ input varying data
///
/// @param oDesc data descriptor shared by all output data buffers
///
/// @param outQ output varying data
///
template<class VARYING_BUFFER, class OUTPUT_BUFFER>
void Bind( OsdVertexBufferDescriptor const & iDesc, VARYING_BUFFER *inQ,
OsdVertexBufferDescriptor const & oDesc, OUTPUT_BUFFER *outQ ) {
inDesc = iDesc;
in.Bind( inQ );
outDesc = oDesc;
out.Bind( outQ );
}
/// True if both the mandatory input and output streams have been bound
bool IsBound() const {
return in.IsBound() and out.IsBound();
}
/// Unbind the vertex data streams
void Unbind();
};
/// Returns an Eval data descriptor of the varying-interpolated data currently
/// bound to this EvalLimitContext.
EvalData const & GetVaryingData() const {
VaryingData & GetVaryingData() {
return _varyingData;
}
/// Binds the face-varying-interpolated data buffers.
///
/// Note : currently we only support bilinear boundary interpolation rules
/// for face-varying data. Although Hbr supports 3 addition smooth rule sets,
/// the feature-adaptive patch interpolation code currently does not support
/// them, and neither does this EvalContext
///
/// @param inDesc varying buffer data descriptor shared by all input data buffers
///
/// @param inQ input varying data
///
/// @param outDesc varying buffer data descriptor shared by all output data buffers
///
/// @param outQ output varying data
///
template<class OUTPUT_BUFFER>
void BindFaceVaryingBuffers( OsdVertexBufferDescriptor const & inDesc,
OsdVertexBufferDescriptor const & outDesc, OUTPUT_BUFFER *outQ) {
_faceVaryingData._inDesc = inDesc;
_faceVaryingData._outDesc = outDesc;
_faceVaryingData.BindOutputData( outQ );
}
/// Face-Varying-interpolated streams
struct FaceVaryingData {
/// input face-varying-interpolated data descriptor
OsdVertexBufferDescriptor inDesc;
/// Unbind the varying data buffers
void UnbindFaceVaryingBuffers();
/// output face-varying-interpolated data descriptor
OsdVertexBufferDescriptor outDesc;
/// output face-varying-interpolated data stream and parametric derivative streams
OutputDataStream out;
/// Binds the face-varying-interpolated data streams
///
/// Note : currently we only support bilinear boundary interpolation rules
/// for face-varying data. Although Hbr supports 3 addition smooth rule sets,
/// the feature-adaptive patch interpolation code currently does not support
/// them, and neither does this EvalContext
///
/// @param iDesc data descriptor shared by all input data buffers
///
/// @param oDesc data descriptor shared by all output data buffers
///
/// @param outQ output face-varying data
///
template<class OUTPUT_BUFFER>
void Bind( OsdVertexBufferDescriptor const & iDesc,
OsdVertexBufferDescriptor const & oDesc, OUTPUT_BUFFER *outQ ) {
inDesc = iDesc;
outDesc = oDesc;
out.Bind( outQ );
}
/// True if the output stream has been bound
bool IsBound() const {
return out.IsBound();
}
/// Unbind the vertex data streams
void Unbind();
};
/// Returns an Eval data descriptor of the face-varying-interpolated data
/// currently bound to this EvalLimitContext.
EvalData const & GetFaceVaryingData() const {
FaceVaryingData & GetFaceVaryingData() {
return _faceVaryingData;
}
/// Returns the vector of patch arrays
const FarPatchTables::PatchArrayVector & GetPatchArrayVector() const {
return _patchArrays;
@ -282,13 +317,13 @@ public:
}
/// Returns the vertex-valence buffer used for Gregory patch computations
const int * GetVertexValenceBuffer() const {
return &_vertexValenceBuffer[0];
FarPatchTables::VertexValenceTable const & GetVertexValenceTable() const {
return _vertexValenceTable;
}
/// Returns the Quad-Offsets buffer used for Gregory patch computations
const unsigned int *GetQuadOffsetBuffer() const {
return &_quadOffsetBuffer[0];
FarPatchTables::QuadOffsetTable const & GetQuadOffsetTable() const {
return _quadOffsetTable;
}
/// Returns the face-varying data patch table
@ -321,16 +356,16 @@ private:
FarPatchTables::PTable _patches; // patch control vertices
std::vector<FarPatchParam::BitField> _patchBitFields; // per-patch parametric info
FarPatchTables::VertexValenceTable _vertexValenceBuffer; // extra Gregory patch data buffers
FarPatchTables::QuadOffsetTable _quadOffsetBuffer;
FarPatchTables::VertexValenceTable _vertexValenceTable; // extra Gregory patch data buffers
FarPatchTables::QuadOffsetTable _quadOffsetTable;
FarPatchTables::FVarDataTable _fvarData;
FarPatchMap * _patchMap; // map of the sub-patches given a face index
FarPatchMap * _patchMap; // map of the sub-patches given a face index
EvalVertexData _vertexData; // vertex-interpolated data descriptor
EvalData _varyingData, // varying-interpolated data descriptor
_faceVaryingData; // face-varying-interpolated data descriptor
VertexData _vertexData; // vertex-interpolated data descriptor
VaryingData _varyingData; // varying-interpolated data descriptor
FaceVaryingData _faceVaryingData; // face-varying-interpolated data descriptor
int _maxValence,
_fvarwidth;

View File

@ -70,7 +70,7 @@ OsdCpuEvalLimitController::~OsdCpuEvalLimitController() {
int
OsdCpuEvalLimitController::_EvalLimitSample( OpenSubdiv::OsdEvalCoords const & coords,
OsdCpuEvalLimitContext const *context,
OsdCpuEvalLimitContext * context,
unsigned int index ) {
float u=coords.u,
v=coords.v;
@ -92,70 +92,80 @@ OsdCpuEvalLimitController::_EvalLimitSample( OpenSubdiv::OsdEvalCoords const & c
unsigned int const * cvs = &context->GetControlVertices()[ parray.GetVertIndex() + handle->vertexOffset ];
OsdCpuEvalLimitContext::EvalVertexData const & vertexData = context->GetVertexData();
OsdCpuEvalLimitContext::VertexData & vertexData = context->GetVertexData();
// Position lookup pointers at the indexed vertex
float const * inQ = vertexData.GetInputData();
float * outQ = const_cast<float *>(vertexData.GetOutputData(index));
float * outdQu = const_cast<float *>(vertexData.GetOutputDU(index));
float * outdQv = const_cast<float *>(vertexData.GetOutputDV(index));
if (vertexData.IsBound()) {
int offset = vertexData.outDesc.stride * index;
// Based on patch type - go execute interpolation
switch( parray.GetDescriptor().GetType() ) {
// Based on patch type - go execute interpolation
switch( parray.GetDescriptor().GetType() ) {
case FarPatchTables::REGULAR : if (vertexData.IsBound()) {
evalBSpline( v, u, cvs,
vertexData.inDesc,
vertexData.in.GetData(),
vertexData.outDesc,
vertexData.out.GetData()+offset,
vertexData.outDu.GetData()+offset,
vertexData.outDv.GetData()+offset );
} break;
case FarPatchTables::REGULAR : if (vertexData.IsBound()) {
evalBSpline( v, u, cvs,
vertexData.GetInputDesc(),
inQ,
vertexData.GetOutputDesc(),
outQ, outdQu, outdQv );
} break;
case FarPatchTables::BOUNDARY : if (vertexData.IsBound()) {
evalBoundary( v, u, cvs,
vertexData.inDesc,
vertexData.in.GetData(),
vertexData.outDesc,
vertexData.out.GetData()+offset,
vertexData.outDu.GetData()+offset,
vertexData.outDv.GetData()+offset );
} break;
case FarPatchTables::BOUNDARY : if (vertexData.IsBound()) {
evalBoundary( v, u, cvs,
vertexData.GetInputDesc(),
inQ,
vertexData.GetOutputDesc(),
outQ, outdQu, outdQv );
} break;
case FarPatchTables::CORNER : if (vertexData.IsBound()) {
evalCorner( v, u, cvs,
vertexData.GetInputDesc(),
inQ,
vertexData.GetOutputDesc(),
outQ, outdQu, outdQv);
} break;
case FarPatchTables::CORNER : if (vertexData.IsBound()) {
evalCorner( v, u, cvs,
vertexData.inDesc,
vertexData.in.GetData(),
vertexData.outDesc,
vertexData.out.GetData()+offset,
vertexData.outDu.GetData()+offset,
vertexData.outDv.GetData()+offset );
} break;
case FarPatchTables::GREGORY : if (vertexData.IsBound()) {
evalGregory( v, u, cvs,
context->GetVertexValenceBuffer(),
context->GetQuadOffsetBuffer() + parray.GetQuadOffsetIndex() + handle->vertexOffset,
context->GetMaxValence(),
vertexData.GetInputDesc(),
inQ,
vertexData.GetOutputDesc(),
outQ, outdQu, outdQv);
} break;
case FarPatchTables::GREGORY : if (vertexData.IsBound()) {
evalGregory( v, u, cvs,
&context->GetVertexValenceTable()[0],
&context->GetQuadOffsetTable()[ parray.GetQuadOffsetIndex() + handle->vertexOffset ],
context->GetMaxValence(),
vertexData.inDesc,
vertexData.in.GetData(),
vertexData.outDesc,
vertexData.out.GetData()+offset,
vertexData.outDu.GetData()+offset,
vertexData.outDv.GetData()+offset );
} break;
case FarPatchTables::GREGORY_BOUNDARY :
if (vertexData.IsBound()) {
evalGregoryBoundary(v, u, cvs,
context->GetVertexValenceBuffer(),
context->GetQuadOffsetBuffer() + parray.GetQuadOffsetIndex() + handle->vertexOffset,
context->GetMaxValence(),
vertexData.GetInputDesc(),
inQ,
vertexData.GetOutputDesc(),
outQ, outdQu, outdQv);
} break;
case FarPatchTables::GREGORY_BOUNDARY :
if (vertexData.IsBound()) {
evalGregoryBoundary(v, u, cvs,
&context->GetVertexValenceTable()[0],
&context->GetQuadOffsetTable()[ parray.GetQuadOffsetIndex() + handle->vertexOffset ],
context->GetMaxValence(),
vertexData.inDesc,
vertexData.in.GetData(),
vertexData.outDesc,
vertexData.out.GetData()+offset,
vertexData.outDu.GetData()+offset,
vertexData.outDv.GetData()+offset );
} break;
default:
assert(0);
default:
assert(0);
}
}
OsdCpuEvalLimitContext::EvalData const & varyingData = context->GetVaryingData();
OsdCpuEvalLimitContext::VaryingData & varyingData = context->GetVaryingData();
if (varyingData.IsBound()) {
static int indices[5][4] = { {5, 6,10, 9}, // regular
@ -166,16 +176,18 @@ OsdCpuEvalLimitController::_EvalLimitSample( OpenSubdiv::OsdEvalCoords const & c
int type = (int)(parray.GetDescriptor().GetType() - FarPatchTables::REGULAR);
int offset = varyingData.outDesc.stride * index;
unsigned int zeroRing[4] = { cvs[indices[type][0]],
cvs[indices[type][1]],
cvs[indices[type][2]],
cvs[indices[type][3]] };
evalBilinear( v, u, zeroRing,
varyingData.GetInputDesc(),
varyingData.GetInputData(),
varyingData.GetOutputDesc(),
const_cast<float *>(varyingData.GetOutputData(index)) );
varyingData.inDesc,
varyingData.in.GetData(),
varyingData.outDesc,
varyingData.out.GetData()+offset);
}
@ -183,22 +195,22 @@ OsdCpuEvalLimitController::_EvalLimitSample( OpenSubdiv::OsdEvalCoords const & c
// for face-varying data. Although Hbr supports 3 additional smooth rule
// sets, the feature-adaptive patch interpolation code currently does not
// support them, and neither does this EvalContext.
OsdCpuEvalLimitContext::EvalData const & faceVaryingData = context->GetFaceVaryingData();
if (faceVaryingData.GetOutputData()) {
OsdCpuEvalLimitContext::FaceVaryingData & faceVaryingData = context->GetFaceVaryingData();
if (faceVaryingData.IsBound()) {
FarPatchTables::FVarDataTable const & fvarData = context->GetFVarData();
if (not fvarData.empty()) {
float const * fvar = &fvarData[ handle->patchIdx * 4 * context->GetFVarWidth() ];
int offset = faceVaryingData.outDesc.stride * index;
static unsigned int zeroRing[4] = {0,1,2,3};
evalBilinear( v, u, zeroRing,
faceVaryingData.GetInputDesc(),
fvar,
faceVaryingData.GetOutputDesc(),
const_cast<float *>(faceVaryingData.GetOutputData(index)) );
faceVaryingData.inDesc,
&fvarData[ handle->patchIdx * 4 * context->GetFVarWidth() ],
faceVaryingData.outDesc,
faceVaryingData.out.GetData()+offset);
}
}

View File

@ -130,7 +130,7 @@ public:
private:
int _EvalLimitSample( OpenSubdiv::OsdEvalCoords const & coords,
OsdCpuEvalLimitContext const * context,
OsdCpuEvalLimitContext * context,
unsigned int index );
};