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:
authorSergey Sharybin <sergey.vfx@gmail.com>2019-10-16 15:59:18 +0300
committerSergey Sharybin <sergey.vfx@gmail.com>2019-10-30 17:15:56 +0300
commitf3059723771b90337b126a87a58b1ada981a21b1 (patch)
tree5443b7fe777d60f47ad1ca41a8dcd8e43977cffc /intern/opensubdiv
parent05ee67a7c82b1c35add60cbf719f370b28538ac9 (diff)
OpenSubdiv: Initial implementation of batched evaluation
The idea is to give multiple coordinates to evaluator and evaluate them all at once, avoiding any possible overhead.
Diffstat (limited to 'intern/opensubdiv')
-rw-r--r--intern/opensubdiv/internal/opensubdiv_evaluator.cc13
-rw-r--r--intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc112
-rw-r--r--intern/opensubdiv/internal/opensubdiv_evaluator_internal.h13
-rw-r--r--intern/opensubdiv/opensubdiv_capi_type.h7
-rw-r--r--intern/opensubdiv/opensubdiv_evaluator_capi.h14
5 files changed, 159 insertions, 0 deletions
diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator.cc b/intern/opensubdiv/internal/opensubdiv_evaluator.cc
index 2500691885c..4f5a1db82ca 100644
--- a/intern/opensubdiv/internal/opensubdiv_evaluator.cc
+++ b/intern/opensubdiv/internal/opensubdiv_evaluator.cc
@@ -102,6 +102,17 @@ void evaluateLimit(OpenSubdiv_Evaluator *evaluator,
evaluator->internal->eval_output->evaluateLimit(ptex_face_index, face_u, face_v, P, dPdu, dPdv);
}
+void evaluatePatchesLimit(OpenSubdiv_Evaluator *evaluator,
+ const OpenSubdiv_PatchCoord *patch_coords,
+ const int num_patch_coords,
+ float *P,
+ float *dPdu,
+ float *dPdv)
+{
+ evaluator->internal->eval_output->evaluatePatchesLimit(
+ patch_coords, num_patch_coords, P, dPdu, dPdv);
+}
+
void evaluateVarying(OpenSubdiv_Evaluator *evaluator,
const int ptex_face_index,
float face_u,
@@ -137,6 +148,8 @@ void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator)
evaluator->evaluateLimit = evaluateLimit;
evaluator->evaluateVarying = evaluateVarying;
evaluator->evaluateFaceVarying = evaluateFaceVarying;
+
+ evaluator->evaluatePatchesLimit = evaluatePatchesLimit;
}
} // namespace
diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc
index acd8472b5f1..c5dd4509976 100644
--- a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc
+++ b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc
@@ -58,6 +58,88 @@ namespace opensubdiv_capi {
namespace {
+// Array implementation which stores small data on stack (or, rather, in the class itself).
+template<typename T, int kNumMaxElementsOnStack> class StackOrHeapArray {
+ public:
+ StackOrHeapArray()
+ : num_elements_(0), heap_elements_(NULL), num_heap_elements_(0), effective_elements_(NULL)
+ {
+ }
+
+ explicit StackOrHeapArray(int size) : StackOrHeapArray()
+ {
+ resize(size);
+ }
+
+ ~StackOrHeapArray()
+ {
+ delete[] heap_elements_;
+ }
+
+ int size() const
+ {
+ return num_elements_;
+ };
+
+ T *data()
+ {
+ return effective_elements_;
+ }
+
+ 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;
+ }
+ }
+
+ protected:
+ T *allocate(int num_elements)
+ {
+ if (num_elements < kNumMaxElementsOnStack) {
+ return stack_elements_;
+ }
+ heap_elements_ = new T[num_elements];
+ return heap_elements_;
+ }
+
+ // Number of elements in the buffer.
+ int num_elements_;
+
+ // 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 {
@@ -441,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
@@ -620,6 +715,23 @@ void CpuEvalOutputAPI::evaluateFaceVarying(const int face_varying_channel,
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
OpenSubdiv_EvaluatorInternal::OpenSubdiv_EvaluatorInternal()
diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.h b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.h
index 7c963227d17..392633944c6 100644
--- a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.h
+++ b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.h
@@ -26,6 +26,7 @@
#include <opensubdiv/far/patchMap.h>
#include <opensubdiv/far/patchTable.h>
+struct OpenSubdiv_PatchCoord;
struct OpenSubdiv_TopologyRefiner;
namespace opensubdiv_capi {
@@ -114,6 +115,18 @@ class CpuEvalOutputAPI {
float face_v,
float face_varying[2]);
+ // Batched evaluation of multiple input coordinates.
+
+ // Evaluate given ptex face at given bilinear coordinate.
+ // If derivatives are NULL, they will not be evaluated.
+ //
+ // NOTE: Output arrays must point to a memory of size float[3]*num_patch_coords.
+ void evaluatePatchesLimit(const OpenSubdiv_PatchCoord *patch_coords,
+ const int num_patch_coords,
+ float *P,
+ float *dPdu,
+ float *dPdv);
+
protected:
CpuEvalOutput *implementation_;
OpenSubdiv::Far::PatchMap *patch_map_;
diff --git a/intern/opensubdiv/opensubdiv_capi_type.h b/intern/opensubdiv/opensubdiv_capi_type.h
index 35eeb71dede..e759c5f43b0 100644
--- a/intern/opensubdiv/opensubdiv_capi_type.h
+++ b/intern/opensubdiv/opensubdiv_capi_type.h
@@ -58,6 +58,13 @@ typedef enum OpenSubdiv_FVarLinearInterpolation {
OSD_FVAR_LINEAR_INTERPOLATION_ALL,
} OpenSubdiv_FVarLinearInterpolation;
+typedef struct OpenSubdiv_PatchCoord {
+ int ptex_face;
+
+ // Parametric location on patch.
+ float u, v;
+} OpenSubdiv_PatchCoord;
+
#ifdef __cplusplus
}
#endif
diff --git a/intern/opensubdiv/opensubdiv_evaluator_capi.h b/intern/opensubdiv/opensubdiv_evaluator_capi.h
index ceb0c58feba..1572d01b851 100644
--- a/intern/opensubdiv/opensubdiv_evaluator_capi.h
+++ b/intern/opensubdiv/opensubdiv_evaluator_capi.h
@@ -24,6 +24,7 @@ extern "C" {
#endif
struct OpenSubdiv_EvaluatorInternal;
+struct OpenSubdiv_PatchCoord;
struct OpenSubdiv_TopologyRefiner;
typedef struct OpenSubdiv_Evaluator {
@@ -108,6 +109,19 @@ typedef struct OpenSubdiv_Evaluator {
float face_v,
float face_varying[2]);
+ // Batched evaluation of multiple input coordinates.
+
+ // Evaluate limit surface.
+ // If derivatives are NULL, they will not be evaluated.
+ //
+ // NOTE: Output arrays must point to a memory of size float[3]*num_patch_coords.
+ void (*evaluatePatchesLimit)(struct OpenSubdiv_Evaluator *evaluator,
+ const struct OpenSubdiv_PatchCoord *patch_coords,
+ const int num_patch_coords,
+ float *P,
+ float *dPdu,
+ float *dPdv);
+
// Internal storage for the use in this module only.
//
// This is where actual OpenSubdiv's evaluator is living.