Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc')
-rw-r--r--intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc287
1 files changed, 163 insertions, 124 deletions
diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc
index fa45c0119ec..c5dd4509976 100644
--- a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc
+++ b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc
@@ -54,109 +54,133 @@ using OpenSubdiv::Osd::CpuPatchTable;
using OpenSubdiv::Osd::CpuVertexBuffer;
using OpenSubdiv::Osd::PatchCoord;
-// TODO(sergey): Remove after official requirement bump for OSD version.
-#if OPENSUBDIV_VERSION_NUMBER >= 30200
-# define OPENSUBDIV_HAS_FVAR_EVALUATION
-#else
-# undef OPENSUBDIV_HAS_FVAR_EVALUATION
-#endif
-
namespace opensubdiv_capi {
namespace {
-// Helper class to wrap numerous of patch coordinates into a buffer.
-// Used to pass coordinates to the CPU evaluator. Other evaluators are not
-// supported.
-class PatchCoordBuffer : public vector<PatchCoord> {
+// Array implementation which stores small data on stack (or, rather, in the class itself).
+template<typename T, int kNumMaxElementsOnStack> class StackOrHeapArray {
public:
- static PatchCoordBuffer *Create(int size)
+ StackOrHeapArray()
+ : num_elements_(0), heap_elements_(NULL), num_heap_elements_(0), effective_elements_(NULL)
{
- PatchCoordBuffer *buffer = new PatchCoordBuffer();
- buffer->resize(size);
- return buffer;
}
- PatchCoord *BindCpuBuffer()
+ explicit StackOrHeapArray(int size) : StackOrHeapArray()
{
- return reinterpret_cast<PatchCoord *>(&(*this)[0]);
+ resize(size);
}
- int GetNumVertices()
+ ~StackOrHeapArray()
{
- return size();
+ delete[] heap_elements_;
}
- void UpdateData(const PatchCoord *patch_coords, int num_patch_coords)
+ int size() const
{
- memcpy(&(*this)[0],
- reinterpret_cast<const void *>(patch_coords),
- sizeof(PatchCoord) * num_patch_coords);
- }
-};
+ return num_elements_;
+ };
-// Helper class to wrap single of patch coord into a buffer. Used to pass
-// coordinates to the CPU evaluator. Other evaluators are not supported.
-class SinglePatchCoordBuffer {
- public:
- static SinglePatchCoordBuffer *Create()
+ T *data()
{
- return new SinglePatchCoordBuffer();
+ return effective_elements_;
}
- SinglePatchCoordBuffer()
+ void resize(int num_elements)
{
+ const int old_num_elements = num_elements_;
+ num_elements_ = num_elements;
+ // Early output if allcoation size did not change, or allocation size is smaller.
+ // We never re-allocate, sacrificing some memory over performance.
+ if (old_num_elements >= num_elements) {
+ return;
+ }
+ // Simple case: no previously allocated buffer, can simply do one allocation.
+ if (effective_elements_ == NULL) {
+ effective_elements_ = allocate(num_elements);
+ return;
+ }
+ // Make new allocation, and copy elements if needed.
+ T *old_buffer = effective_elements_;
+ effective_elements_ = allocate(num_elements);
+ if (old_buffer != effective_elements_) {
+ memcpy(effective_elements_, old_buffer, sizeof(T) * min(old_num_elements, num_elements));
+ }
+ if (old_buffer != stack_elements_) {
+ delete[] old_buffer;
+ }
}
- explicit SinglePatchCoordBuffer(const PatchCoord &patch_coord) : patch_coord_(patch_coord)
+ protected:
+ T *allocate(int num_elements)
{
+ if (num_elements < kNumMaxElementsOnStack) {
+ return stack_elements_;
+ }
+ heap_elements_ = new T[num_elements];
+ return heap_elements_;
}
- PatchCoord *BindCpuBuffer()
- {
- return &patch_coord_;
- }
+ // Number of elements in the buffer.
+ int num_elements_;
- int GetNumVertices()
+ // Elements which are allocated on a stack (or, rather, in the same allocation as the buffer
+ // itself).
+ // Is used as long as buffer is smaller than kNumMaxElementsOnStack.
+ T stack_elements_[kNumMaxElementsOnStack];
+
+ // Heap storage for buffer larger than kNumMaxElementsOnStack.
+ T *heap_elements_;
+ int num_heap_elements_;
+
+ // Depending on the current buffer size points to rither stack_elements_ or heap_elements_.
+ T *effective_elements_;
+};
+
+// 32 is a number of inner vertices along the patch size at subdivision level 6.
+typedef StackOrHeapArray<PatchCoord, 32 * 32> StackOrHeapPatchCoordArray;
+
+// Buffer which implements API required by OpenSubdiv and uses an existing memory as an underlying
+// storage.
+template<typename T> class RawDataWrapperBuffer {
+ public:
+ RawDataWrapperBuffer(T *data) : data_(data)
{
- return 1;
}
- void UpdateData(const PatchCoord &patch_coord)
+ T *BindCpuBuffer()
{
- patch_coord_ = patch_coord;
+ return data_;
}
+ // TODO(sergey): Support UpdateData().
+
protected:
- PatchCoord patch_coord_;
+ T *data_;
};
-// Helper class which is aimed to be used in cases when buffer is small enough
-// and better to be allocated in stack rather than in heap.
-//
-// TODO(sergey): Check if bare arrays could be used by CPU evaluator.
-template<int element_size, int num_vertices> class StackAllocatedBuffer {
+template<typename T> class RawDataWrapperVertexBuffer : public RawDataWrapperBuffer<T> {
public:
- static PatchCoordBuffer *Create(int /*size*/)
+ RawDataWrapperVertexBuffer(T *data, int num_vertices)
+ : RawDataWrapperBuffer<T>(data), num_vertices_(num_vertices)
{
- // TODO(sergey): Validate that requested size is smaller than static
- // stack memory size.
- return new StackAllocatedBuffer<element_size, num_vertices>();
- }
-
- float *BindCpuBuffer()
- {
- return &data_[0];
}
int GetNumVertices()
{
- return num_vertices;
+ return num_vertices_;
}
- // TODO(sergey): Support UpdateData().
protected:
- float data_[element_size * num_vertices];
+ int num_vertices_;
+};
+
+class ConstPatchCoordWrapperBuffer : public RawDataWrapperVertexBuffer<const PatchCoord> {
+ public:
+ ConstPatchCoordWrapperBuffer(const PatchCoord *data, int num_vertices)
+ : RawDataWrapperVertexBuffer(data, num_vertices)
+ {
+ }
};
template<typename EVAL_VERTEX_BUFFER,
@@ -217,11 +241,12 @@ class FaceVaryingVolatileEval {
device_context_);
}
- void evalPatch(const PatchCoord &patch_coord, float face_varying[2])
+ // NOTE: face_varying must point to a memory of at least float[2]*num_patch_coords.
+ void evalPatches(const PatchCoord *patch_coord, const int num_patch_coords, float *face_varying)
{
- StackAllocatedBuffer<2, 1> face_varying_data;
+ RawDataWrapperBuffer<float> face_varying_data(face_varying);
BufferDescriptor face_varying_desc(0, 2, 2);
- SinglePatchCoordBuffer patch_coord_buffer(patch_coord);
+ ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
evaluator_cache_, src_face_varying_desc_, face_varying_desc, device_context_);
EVALUATOR::EvalPatchesFaceVarying(src_face_varying_data_,
@@ -234,8 +259,6 @@ class FaceVaryingVolatileEval {
face_varying_channel_,
eval_instance,
device_context_);
- const float *refined_face_varying = face_varying_data.BindCpuBuffer();
- memcpy(face_varying, refined_face_varying, sizeof(float) * 2);
}
protected:
@@ -297,7 +320,6 @@ class VolatileEvalOutput {
src_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_vertices, device_context_);
src_varying_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_vertices, device_context_);
patch_table_ = PATCH_TABLE::Create(patch_table, device_context_);
- patch_coords_ = NULL;
vertex_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(vertex_stencils,
device_context_);
varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(varying_stencils,
@@ -398,74 +420,66 @@ class VolatileEvalOutput {
}
}
- void evalPatchCoord(const PatchCoord &patch_coord, float P[3])
+ // NOTE: P must point to a memory of at least float[3]*num_patch_coords.
+ void evalPatches(const PatchCoord *patch_coord, const int num_patch_coords, float *P)
{
- StackAllocatedBuffer<6, 1> vertex_data;
- // TODO(sergey): Varying data is interleaved in vertex array, so need to
- // adjust stride if there is a varying data.
- // BufferDescriptor vertex_desc(0, 3, 6);
- BufferDescriptor vertex_desc(0, 3, 3);
- SinglePatchCoordBuffer patch_coord_buffer(patch_coord);
+ RawDataWrapperBuffer<float> P_data(P);
+ // TODO(sergey): Support interleaved vertex-varying data.
+ BufferDescriptor P_desc(0, 3, 3);
+ ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
- evaluator_cache_, src_desc_, vertex_desc, device_context_);
+ evaluator_cache_, src_desc_, P_desc, device_context_);
EVALUATOR::EvalPatches(src_data_,
src_desc_,
- &vertex_data,
- vertex_desc,
+ &P_data,
+ P_desc,
patch_coord_buffer.GetNumVertices(),
&patch_coord_buffer,
patch_table_,
eval_instance,
device_context_);
- const float *refined_vertices = vertex_data.BindCpuBuffer();
- memcpy(P, refined_vertices, sizeof(float) * 3);
}
- void evalPatchesWithDerivatives(const PatchCoord &patch_coord,
- float P[3],
- float dPdu[3],
- float dPdv[3])
+ // NOTE: P, dPdu, dPdv must point to a memory of at least float[3]*num_patch_coords.
+ void evalPatchesWithDerivatives(const PatchCoord *patch_coord,
+ const int num_patch_coords,
+ float *P,
+ float *dPdu,
+ float *dPdv)
{
- StackAllocatedBuffer<6, 1> vertex_data, derivatives;
- // TODO(sergey): Varying data is interleaved in vertex array, so need to
- // adjust stride if there is a varying data.
- // BufferDescriptor vertex_desc(0, 3, 6);
- BufferDescriptor vertex_desc(0, 3, 3);
- BufferDescriptor du_desc(0, 3, 6), dv_desc(3, 3, 6);
- SinglePatchCoordBuffer patch_coord_buffer(patch_coord);
+ assert(dPdu);
+ assert(dPdv);
+ RawDataWrapperBuffer<float> P_data(P);
+ RawDataWrapperBuffer<float> dPdu_data(dPdu), dPdv_data(dPdv);
+ // TODO(sergey): Support interleaved vertex-varying data.
+ BufferDescriptor P_desc(0, 3, 3);
+ BufferDescriptor dpDu_desc(0, 3, 3), pPdv_desc(0, 3, 3);
+ ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
- evaluator_cache_, src_desc_, vertex_desc, du_desc, dv_desc, device_context_);
+ evaluator_cache_, src_desc_, P_desc, dpDu_desc, pPdv_desc, device_context_);
EVALUATOR::EvalPatches(src_data_,
src_desc_,
- &vertex_data,
- vertex_desc,
- &derivatives,
- du_desc,
- &derivatives,
- dv_desc,
+ &P_data,
+ P_desc,
+ &dPdu_data,
+ dpDu_desc,
+ &dPdv_data,
+ pPdv_desc,
patch_coord_buffer.GetNumVertices(),
&patch_coord_buffer,
patch_table_,
eval_instance,
device_context_);
- const float *refined_vertices = vertex_data.BindCpuBuffer();
- memcpy(P, refined_vertices, sizeof(float) * 3);
- if (dPdu != NULL || dPdv != NULL) {
- const float *refined_derivatives = derivatives.BindCpuBuffer();
- if (dPdu != NULL) {
- memcpy(dPdu, refined_derivatives, sizeof(float) * 3);
- }
- if (dPdv != NULL) {
- memcpy(dPdv, refined_derivatives + 3, sizeof(float) * 3);
- }
- }
}
- void evalPatchVarying(const PatchCoord &patch_coord, float varying[3])
+ // NOTE: varying must point to a memory of at least float[3]*num_patch_coords.
+ void evalPatchesVarying(const PatchCoord *patch_coord,
+ const int num_patch_coords,
+ float *varying)
{
- StackAllocatedBuffer<6, 1> varying_data;
+ RawDataWrapperBuffer<float> varying_data(varying);
BufferDescriptor varying_desc(3, 3, 6);
- SinglePatchCoordBuffer patch_coord_buffer(patch_coord);
+ ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
evaluator_cache_, src_varying_desc_, varying_desc, device_context_);
EVALUATOR::EvalPatchesVarying(src_varying_data_,
@@ -477,23 +491,22 @@ class VolatileEvalOutput {
patch_table_,
eval_instance,
device_context_);
- const float *refined_varying = varying_data.BindCpuBuffer();
- memcpy(varying, refined_varying, sizeof(float) * 3);
}
- void evalPatchFaceVarying(const int face_varying_channel,
- const PatchCoord &patch_coord,
- float face_varying[2])
+ void evalPatchesFaceVarying(const int face_varying_channel,
+ const PatchCoord *patch_coord,
+ const int num_patch_coords,
+ float face_varying[2])
{
assert(face_varying_channel >= 0);
assert(face_varying_channel < face_varying_evaluators.size());
- face_varying_evaluators[face_varying_channel]->evalPatch(patch_coord, face_varying);
+ face_varying_evaluators[face_varying_channel]->evalPatches(
+ patch_coord, num_patch_coords, face_varying);
}
private:
SRC_VERTEX_BUFFER *src_data_;
SRC_VERTEX_BUFFER *src_varying_data_;
- PatchCoordBuffer *patch_coords_;
PATCH_TABLE *patch_table_;
BufferDescriptor src_desc_;
BufferDescriptor src_varying_desc_;
@@ -510,6 +523,19 @@ class VolatileEvalOutput {
DEVICE_CONTEXT *device_context_;
};
+void convertPatchCoordsToArray(const OpenSubdiv_PatchCoord *patch_coords,
+ const int num_patch_coords,
+ const OpenSubdiv::Far::PatchMap *patch_map,
+ StackOrHeapPatchCoordArray *array)
+{
+ array->resize(num_patch_coords);
+ for (int i = 0; i < num_patch_coords; ++i) {
+ const PatchTable::PatchHandle *handle = patch_map->FindPatch(
+ patch_coords[i].ptex_face, patch_coords[i].u, patch_coords[i].v);
+ (array->data())[i] = PatchCoord(*handle, patch_coords[i].u, patch_coords[i].v);
+ }
+}
+
} // namespace
// Note: Define as a class instead of typedcef to make it possible
@@ -653,10 +679,10 @@ void CpuEvalOutputAPI::evaluateLimit(const int ptex_face_index,
const PatchTable::PatchHandle *handle = patch_map_->FindPatch(ptex_face_index, face_u, face_v);
PatchCoord patch_coord(*handle, face_u, face_v);
if (dPdu != NULL || dPdv != NULL) {
- implementation_->evalPatchesWithDerivatives(patch_coord, P, dPdu, dPdv);
+ implementation_->evalPatchesWithDerivatives(&patch_coord, 1, P, dPdu, dPdv);
}
else {
- implementation_->evalPatchCoord(patch_coord, P);
+ implementation_->evalPatches(&patch_coord, 1, P);
}
}
@@ -671,7 +697,7 @@ void CpuEvalOutputAPI::evaluateVarying(const int ptex_face_index,
assert(face_v <= 1.0f);
const PatchTable::PatchHandle *handle = patch_map_->FindPatch(ptex_face_index, face_u, face_v);
PatchCoord patch_coord(*handle, face_u, face_v);
- implementation_->evalPatchVarying(patch_coord, varying);
+ implementation_->evalPatchesVarying(&patch_coord, 1, varying);
}
void CpuEvalOutputAPI::evaluateFaceVarying(const int face_varying_channel,
@@ -686,7 +712,24 @@ void CpuEvalOutputAPI::evaluateFaceVarying(const int face_varying_channel,
assert(face_v <= 1.0f);
const PatchTable::PatchHandle *handle = patch_map_->FindPatch(ptex_face_index, face_u, face_v);
PatchCoord patch_coord(*handle, face_u, face_v);
- implementation_->evalPatchFaceVarying(face_varying_channel, patch_coord, face_varying);
+ implementation_->evalPatchesFaceVarying(face_varying_channel, &patch_coord, 1, face_varying);
+}
+
+void CpuEvalOutputAPI::evaluatePatchesLimit(const OpenSubdiv_PatchCoord *patch_coords,
+ const int num_patch_coords,
+ float *P,
+ float *dPdu,
+ float *dPdv)
+{
+ StackOrHeapPatchCoordArray patch_coords_array;
+ convertPatchCoordsToArray(patch_coords, num_patch_coords, patch_map_, &patch_coords_array);
+ if (dPdu != NULL || dPdv != NULL) {
+ implementation_->evalPatchesWithDerivatives(
+ patch_coords_array.data(), num_patch_coords, P, dPdu, dPdv);
+ }
+ else {
+ implementation_->evalPatches(patch_coords_array.data(), num_patch_coords, P);
+ }
}
} // namespace opensubdiv_capi
@@ -757,7 +800,6 @@ OpenSubdiv_EvaluatorInternal *openSubdiv_createEvaluatorInternal(
}
// Face warying stencil.
vector<const StencilTable *> all_face_varying_stencils;
-#ifdef OPENSUBDIV_HAS_FVAR_EVALUATION
all_face_varying_stencils.reserve(num_face_varying_channels);
for (int face_varying_channel = 0; face_varying_channel < num_face_varying_channels;
++face_varying_channel) {
@@ -769,7 +811,6 @@ OpenSubdiv_EvaluatorInternal *openSubdiv_createEvaluatorInternal(
all_face_varying_stencils.push_back(
StencilTableFactory::Create(*refiner, face_varying_stencil_options));
}
-#endif
// Generate bi-cubic patch table for the limit surface.
// TODO(sergey): Ideally we would want to expose end-cap settings via
// C-API to make it more generic. Currently it matches old Blender's
@@ -800,7 +841,6 @@ OpenSubdiv_EvaluatorInternal *openSubdiv_createEvaluatorInternal(
varying_stencils = table;
}
}
-#ifdef OPENSUBDIV_HAS_FVAR_EVALUATION
for (int face_varying_channel = 0; face_varying_channel < num_face_varying_channels;
++face_varying_channel) {
const StencilTable *table = StencilTableFactory::AppendLocalPointStencilTableFaceVarying(
@@ -813,7 +853,6 @@ OpenSubdiv_EvaluatorInternal *openSubdiv_createEvaluatorInternal(
all_face_varying_stencils[face_varying_channel] = table;
}
}
-#endif
// Create OpenSubdiv's CPU side evaluator.
// TODO(sergey): Make it possible to use different evaluators.
opensubdiv_capi::CpuEvalOutput *eval_output = new opensubdiv_capi::CpuEvalOutput(