From 4886a704b313e480edba8e250c38387b30669ea4 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 19 May 2020 10:46:42 +0200 Subject: OpenSubdiv: Refactor, move evaluator to own folder --- intern/opensubdiv/CMakeLists.txt | 8 +- .../internal/evaluator/evaluator_capi.cc | 169 ++++ .../internal/evaluator/evaluator_impl.cc | 877 +++++++++++++++++++++ .../opensubdiv/internal/evaluator/evaluator_impl.h | 158 ++++ intern/opensubdiv/internal/opensubdiv_evaluator.cc | 170 ---- .../internal/opensubdiv_evaluator_internal.cc | 877 --------------------- .../internal/opensubdiv_evaluator_internal.h | 158 ---- intern/opensubdiv/opensubdiv_evaluator_capi.h | 6 +- 8 files changed, 1211 insertions(+), 1212 deletions(-) create mode 100644 intern/opensubdiv/internal/evaluator/evaluator_capi.cc create mode 100644 intern/opensubdiv/internal/evaluator/evaluator_impl.cc create mode 100644 intern/opensubdiv/internal/evaluator/evaluator_impl.h delete mode 100644 intern/opensubdiv/internal/opensubdiv_evaluator.cc delete mode 100644 intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc delete mode 100644 intern/opensubdiv/internal/opensubdiv_evaluator_internal.h (limited to 'intern') diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt index 5b5aebd88b8..90895cf6ed3 100644 --- a/intern/opensubdiv/CMakeLists.txt +++ b/intern/opensubdiv/CMakeLists.txt @@ -66,6 +66,11 @@ if(WITH_OPENSUBDIV) internal/device/device_context_openmp.cc internal/device/device_context_openmp.h + # Evaluator. + internal/evaluator/evaluator_capi.cc + internal/evaluator/evaluator_impl.cc + internal/evaluator/evaluator_impl.h + # Topology. internal/topology/topology_refiner_capi.cc internal/topology/topology_refiner_factory.cc @@ -74,12 +79,9 @@ if(WITH_OPENSUBDIV) internal/opensubdiv.cc internal/opensubdiv_converter_internal.cc - internal/opensubdiv_evaluator.cc - internal/opensubdiv_evaluator_internal.cc internal/opensubdiv_util.cc internal/opensubdiv_converter_internal.h - internal/opensubdiv_evaluator_internal.h internal/opensubdiv_util.h ) diff --git a/intern/opensubdiv/internal/evaluator/evaluator_capi.cc b/intern/opensubdiv/internal/evaluator/evaluator_capi.cc new file mode 100644 index 00000000000..4b12206e103 --- /dev/null +++ b/intern/opensubdiv/internal/evaluator/evaluator_capi.cc @@ -0,0 +1,169 @@ +// Copyright 2015 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#include "opensubdiv_evaluator_capi.h" + +#include "MEM_guardedalloc.h" +#include + +#include "internal/evaluator/evaluator_impl.h" + +namespace { + +void setCoarsePositions(OpenSubdiv_Evaluator *evaluator, + const float *positions, + const int start_vertex_index, + const int num_vertices) +{ + evaluator->impl->eval_output->setCoarsePositions(positions, start_vertex_index, num_vertices); +} + +void setVaryingData(OpenSubdiv_Evaluator *evaluator, + const float *varying_data, + const int start_vertex_index, + const int num_vertices) +{ + evaluator->impl->eval_output->setVaryingData(varying_data, start_vertex_index, num_vertices); +} + +void setFaceVaryingData(OpenSubdiv_Evaluator *evaluator, + const int face_varying_channel, + const float *face_varying_data, + const int start_vertex_index, + const int num_vertices) +{ + evaluator->impl->eval_output->setFaceVaryingData( + face_varying_channel, face_varying_data, start_vertex_index, num_vertices); +} + +void setCoarsePositionsFromBuffer(OpenSubdiv_Evaluator *evaluator, + const void *buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices) +{ + evaluator->impl->eval_output->setCoarsePositionsFromBuffer( + buffer, start_offset, stride, start_vertex_index, num_vertices); +} + +void setVaryingDataFromBuffer(OpenSubdiv_Evaluator *evaluator, + const void *buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices) +{ + evaluator->impl->eval_output->setVaryingDataFromBuffer( + buffer, start_offset, stride, start_vertex_index, num_vertices); +} + +void setFaceVaryingDataFromBuffer(OpenSubdiv_Evaluator *evaluator, + const int face_varying_channel, + const void *buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices) +{ + evaluator->impl->eval_output->setFaceVaryingDataFromBuffer( + face_varying_channel, buffer, start_offset, stride, start_vertex_index, num_vertices); +} + +void refine(OpenSubdiv_Evaluator *evaluator) +{ + evaluator->impl->eval_output->refine(); +} + +void evaluateLimit(OpenSubdiv_Evaluator *evaluator, + const int ptex_face_index, + const float face_u, + const float face_v, + float P[3], + float dPdu[3], + float dPdv[3]) +{ + evaluator->impl->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->impl->eval_output->evaluatePatchesLimit( + patch_coords, num_patch_coords, P, dPdu, dPdv); +} + +void evaluateVarying(OpenSubdiv_Evaluator *evaluator, + const int ptex_face_index, + float face_u, + float face_v, + float varying[3]) +{ + evaluator->impl->eval_output->evaluateVarying(ptex_face_index, face_u, face_v, varying); +} + +void evaluateFaceVarying(OpenSubdiv_Evaluator *evaluator, + const int face_varying_channel, + const int ptex_face_index, + float face_u, + float face_v, + float face_varying[2]) +{ + evaluator->impl->eval_output->evaluateFaceVarying( + face_varying_channel, ptex_face_index, face_u, face_v, face_varying); +} + +void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator) +{ + evaluator->setCoarsePositions = setCoarsePositions; + evaluator->setVaryingData = setVaryingData; + evaluator->setFaceVaryingData = setFaceVaryingData; + + evaluator->setCoarsePositionsFromBuffer = setCoarsePositionsFromBuffer; + evaluator->setVaryingDataFromBuffer = setVaryingDataFromBuffer; + evaluator->setFaceVaryingDataFromBuffer = setFaceVaryingDataFromBuffer; + + evaluator->refine = refine; + + evaluator->evaluateLimit = evaluateLimit; + evaluator->evaluateVarying = evaluateVarying; + evaluator->evaluateFaceVarying = evaluateFaceVarying; + + evaluator->evaluatePatchesLimit = evaluatePatchesLimit; +} + +} // namespace + +OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner( + OpenSubdiv_TopologyRefiner *topology_refiner) +{ + OpenSubdiv_Evaluator *evaluator = OBJECT_GUARDED_NEW(OpenSubdiv_Evaluator); + assignFunctionPointers(evaluator); + evaluator->impl = openSubdiv_createEvaluatorInternal(topology_refiner); + return evaluator; +} + +void openSubdiv_deleteEvaluator(OpenSubdiv_Evaluator *evaluator) +{ + openSubdiv_deleteEvaluatorInternal(evaluator->impl); + OBJECT_GUARDED_DELETE(evaluator, OpenSubdiv_Evaluator); +} diff --git a/intern/opensubdiv/internal/evaluator/evaluator_impl.cc b/intern/opensubdiv/internal/evaluator/evaluator_impl.cc new file mode 100644 index 00000000000..7c80fceb51e --- /dev/null +++ b/intern/opensubdiv/internal/evaluator/evaluator_impl.cc @@ -0,0 +1,877 @@ +// Copyright 2018 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#include "internal/evaluator/evaluator_impl.h" + +#include +#include + +#ifdef _MSC_VER +# include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "internal/opensubdiv_util.h" +#include "internal/topology/topology_refiner_impl.h" +#include "opensubdiv_topology_refiner_capi.h" + +using OpenSubdiv::Far::PatchMap; +using OpenSubdiv::Far::PatchTable; +using OpenSubdiv::Far::PatchTableFactory; +using OpenSubdiv::Far::StencilTable; +using OpenSubdiv::Far::StencilTableFactory; +using OpenSubdiv::Far::TopologyRefiner; +using OpenSubdiv::Osd::BufferDescriptor; +using OpenSubdiv::Osd::CpuEvaluator; +using OpenSubdiv::Osd::CpuPatchTable; +using OpenSubdiv::Osd::CpuVertexBuffer; +using OpenSubdiv::Osd::PatchCoord; + +namespace blender { +namespace opensubdiv { + +namespace { + +// Array implementation which stores small data on stack (or, rather, in the class itself). +template 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 StackOrHeapPatchCoordArray; + +// Buffer which implements API required by OpenSubdiv and uses an existing memory as an underlying +// storage. +template class RawDataWrapperBuffer { + public: + RawDataWrapperBuffer(T *data) : data_(data) + { + } + + T *BindCpuBuffer() + { + return data_; + } + + // TODO(sergey): Support UpdateData(). + + protected: + T *data_; +}; + +template class RawDataWrapperVertexBuffer : public RawDataWrapperBuffer { + public: + RawDataWrapperVertexBuffer(T *data, int num_vertices) + : RawDataWrapperBuffer(data), num_vertices_(num_vertices) + { + } + + int GetNumVertices() + { + return num_vertices_; + } + + protected: + int num_vertices_; +}; + +class ConstPatchCoordWrapperBuffer : public RawDataWrapperVertexBuffer { + public: + ConstPatchCoordWrapperBuffer(const PatchCoord *data, int num_vertices) + : RawDataWrapperVertexBuffer(data, num_vertices) + { + } +}; + +template +class FaceVaryingVolatileEval { + public: + typedef OpenSubdiv::Osd::EvaluatorCacheT EvaluatorCache; + + FaceVaryingVolatileEval(int face_varying_channel, + const StencilTable *face_varying_stencils, + int face_varying_width, + PATCH_TABLE *patch_table, + EvaluatorCache *evaluator_cache = NULL, + DEVICE_CONTEXT *device_context = NULL) + : face_varying_channel_(face_varying_channel), + src_face_varying_desc_(0, face_varying_width, face_varying_width), + patch_table_(patch_table), + evaluator_cache_(evaluator_cache), + device_context_(device_context) + { + using OpenSubdiv::Osd::convertToCompatibleStencilTable; + num_coarse_face_varying_vertices_ = face_varying_stencils->GetNumControlVertices(); + const int num_total_face_varying_vertices = face_varying_stencils->GetNumControlVertices() + + face_varying_stencils->GetNumStencils(); + src_face_varying_data_ = EVAL_VERTEX_BUFFER::Create( + 2, num_total_face_varying_vertices, device_context); + face_varying_stencils_ = convertToCompatibleStencilTable(face_varying_stencils, + device_context_); + } + + ~FaceVaryingVolatileEval() + { + delete src_face_varying_data_; + delete face_varying_stencils_; + } + + void updateData(const float *src, int start_vertex, int num_vertices) + { + src_face_varying_data_->UpdateData(src, start_vertex, num_vertices, device_context_); + } + + void refine() + { + BufferDescriptor dst_face_varying_desc = src_face_varying_desc_; + dst_face_varying_desc.offset += num_coarse_face_varying_vertices_ * + src_face_varying_desc_.stride; + const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator( + evaluator_cache_, src_face_varying_desc_, dst_face_varying_desc, device_context_); + EVALUATOR::EvalStencils(src_face_varying_data_, + src_face_varying_desc_, + src_face_varying_data_, + dst_face_varying_desc, + face_varying_stencils_, + eval_instance, + device_context_); + } + + // 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) + { + RawDataWrapperBuffer face_varying_data(face_varying); + BufferDescriptor face_varying_desc(0, 2, 2); + ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords); + const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator( + evaluator_cache_, src_face_varying_desc_, face_varying_desc, device_context_); + EVALUATOR::EvalPatchesFaceVarying(src_face_varying_data_, + src_face_varying_desc_, + &face_varying_data, + face_varying_desc, + patch_coord_buffer.GetNumVertices(), + &patch_coord_buffer, + patch_table_, + face_varying_channel_, + eval_instance, + device_context_); + } + + protected: + int face_varying_channel_; + + BufferDescriptor src_face_varying_desc_; + + int num_coarse_face_varying_vertices_; + EVAL_VERTEX_BUFFER *src_face_varying_data_; + const STENCIL_TABLE *face_varying_stencils_; + + // NOTE: We reference this, do not own it. + PATCH_TABLE *patch_table_; + + EvaluatorCache *evaluator_cache_; + DEVICE_CONTEXT *device_context_; +}; + +// Volatile evaluator which can be used from threads. +// +// TODO(sergey): Make it possible to evaluate coordinates in chunks. +// TODO(sergey): Make it possible to evaluate multiple face varying layers. +// (or maybe, it's cheap to create new evaluator for existing +// topology to evaluate all needed face varying layers?) +template +class VolatileEvalOutput { + public: + typedef OpenSubdiv::Osd::EvaluatorCacheT EvaluatorCache; + typedef FaceVaryingVolatileEval + FaceVaryingEval; + + VolatileEvalOutput(const StencilTable *vertex_stencils, + const StencilTable *varying_stencils, + const vector &all_face_varying_stencils, + const int face_varying_width, + const PatchTable *patch_table, + EvaluatorCache *evaluator_cache = NULL, + DEVICE_CONTEXT *device_context = NULL) + : src_desc_(0, 3, 3), + src_varying_desc_(0, 3, 3), + face_varying_width_(face_varying_width), + evaluator_cache_(evaluator_cache), + device_context_(device_context) + { + // Total number of vertices = coarse points + refined points + local points. + int num_total_vertices = vertex_stencils->GetNumControlVertices() + + vertex_stencils->GetNumStencils(); + num_coarse_vertices_ = vertex_stencils->GetNumControlVertices(); + using OpenSubdiv::Osd::convertToCompatibleStencilTable; + 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_); + vertex_stencils_ = convertToCompatibleStencilTable(vertex_stencils, + device_context_); + varying_stencils_ = convertToCompatibleStencilTable(varying_stencils, + device_context_); + // Create evaluators for every face varying channel. + face_varying_evaluators.reserve(all_face_varying_stencils.size()); + int face_varying_channel = 0; + foreach (const StencilTable *face_varying_stencils, all_face_varying_stencils) { + face_varying_evaluators.push_back(new FaceVaryingEval(face_varying_channel, + face_varying_stencils, + face_varying_width, + patch_table_, + evaluator_cache_, + device_context_)); + ++face_varying_channel; + } + } + + ~VolatileEvalOutput() + { + delete src_data_; + delete src_varying_data_; + delete patch_table_; + delete vertex_stencils_; + delete varying_stencils_; + foreach (FaceVaryingEval *face_varying_evaluator, face_varying_evaluators) { + delete face_varying_evaluator; + } + } + + // TODO(sergey): Implement binding API. + + void updateData(const float *src, int start_vertex, int num_vertices) + { + src_data_->UpdateData(src, start_vertex, num_vertices, device_context_); + } + + void updateVaryingData(const float *src, int start_vertex, int num_vertices) + { + src_varying_data_->UpdateData(src, start_vertex, num_vertices, device_context_); + } + + void updateFaceVaryingData(const int face_varying_channel, + const float *src, + int start_vertex, + int num_vertices) + { + assert(face_varying_channel >= 0); + assert(face_varying_channel < face_varying_evaluators.size()); + face_varying_evaluators[face_varying_channel]->updateData(src, start_vertex, num_vertices); + } + + bool hasVaryingData() const + { + // return varying_stencils_ != NULL; + // TODO(sergey): Check this based on actual topology. + return false; + } + + bool hasFaceVaryingData() const + { + return face_varying_evaluators.size() != 0; + } + + void refine() + { + // Evaluate vertex positions. + BufferDescriptor dst_desc = src_desc_; + dst_desc.offset += num_coarse_vertices_ * src_desc_.stride; + const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator( + evaluator_cache_, src_desc_, dst_desc, device_context_); + EVALUATOR::EvalStencils(src_data_, + src_desc_, + src_data_, + dst_desc, + vertex_stencils_, + eval_instance, + device_context_); + // Evaluate varying data. + if (hasVaryingData()) { + BufferDescriptor dst_varying_desc = src_varying_desc_; + dst_varying_desc.offset += num_coarse_vertices_ * src_varying_desc_.stride; + eval_instance = OpenSubdiv::Osd::GetEvaluator( + evaluator_cache_, src_varying_desc_, dst_varying_desc, device_context_); + EVALUATOR::EvalStencils(src_varying_data_, + src_varying_desc_, + src_varying_data_, + dst_varying_desc, + varying_stencils_, + eval_instance, + device_context_); + } + // Evaluate face-varying data. + if (hasFaceVaryingData()) { + foreach (FaceVaryingEval *face_varying_evaluator, face_varying_evaluators) { + face_varying_evaluator->refine(); + } + } + } + + // 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) + { + RawDataWrapperBuffer 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_cache_, src_desc_, P_desc, device_context_); + EVALUATOR::EvalPatches(src_data_, + src_desc_, + &P_data, + P_desc, + patch_coord_buffer.GetNumVertices(), + &patch_coord_buffer, + patch_table_, + eval_instance, + device_context_); + } + + // 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) + { + assert(dPdu); + assert(dPdv); + RawDataWrapperBuffer P_data(P); + RawDataWrapperBuffer 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_cache_, src_desc_, P_desc, dpDu_desc, pPdv_desc, device_context_); + EVALUATOR::EvalPatches(src_data_, + src_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_); + } + + // 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) + { + RawDataWrapperBuffer varying_data(varying); + BufferDescriptor varying_desc(3, 3, 6); + ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords); + const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator( + evaluator_cache_, src_varying_desc_, varying_desc, device_context_); + EVALUATOR::EvalPatchesVarying(src_varying_data_, + src_varying_desc_, + &varying_data, + varying_desc, + patch_coord_buffer.GetNumVertices(), + &patch_coord_buffer, + patch_table_, + eval_instance, + device_context_); + } + + 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]->evalPatches( + patch_coord, num_patch_coords, face_varying); + } + + private: + SRC_VERTEX_BUFFER *src_data_; + SRC_VERTEX_BUFFER *src_varying_data_; + PATCH_TABLE *patch_table_; + BufferDescriptor src_desc_; + BufferDescriptor src_varying_desc_; + + int num_coarse_vertices_; + + const STENCIL_TABLE *vertex_stencils_; + const STENCIL_TABLE *varying_stencils_; + + int face_varying_width_; + vector face_varying_evaluators; + + EvaluatorCache *evaluator_cache_; + 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 +// to have anonymous class in opensubdiv_evaluator_internal.h +class CpuEvalOutput : public VolatileEvalOutput { + public: + CpuEvalOutput(const StencilTable *vertex_stencils, + const StencilTable *varying_stencils, + const vector &all_face_varying_stencils, + const int face_varying_width, + const PatchTable *patch_table, + EvaluatorCache *evaluator_cache = NULL) + : VolatileEvalOutput(vertex_stencils, + varying_stencils, + all_face_varying_stencils, + face_varying_width, + patch_table, + evaluator_cache) + { + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// Evaluator wrapper for anonymous API. + +CpuEvalOutputAPI::CpuEvalOutputAPI(CpuEvalOutput *implementation, + OpenSubdiv::Far::PatchMap *patch_map) + : implementation_(implementation), patch_map_(patch_map) +{ +} + +CpuEvalOutputAPI::~CpuEvalOutputAPI() +{ + delete implementation_; +} + +void CpuEvalOutputAPI::setCoarsePositions(const float *positions, + const int start_vertex_index, + const int num_vertices) +{ + // TODO(sergey): Add sanity check on indices. + implementation_->updateData(positions, start_vertex_index, num_vertices); +} + +void CpuEvalOutputAPI::setVaryingData(const float *varying_data, + const int start_vertex_index, + const int num_vertices) +{ + // TODO(sergey): Add sanity check on indices. + implementation_->updateVaryingData(varying_data, start_vertex_index, num_vertices); +} + +void CpuEvalOutputAPI::setFaceVaryingData(const int face_varying_channel, + const float *face_varying_data, + const int start_vertex_index, + const int num_vertices) +{ + // TODO(sergey): Add sanity check on indices. + implementation_->updateFaceVaryingData( + face_varying_channel, face_varying_data, start_vertex_index, num_vertices); +} + +void CpuEvalOutputAPI::setCoarsePositionsFromBuffer(const void *buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices) +{ + // TODO(sergey): Add sanity check on indices. + const unsigned char *current_buffer = (unsigned char *)buffer; + current_buffer += start_offset; + for (int i = 0; i < num_vertices; ++i) { + const int current_vertex_index = start_vertex_index + i; + implementation_->updateData( + reinterpret_cast(current_buffer), current_vertex_index, 1); + current_buffer += stride; + } +} + +void CpuEvalOutputAPI::setVaryingDataFromBuffer(const void *buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices) +{ + // TODO(sergey): Add sanity check on indices. + const unsigned char *current_buffer = (unsigned char *)buffer; + current_buffer += start_offset; + for (int i = 0; i < num_vertices; ++i) { + const int current_vertex_index = start_vertex_index + i; + implementation_->updateVaryingData( + reinterpret_cast(current_buffer), current_vertex_index, 1); + current_buffer += stride; + } +} + +void CpuEvalOutputAPI::setFaceVaryingDataFromBuffer(const int face_varying_channel, + const void *buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices) +{ + // TODO(sergey): Add sanity check on indices. + const unsigned char *current_buffer = (unsigned char *)buffer; + current_buffer += start_offset; + for (int i = 0; i < num_vertices; ++i) { + const int current_vertex_index = start_vertex_index + i; + implementation_->updateFaceVaryingData(face_varying_channel, + reinterpret_cast(current_buffer), + current_vertex_index, + 1); + current_buffer += stride; + } +} + +void CpuEvalOutputAPI::refine() +{ + implementation_->refine(); +} + +void CpuEvalOutputAPI::evaluateLimit(const int ptex_face_index, + float face_u, + float face_v, + float P[3], + float dPdu[3], + float dPdv[3]) +{ + assert(face_u >= 0.0f); + assert(face_u <= 1.0f); + assert(face_v >= 0.0f); + 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); + if (dPdu != NULL || dPdv != NULL) { + implementation_->evalPatchesWithDerivatives(&patch_coord, 1, P, dPdu, dPdv); + } + else { + implementation_->evalPatches(&patch_coord, 1, P); + } +} + +void CpuEvalOutputAPI::evaluateVarying(const int ptex_face_index, + float face_u, + float face_v, + float varying[3]) +{ + assert(face_u >= 0.0f); + assert(face_u <= 1.0f); + assert(face_v >= 0.0f); + 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_->evalPatchesVarying(&patch_coord, 1, varying); +} + +void CpuEvalOutputAPI::evaluateFaceVarying(const int face_varying_channel, + const int ptex_face_index, + float face_u, + float face_v, + float face_varying[2]) +{ + assert(face_u >= 0.0f); + assert(face_u <= 1.0f); + assert(face_v >= 0.0f); + 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_->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 +} // namespace blender + +OpenSubdiv_EvaluatorImpl::OpenSubdiv_EvaluatorImpl() + : eval_output(NULL), patch_map(NULL), patch_table(NULL) +{ +} + +OpenSubdiv_EvaluatorImpl::~OpenSubdiv_EvaluatorImpl() +{ + delete eval_output; + delete patch_map; + delete patch_table; +} + +OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal( + OpenSubdiv_TopologyRefiner *topology_refiner) +{ + using blender::opensubdiv::vector; + TopologyRefiner *refiner = topology_refiner->impl->topology_refiner; + if (refiner == NULL) { + // Happens on bad topology. + return NULL; + } + // TODO(sergey): Base this on actual topology. + const bool has_varying_data = false; + const int num_face_varying_channels = refiner->GetNumFVarChannels(); + const bool has_face_varying_data = (num_face_varying_channels != 0); + const int level = topology_refiner->getSubdivisionLevel(topology_refiner); + const bool is_adaptive = topology_refiner->getIsAdaptive(topology_refiner); + // Common settings for stencils and patches. + const bool stencil_generate_intermediate_levels = is_adaptive; + const bool stencil_generate_offsets = true; + const bool use_inf_sharp_patch = true; + // Refine the topology with given settings. + // TODO(sergey): What if topology is already refined? + if (is_adaptive) { + TopologyRefiner::AdaptiveOptions options(level); + options.considerFVarChannels = has_face_varying_data; + options.useInfSharpPatch = use_inf_sharp_patch; + refiner->RefineAdaptive(options); + } + else { + TopologyRefiner::UniformOptions options(level); + refiner->RefineUniform(options); + } + // Generate stencil table to update the bi-cubic patches control vertices + // after they have been re-posed (both for vertex & varying interpolation). + // + // Vertex stencils. + StencilTableFactory::Options vertex_stencil_options; + vertex_stencil_options.generateOffsets = stencil_generate_offsets; + vertex_stencil_options.generateIntermediateLevels = stencil_generate_intermediate_levels; + const StencilTable *vertex_stencils = StencilTableFactory::Create(*refiner, + vertex_stencil_options); + // Varying stencils. + // + // TODO(sergey): Seems currently varying stencils are always required in + // OpenSubdiv itself. + const StencilTable *varying_stencils = NULL; + if (has_varying_data) { + StencilTableFactory::Options varying_stencil_options; + varying_stencil_options.generateOffsets = stencil_generate_offsets; + varying_stencil_options.generateIntermediateLevels = stencil_generate_intermediate_levels; + varying_stencil_options.interpolationMode = StencilTableFactory::INTERPOLATE_VARYING; + varying_stencils = StencilTableFactory::Create(*refiner, varying_stencil_options); + } + // Face warying stencil. + vector all_face_varying_stencils; + 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) { + StencilTableFactory::Options face_varying_stencil_options; + face_varying_stencil_options.generateOffsets = stencil_generate_offsets; + face_varying_stencil_options.generateIntermediateLevels = stencil_generate_intermediate_levels; + face_varying_stencil_options.interpolationMode = StencilTableFactory::INTERPOLATE_FACE_VARYING; + face_varying_stencil_options.fvarChannel = face_varying_channel; + all_face_varying_stencils.push_back( + StencilTableFactory::Create(*refiner, face_varying_stencil_options)); + } + // Generate bi-cubic patch table for the limit surface. + PatchTableFactory::Options patch_options(level); + patch_options.SetEndCapType(PatchTableFactory::Options::ENDCAP_GREGORY_BASIS); + patch_options.useInfSharpPatch = use_inf_sharp_patch; + patch_options.generateFVarTables = has_face_varying_data; + patch_options.generateFVarLegacyLinearPatches = false; + const PatchTable *patch_table = PatchTableFactory::Create(*refiner, patch_options); + // Append local points stencils. + // Point stencils. + const StencilTable *local_point_stencil_table = patch_table->GetLocalPointStencilTable(); + if (local_point_stencil_table != NULL) { + const StencilTable *table = StencilTableFactory::AppendLocalPointStencilTable( + *refiner, vertex_stencils, local_point_stencil_table); + delete vertex_stencils; + vertex_stencils = table; + } + // Varying stencils. + if (has_varying_data) { + const StencilTable *local_point_varying_stencil_table = + patch_table->GetLocalPointVaryingStencilTable(); + if (local_point_varying_stencil_table != NULL) { + const StencilTable *table = StencilTableFactory::AppendLocalPointStencilTable( + *refiner, varying_stencils, local_point_varying_stencil_table); + delete varying_stencils; + varying_stencils = table; + } + } + for (int face_varying_channel = 0; face_varying_channel < num_face_varying_channels; + ++face_varying_channel) { + const StencilTable *table = StencilTableFactory::AppendLocalPointStencilTableFaceVarying( + *refiner, + all_face_varying_stencils[face_varying_channel], + patch_table->GetLocalPointFaceVaryingStencilTable(face_varying_channel), + face_varying_channel); + if (table != NULL) { + delete all_face_varying_stencils[face_varying_channel]; + all_face_varying_stencils[face_varying_channel] = table; + } + } + // Create OpenSubdiv's CPU side evaluator. + // TODO(sergey): Make it possible to use different evaluators. + blender::opensubdiv::CpuEvalOutput *eval_output = new blender::opensubdiv::CpuEvalOutput( + vertex_stencils, varying_stencils, all_face_varying_stencils, 2, patch_table); + OpenSubdiv::Far::PatchMap *patch_map = new PatchMap(*patch_table); + // Wrap everything we need into an object which we control from our side. + OpenSubdiv_EvaluatorImpl *evaluator_descr; + evaluator_descr = new OpenSubdiv_EvaluatorImpl(); + evaluator_descr->eval_output = new blender::opensubdiv::CpuEvalOutputAPI(eval_output, patch_map); + evaluator_descr->patch_map = patch_map; + evaluator_descr->patch_table = patch_table; + // TOOD(sergey): Look into whether we've got duplicated stencils arrays. + delete vertex_stencils; + delete varying_stencils; + foreach (const StencilTable *table, all_face_varying_stencils) { + delete table; + } + return evaluator_descr; +} + +void openSubdiv_deleteEvaluatorInternal(OpenSubdiv_EvaluatorImpl *evaluator) +{ + delete evaluator; +} diff --git a/intern/opensubdiv/internal/evaluator/evaluator_impl.h b/intern/opensubdiv/internal/evaluator/evaluator_impl.h new file mode 100644 index 00000000000..6a3682efa62 --- /dev/null +++ b/intern/opensubdiv/internal/evaluator/evaluator_impl.h @@ -0,0 +1,158 @@ +// Copyright 2018 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_EVALUATOR_IMPL_H_ +#define OPENSUBDIV_EVALUATOR_IMPL_H_ + +#ifdef _MSC_VER +# include +#endif + +#include +#include + +#include "internal/base/memory.h" + +struct OpenSubdiv_PatchCoord; +struct OpenSubdiv_TopologyRefiner; + +namespace blender { +namespace opensubdiv { + +// Anonymous forward declaration of actual evaluator implementation. +class CpuEvalOutput; + +// Wrapper around implementaiton, which defines API which we are capable to +// provide over the implementation. +// +// TODO(sergey): It is almost the same as C-API object, so ideally need to +// merge them somehow, but how to do this and keep files with all the templates +// and such separate? +class CpuEvalOutputAPI { + public: + // NOTE: API object becomes an owner of evaluator. Patch we are referencing. + CpuEvalOutputAPI(CpuEvalOutput *implementation, OpenSubdiv::Far::PatchMap *patch_map); + ~CpuEvalOutputAPI(); + + // Set coarse positions from a continuous array of coordinates. + void setCoarsePositions(const float *positions, + const int start_vertex_index, + const int num_vertices); + // Set varying data from a continuous array of data. + void setVaryingData(const float *varying_data, + const int start_vertex_index, + const int num_vertices); + // Set face varying data from a continuous array of data. + // + // TODO(sergey): Find a better name for vertex here. It is not the vertex of + // geometry, but a vertex of UV map. + void setFaceVaryingData(const int face_varying_channel, + const float *varying_data, + const int start_vertex_index, + const int num_vertices); + + // Set coarse vertex position from a continuous memory buffer where + // first coordinate starts at offset of `start_offset` and there is `stride` + // bytes between adjacent vertex coordinates. + void setCoarsePositionsFromBuffer(const void *buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices); + // Set varying data from a continuous memory buffer where + // first coordinate starts at offset of `start_offset` and there is `stride` + // bytes between adjacent vertex coordinates. + void setVaryingDataFromBuffer(const void *buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices); + // Set face varying data from a continuous memory buffer where + // first coordinate starts at offset of `start_offset` and there is `stride` + // bytes between adjacent vertex coordinates. + // + // TODO(sergey): Find a better name for vertex here. It is not the vertex of + // geometry, but a vertex of UV map. + void setFaceVaryingDataFromBuffer(const int face_varying_channel, + const void *buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices); + + // Refine after coarse positions update. + void refine(); + + // Evaluate given ptex face at given bilinear coordinate. + // If derivatives are NULL, they will not be evaluated. + void evaluateLimit(const int ptex_face_index, + float face_u, + float face_v, + float P[3], + float dPdu[3], + float dPdv[3]); + + // Evaluate varying data at a given bilinear coordinate of given ptex face. + void evaluateVarying(const int ptes_face_index, float face_u, float face_v, float varying[3]); + + // Evaluate facee-varying data at a given bilinear coordinate of given + // ptex face. + void evaluateFaceVarying(const int face_varying_channel, + const int ptes_face_index, + float face_u, + 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_; +}; + +} // namespace opensubdiv +} // namespace blender + +struct OpenSubdiv_EvaluatorImpl { + public: + OpenSubdiv_EvaluatorImpl(); + ~OpenSubdiv_EvaluatorImpl(); + + blender::opensubdiv::CpuEvalOutputAPI *eval_output; + const OpenSubdiv::Far::PatchMap *patch_map; + const OpenSubdiv::Far::PatchTable *patch_table; + + MEM_CXX_CLASS_ALLOC_FUNCS("OpenSubdiv_EvaluatorImpl"); +}; + +OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal( + struct OpenSubdiv_TopologyRefiner *topology_refiner); + +void openSubdiv_deleteEvaluatorInternal(OpenSubdiv_EvaluatorImpl *evaluator); + +#endif // OPENSUBDIV_EVALUATOR_IMPL_H_ diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator.cc b/intern/opensubdiv/internal/opensubdiv_evaluator.cc deleted file mode 100644 index c599a3c9f68..00000000000 --- a/intern/opensubdiv/internal/opensubdiv_evaluator.cc +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2015 Blender Foundation. All rights reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// Author: Sergey Sharybin - -#include "opensubdiv_evaluator_capi.h" - -#include "MEM_guardedalloc.h" -#include - -#include "internal/opensubdiv_evaluator_internal.h" - -namespace { - -void setCoarsePositions(OpenSubdiv_Evaluator *evaluator, - const float *positions, - const int start_vertex_index, - const int num_vertices) -{ - evaluator->internal->eval_output->setCoarsePositions( - positions, start_vertex_index, num_vertices); -} - -void setVaryingData(OpenSubdiv_Evaluator *evaluator, - const float *varying_data, - const int start_vertex_index, - const int num_vertices) -{ - evaluator->internal->eval_output->setVaryingData(varying_data, start_vertex_index, num_vertices); -} - -void setFaceVaryingData(OpenSubdiv_Evaluator *evaluator, - const int face_varying_channel, - const float *face_varying_data, - const int start_vertex_index, - const int num_vertices) -{ - evaluator->internal->eval_output->setFaceVaryingData( - face_varying_channel, face_varying_data, start_vertex_index, num_vertices); -} - -void setCoarsePositionsFromBuffer(OpenSubdiv_Evaluator *evaluator, - const void *buffer, - const int start_offset, - const int stride, - const int start_vertex_index, - const int num_vertices) -{ - evaluator->internal->eval_output->setCoarsePositionsFromBuffer( - buffer, start_offset, stride, start_vertex_index, num_vertices); -} - -void setVaryingDataFromBuffer(OpenSubdiv_Evaluator *evaluator, - const void *buffer, - const int start_offset, - const int stride, - const int start_vertex_index, - const int num_vertices) -{ - evaluator->internal->eval_output->setVaryingDataFromBuffer( - buffer, start_offset, stride, start_vertex_index, num_vertices); -} - -void setFaceVaryingDataFromBuffer(OpenSubdiv_Evaluator *evaluator, - const int face_varying_channel, - const void *buffer, - const int start_offset, - const int stride, - const int start_vertex_index, - const int num_vertices) -{ - evaluator->internal->eval_output->setFaceVaryingDataFromBuffer( - face_varying_channel, buffer, start_offset, stride, start_vertex_index, num_vertices); -} - -void refine(OpenSubdiv_Evaluator *evaluator) -{ - evaluator->internal->eval_output->refine(); -} - -void evaluateLimit(OpenSubdiv_Evaluator *evaluator, - const int ptex_face_index, - const float face_u, - const float face_v, - float P[3], - float dPdu[3], - float dPdv[3]) -{ - 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, - float face_v, - float varying[3]) -{ - evaluator->internal->eval_output->evaluateVarying(ptex_face_index, face_u, face_v, varying); -} - -void evaluateFaceVarying(OpenSubdiv_Evaluator *evaluator, - const int face_varying_channel, - const int ptex_face_index, - float face_u, - float face_v, - float face_varying[2]) -{ - evaluator->internal->eval_output->evaluateFaceVarying( - face_varying_channel, ptex_face_index, face_u, face_v, face_varying); -} - -void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator) -{ - evaluator->setCoarsePositions = setCoarsePositions; - evaluator->setVaryingData = setVaryingData; - evaluator->setFaceVaryingData = setFaceVaryingData; - - evaluator->setCoarsePositionsFromBuffer = setCoarsePositionsFromBuffer; - evaluator->setVaryingDataFromBuffer = setVaryingDataFromBuffer; - evaluator->setFaceVaryingDataFromBuffer = setFaceVaryingDataFromBuffer; - - evaluator->refine = refine; - - evaluator->evaluateLimit = evaluateLimit; - evaluator->evaluateVarying = evaluateVarying; - evaluator->evaluateFaceVarying = evaluateFaceVarying; - - evaluator->evaluatePatchesLimit = evaluatePatchesLimit; -} - -} // namespace - -OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner( - OpenSubdiv_TopologyRefiner *topology_refiner) -{ - OpenSubdiv_Evaluator *evaluator = OBJECT_GUARDED_NEW(OpenSubdiv_Evaluator); - assignFunctionPointers(evaluator); - evaluator->internal = openSubdiv_createEvaluatorInternal(topology_refiner); - return evaluator; -} - -void openSubdiv_deleteEvaluator(OpenSubdiv_Evaluator *evaluator) -{ - openSubdiv_deleteEvaluatorInternal(evaluator->internal); - OBJECT_GUARDED_DELETE(evaluator, OpenSubdiv_Evaluator); -} diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc deleted file mode 100644 index a9960a9b027..00000000000 --- a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.cc +++ /dev/null @@ -1,877 +0,0 @@ -// Copyright 2018 Blender Foundation. All rights reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// Author: Sergey Sharybin - -#include "internal/opensubdiv_evaluator_internal.h" - -#include -#include - -#ifdef _MSC_VER -# include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "MEM_guardedalloc.h" - -#include "internal/opensubdiv_util.h" -#include "internal/topology/topology_refiner_impl.h" -#include "opensubdiv_topology_refiner_capi.h" - -using OpenSubdiv::Far::PatchMap; -using OpenSubdiv::Far::PatchTable; -using OpenSubdiv::Far::PatchTableFactory; -using OpenSubdiv::Far::StencilTable; -using OpenSubdiv::Far::StencilTableFactory; -using OpenSubdiv::Far::TopologyRefiner; -using OpenSubdiv::Osd::BufferDescriptor; -using OpenSubdiv::Osd::CpuEvaluator; -using OpenSubdiv::Osd::CpuPatchTable; -using OpenSubdiv::Osd::CpuVertexBuffer; -using OpenSubdiv::Osd::PatchCoord; - -namespace blender { -namespace opensubdiv { - -namespace { - -// Array implementation which stores small data on stack (or, rather, in the class itself). -template 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 StackOrHeapPatchCoordArray; - -// Buffer which implements API required by OpenSubdiv and uses an existing memory as an underlying -// storage. -template class RawDataWrapperBuffer { - public: - RawDataWrapperBuffer(T *data) : data_(data) - { - } - - T *BindCpuBuffer() - { - return data_; - } - - // TODO(sergey): Support UpdateData(). - - protected: - T *data_; -}; - -template class RawDataWrapperVertexBuffer : public RawDataWrapperBuffer { - public: - RawDataWrapperVertexBuffer(T *data, int num_vertices) - : RawDataWrapperBuffer(data), num_vertices_(num_vertices) - { - } - - int GetNumVertices() - { - return num_vertices_; - } - - protected: - int num_vertices_; -}; - -class ConstPatchCoordWrapperBuffer : public RawDataWrapperVertexBuffer { - public: - ConstPatchCoordWrapperBuffer(const PatchCoord *data, int num_vertices) - : RawDataWrapperVertexBuffer(data, num_vertices) - { - } -}; - -template -class FaceVaryingVolatileEval { - public: - typedef OpenSubdiv::Osd::EvaluatorCacheT EvaluatorCache; - - FaceVaryingVolatileEval(int face_varying_channel, - const StencilTable *face_varying_stencils, - int face_varying_width, - PATCH_TABLE *patch_table, - EvaluatorCache *evaluator_cache = NULL, - DEVICE_CONTEXT *device_context = NULL) - : face_varying_channel_(face_varying_channel), - src_face_varying_desc_(0, face_varying_width, face_varying_width), - patch_table_(patch_table), - evaluator_cache_(evaluator_cache), - device_context_(device_context) - { - using OpenSubdiv::Osd::convertToCompatibleStencilTable; - num_coarse_face_varying_vertices_ = face_varying_stencils->GetNumControlVertices(); - const int num_total_face_varying_vertices = face_varying_stencils->GetNumControlVertices() + - face_varying_stencils->GetNumStencils(); - src_face_varying_data_ = EVAL_VERTEX_BUFFER::Create( - 2, num_total_face_varying_vertices, device_context); - face_varying_stencils_ = convertToCompatibleStencilTable(face_varying_stencils, - device_context_); - } - - ~FaceVaryingVolatileEval() - { - delete src_face_varying_data_; - delete face_varying_stencils_; - } - - void updateData(const float *src, int start_vertex, int num_vertices) - { - src_face_varying_data_->UpdateData(src, start_vertex, num_vertices, device_context_); - } - - void refine() - { - BufferDescriptor dst_face_varying_desc = src_face_varying_desc_; - dst_face_varying_desc.offset += num_coarse_face_varying_vertices_ * - src_face_varying_desc_.stride; - const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator( - evaluator_cache_, src_face_varying_desc_, dst_face_varying_desc, device_context_); - EVALUATOR::EvalStencils(src_face_varying_data_, - src_face_varying_desc_, - src_face_varying_data_, - dst_face_varying_desc, - face_varying_stencils_, - eval_instance, - device_context_); - } - - // 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) - { - RawDataWrapperBuffer face_varying_data(face_varying); - BufferDescriptor face_varying_desc(0, 2, 2); - ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords); - const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator( - evaluator_cache_, src_face_varying_desc_, face_varying_desc, device_context_); - EVALUATOR::EvalPatchesFaceVarying(src_face_varying_data_, - src_face_varying_desc_, - &face_varying_data, - face_varying_desc, - patch_coord_buffer.GetNumVertices(), - &patch_coord_buffer, - patch_table_, - face_varying_channel_, - eval_instance, - device_context_); - } - - protected: - int face_varying_channel_; - - BufferDescriptor src_face_varying_desc_; - - int num_coarse_face_varying_vertices_; - EVAL_VERTEX_BUFFER *src_face_varying_data_; - const STENCIL_TABLE *face_varying_stencils_; - - // NOTE: We reference this, do not own it. - PATCH_TABLE *patch_table_; - - EvaluatorCache *evaluator_cache_; - DEVICE_CONTEXT *device_context_; -}; - -// Volatile evaluator which can be used from threads. -// -// TODO(sergey): Make it possible to evaluate coordinates in chunks. -// TODO(sergey): Make it possible to evaluate multiple face varying layers. -// (or maybe, it's cheap to create new evaluator for existing -// topology to evaluate all needed face varying layers?) -template -class VolatileEvalOutput { - public: - typedef OpenSubdiv::Osd::EvaluatorCacheT EvaluatorCache; - typedef FaceVaryingVolatileEval - FaceVaryingEval; - - VolatileEvalOutput(const StencilTable *vertex_stencils, - const StencilTable *varying_stencils, - const vector &all_face_varying_stencils, - const int face_varying_width, - const PatchTable *patch_table, - EvaluatorCache *evaluator_cache = NULL, - DEVICE_CONTEXT *device_context = NULL) - : src_desc_(0, 3, 3), - src_varying_desc_(0, 3, 3), - face_varying_width_(face_varying_width), - evaluator_cache_(evaluator_cache), - device_context_(device_context) - { - // Total number of vertices = coarse points + refined points + local points. - int num_total_vertices = vertex_stencils->GetNumControlVertices() + - vertex_stencils->GetNumStencils(); - num_coarse_vertices_ = vertex_stencils->GetNumControlVertices(); - using OpenSubdiv::Osd::convertToCompatibleStencilTable; - 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_); - vertex_stencils_ = convertToCompatibleStencilTable(vertex_stencils, - device_context_); - varying_stencils_ = convertToCompatibleStencilTable(varying_stencils, - device_context_); - // Create evaluators for every face varying channel. - face_varying_evaluators.reserve(all_face_varying_stencils.size()); - int face_varying_channel = 0; - foreach (const StencilTable *face_varying_stencils, all_face_varying_stencils) { - face_varying_evaluators.push_back(new FaceVaryingEval(face_varying_channel, - face_varying_stencils, - face_varying_width, - patch_table_, - evaluator_cache_, - device_context_)); - ++face_varying_channel; - } - } - - ~VolatileEvalOutput() - { - delete src_data_; - delete src_varying_data_; - delete patch_table_; - delete vertex_stencils_; - delete varying_stencils_; - foreach (FaceVaryingEval *face_varying_evaluator, face_varying_evaluators) { - delete face_varying_evaluator; - } - } - - // TODO(sergey): Implement binding API. - - void updateData(const float *src, int start_vertex, int num_vertices) - { - src_data_->UpdateData(src, start_vertex, num_vertices, device_context_); - } - - void updateVaryingData(const float *src, int start_vertex, int num_vertices) - { - src_varying_data_->UpdateData(src, start_vertex, num_vertices, device_context_); - } - - void updateFaceVaryingData(const int face_varying_channel, - const float *src, - int start_vertex, - int num_vertices) - { - assert(face_varying_channel >= 0); - assert(face_varying_channel < face_varying_evaluators.size()); - face_varying_evaluators[face_varying_channel]->updateData(src, start_vertex, num_vertices); - } - - bool hasVaryingData() const - { - // return varying_stencils_ != NULL; - // TODO(sergey): Check this based on actual topology. - return false; - } - - bool hasFaceVaryingData() const - { - return face_varying_evaluators.size() != 0; - } - - void refine() - { - // Evaluate vertex positions. - BufferDescriptor dst_desc = src_desc_; - dst_desc.offset += num_coarse_vertices_ * src_desc_.stride; - const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator( - evaluator_cache_, src_desc_, dst_desc, device_context_); - EVALUATOR::EvalStencils(src_data_, - src_desc_, - src_data_, - dst_desc, - vertex_stencils_, - eval_instance, - device_context_); - // Evaluate varying data. - if (hasVaryingData()) { - BufferDescriptor dst_varying_desc = src_varying_desc_; - dst_varying_desc.offset += num_coarse_vertices_ * src_varying_desc_.stride; - eval_instance = OpenSubdiv::Osd::GetEvaluator( - evaluator_cache_, src_varying_desc_, dst_varying_desc, device_context_); - EVALUATOR::EvalStencils(src_varying_data_, - src_varying_desc_, - src_varying_data_, - dst_varying_desc, - varying_stencils_, - eval_instance, - device_context_); - } - // Evaluate face-varying data. - if (hasFaceVaryingData()) { - foreach (FaceVaryingEval *face_varying_evaluator, face_varying_evaluators) { - face_varying_evaluator->refine(); - } - } - } - - // 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) - { - RawDataWrapperBuffer 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_cache_, src_desc_, P_desc, device_context_); - EVALUATOR::EvalPatches(src_data_, - src_desc_, - &P_data, - P_desc, - patch_coord_buffer.GetNumVertices(), - &patch_coord_buffer, - patch_table_, - eval_instance, - device_context_); - } - - // 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) - { - assert(dPdu); - assert(dPdv); - RawDataWrapperBuffer P_data(P); - RawDataWrapperBuffer 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_cache_, src_desc_, P_desc, dpDu_desc, pPdv_desc, device_context_); - EVALUATOR::EvalPatches(src_data_, - src_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_); - } - - // 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) - { - RawDataWrapperBuffer varying_data(varying); - BufferDescriptor varying_desc(3, 3, 6); - ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords); - const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator( - evaluator_cache_, src_varying_desc_, varying_desc, device_context_); - EVALUATOR::EvalPatchesVarying(src_varying_data_, - src_varying_desc_, - &varying_data, - varying_desc, - patch_coord_buffer.GetNumVertices(), - &patch_coord_buffer, - patch_table_, - eval_instance, - device_context_); - } - - 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]->evalPatches( - patch_coord, num_patch_coords, face_varying); - } - - private: - SRC_VERTEX_BUFFER *src_data_; - SRC_VERTEX_BUFFER *src_varying_data_; - PATCH_TABLE *patch_table_; - BufferDescriptor src_desc_; - BufferDescriptor src_varying_desc_; - - int num_coarse_vertices_; - - const STENCIL_TABLE *vertex_stencils_; - const STENCIL_TABLE *varying_stencils_; - - int face_varying_width_; - vector face_varying_evaluators; - - EvaluatorCache *evaluator_cache_; - 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 -// to have anonymous class in opensubdiv_evaluator_internal.h -class CpuEvalOutput : public VolatileEvalOutput { - public: - CpuEvalOutput(const StencilTable *vertex_stencils, - const StencilTable *varying_stencils, - const vector &all_face_varying_stencils, - const int face_varying_width, - const PatchTable *patch_table, - EvaluatorCache *evaluator_cache = NULL) - : VolatileEvalOutput(vertex_stencils, - varying_stencils, - all_face_varying_stencils, - face_varying_width, - patch_table, - evaluator_cache) - { - } -}; - -//////////////////////////////////////////////////////////////////////////////// -// Evaluator wrapper for anonymous API. - -CpuEvalOutputAPI::CpuEvalOutputAPI(CpuEvalOutput *implementation, - OpenSubdiv::Far::PatchMap *patch_map) - : implementation_(implementation), patch_map_(patch_map) -{ -} - -CpuEvalOutputAPI::~CpuEvalOutputAPI() -{ - delete implementation_; -} - -void CpuEvalOutputAPI::setCoarsePositions(const float *positions, - const int start_vertex_index, - const int num_vertices) -{ - // TODO(sergey): Add sanity check on indices. - implementation_->updateData(positions, start_vertex_index, num_vertices); -} - -void CpuEvalOutputAPI::setVaryingData(const float *varying_data, - const int start_vertex_index, - const int num_vertices) -{ - // TODO(sergey): Add sanity check on indices. - implementation_->updateVaryingData(varying_data, start_vertex_index, num_vertices); -} - -void CpuEvalOutputAPI::setFaceVaryingData(const int face_varying_channel, - const float *face_varying_data, - const int start_vertex_index, - const int num_vertices) -{ - // TODO(sergey): Add sanity check on indices. - implementation_->updateFaceVaryingData( - face_varying_channel, face_varying_data, start_vertex_index, num_vertices); -} - -void CpuEvalOutputAPI::setCoarsePositionsFromBuffer(const void *buffer, - const int start_offset, - const int stride, - const int start_vertex_index, - const int num_vertices) -{ - // TODO(sergey): Add sanity check on indices. - const unsigned char *current_buffer = (unsigned char *)buffer; - current_buffer += start_offset; - for (int i = 0; i < num_vertices; ++i) { - const int current_vertex_index = start_vertex_index + i; - implementation_->updateData( - reinterpret_cast(current_buffer), current_vertex_index, 1); - current_buffer += stride; - } -} - -void CpuEvalOutputAPI::setVaryingDataFromBuffer(const void *buffer, - const int start_offset, - const int stride, - const int start_vertex_index, - const int num_vertices) -{ - // TODO(sergey): Add sanity check on indices. - const unsigned char *current_buffer = (unsigned char *)buffer; - current_buffer += start_offset; - for (int i = 0; i < num_vertices; ++i) { - const int current_vertex_index = start_vertex_index + i; - implementation_->updateVaryingData( - reinterpret_cast(current_buffer), current_vertex_index, 1); - current_buffer += stride; - } -} - -void CpuEvalOutputAPI::setFaceVaryingDataFromBuffer(const int face_varying_channel, - const void *buffer, - const int start_offset, - const int stride, - const int start_vertex_index, - const int num_vertices) -{ - // TODO(sergey): Add sanity check on indices. - const unsigned char *current_buffer = (unsigned char *)buffer; - current_buffer += start_offset; - for (int i = 0; i < num_vertices; ++i) { - const int current_vertex_index = start_vertex_index + i; - implementation_->updateFaceVaryingData(face_varying_channel, - reinterpret_cast(current_buffer), - current_vertex_index, - 1); - current_buffer += stride; - } -} - -void CpuEvalOutputAPI::refine() -{ - implementation_->refine(); -} - -void CpuEvalOutputAPI::evaluateLimit(const int ptex_face_index, - float face_u, - float face_v, - float P[3], - float dPdu[3], - float dPdv[3]) -{ - assert(face_u >= 0.0f); - assert(face_u <= 1.0f); - assert(face_v >= 0.0f); - 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); - if (dPdu != NULL || dPdv != NULL) { - implementation_->evalPatchesWithDerivatives(&patch_coord, 1, P, dPdu, dPdv); - } - else { - implementation_->evalPatches(&patch_coord, 1, P); - } -} - -void CpuEvalOutputAPI::evaluateVarying(const int ptex_face_index, - float face_u, - float face_v, - float varying[3]) -{ - assert(face_u >= 0.0f); - assert(face_u <= 1.0f); - assert(face_v >= 0.0f); - 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_->evalPatchesVarying(&patch_coord, 1, varying); -} - -void CpuEvalOutputAPI::evaluateFaceVarying(const int face_varying_channel, - const int ptex_face_index, - float face_u, - float face_v, - float face_varying[2]) -{ - assert(face_u >= 0.0f); - assert(face_u <= 1.0f); - assert(face_v >= 0.0f); - 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_->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 -} // namespace blender - -OpenSubdiv_EvaluatorInternal::OpenSubdiv_EvaluatorInternal() - : eval_output(NULL), patch_map(NULL), patch_table(NULL) -{ -} - -OpenSubdiv_EvaluatorInternal::~OpenSubdiv_EvaluatorInternal() -{ - delete eval_output; - delete patch_map; - delete patch_table; -} - -OpenSubdiv_EvaluatorInternal *openSubdiv_createEvaluatorInternal( - OpenSubdiv_TopologyRefiner *topology_refiner) -{ - using blender::opensubdiv::vector; - TopologyRefiner *refiner = topology_refiner->impl->topology_refiner; - if (refiner == NULL) { - // Happens on bad topology. - return NULL; - } - // TODO(sergey): Base this on actual topology. - const bool has_varying_data = false; - const int num_face_varying_channels = refiner->GetNumFVarChannels(); - const bool has_face_varying_data = (num_face_varying_channels != 0); - const int level = topology_refiner->getSubdivisionLevel(topology_refiner); - const bool is_adaptive = topology_refiner->getIsAdaptive(topology_refiner); - // Common settings for stencils and patches. - const bool stencil_generate_intermediate_levels = is_adaptive; - const bool stencil_generate_offsets = true; - const bool use_inf_sharp_patch = true; - // Refine the topology with given settings. - // TODO(sergey): What if topology is already refined? - if (is_adaptive) { - TopologyRefiner::AdaptiveOptions options(level); - options.considerFVarChannels = has_face_varying_data; - options.useInfSharpPatch = use_inf_sharp_patch; - refiner->RefineAdaptive(options); - } - else { - TopologyRefiner::UniformOptions options(level); - refiner->RefineUniform(options); - } - // Generate stencil table to update the bi-cubic patches control vertices - // after they have been re-posed (both for vertex & varying interpolation). - // - // Vertex stencils. - StencilTableFactory::Options vertex_stencil_options; - vertex_stencil_options.generateOffsets = stencil_generate_offsets; - vertex_stencil_options.generateIntermediateLevels = stencil_generate_intermediate_levels; - const StencilTable *vertex_stencils = StencilTableFactory::Create(*refiner, - vertex_stencil_options); - // Varying stencils. - // - // TODO(sergey): Seems currently varying stencils are always required in - // OpenSubdiv itself. - const StencilTable *varying_stencils = NULL; - if (has_varying_data) { - StencilTableFactory::Options varying_stencil_options; - varying_stencil_options.generateOffsets = stencil_generate_offsets; - varying_stencil_options.generateIntermediateLevels = stencil_generate_intermediate_levels; - varying_stencil_options.interpolationMode = StencilTableFactory::INTERPOLATE_VARYING; - varying_stencils = StencilTableFactory::Create(*refiner, varying_stencil_options); - } - // Face warying stencil. - vector all_face_varying_stencils; - 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) { - StencilTableFactory::Options face_varying_stencil_options; - face_varying_stencil_options.generateOffsets = stencil_generate_offsets; - face_varying_stencil_options.generateIntermediateLevels = stencil_generate_intermediate_levels; - face_varying_stencil_options.interpolationMode = StencilTableFactory::INTERPOLATE_FACE_VARYING; - face_varying_stencil_options.fvarChannel = face_varying_channel; - all_face_varying_stencils.push_back( - StencilTableFactory::Create(*refiner, face_varying_stencil_options)); - } - // Generate bi-cubic patch table for the limit surface. - PatchTableFactory::Options patch_options(level); - patch_options.SetEndCapType(PatchTableFactory::Options::ENDCAP_GREGORY_BASIS); - patch_options.useInfSharpPatch = use_inf_sharp_patch; - patch_options.generateFVarTables = has_face_varying_data; - patch_options.generateFVarLegacyLinearPatches = false; - const PatchTable *patch_table = PatchTableFactory::Create(*refiner, patch_options); - // Append local points stencils. - // Point stencils. - const StencilTable *local_point_stencil_table = patch_table->GetLocalPointStencilTable(); - if (local_point_stencil_table != NULL) { - const StencilTable *table = StencilTableFactory::AppendLocalPointStencilTable( - *refiner, vertex_stencils, local_point_stencil_table); - delete vertex_stencils; - vertex_stencils = table; - } - // Varying stencils. - if (has_varying_data) { - const StencilTable *local_point_varying_stencil_table = - patch_table->GetLocalPointVaryingStencilTable(); - if (local_point_varying_stencil_table != NULL) { - const StencilTable *table = StencilTableFactory::AppendLocalPointStencilTable( - *refiner, varying_stencils, local_point_varying_stencil_table); - delete varying_stencils; - varying_stencils = table; - } - } - for (int face_varying_channel = 0; face_varying_channel < num_face_varying_channels; - ++face_varying_channel) { - const StencilTable *table = StencilTableFactory::AppendLocalPointStencilTableFaceVarying( - *refiner, - all_face_varying_stencils[face_varying_channel], - patch_table->GetLocalPointFaceVaryingStencilTable(face_varying_channel), - face_varying_channel); - if (table != NULL) { - delete all_face_varying_stencils[face_varying_channel]; - all_face_varying_stencils[face_varying_channel] = table; - } - } - // Create OpenSubdiv's CPU side evaluator. - // TODO(sergey): Make it possible to use different evaluators. - blender::opensubdiv::CpuEvalOutput *eval_output = new blender::opensubdiv::CpuEvalOutput( - vertex_stencils, varying_stencils, all_face_varying_stencils, 2, patch_table); - OpenSubdiv::Far::PatchMap *patch_map = new PatchMap(*patch_table); - // Wrap everything we need into an object which we control from our side. - OpenSubdiv_EvaluatorInternal *evaluator_descr; - evaluator_descr = new OpenSubdiv_EvaluatorInternal(); - evaluator_descr->eval_output = new blender::opensubdiv::CpuEvalOutputAPI(eval_output, patch_map); - evaluator_descr->patch_map = patch_map; - evaluator_descr->patch_table = patch_table; - // TOOD(sergey): Look into whether we've got duplicated stencils arrays. - delete vertex_stencils; - delete varying_stencils; - foreach (const StencilTable *table, all_face_varying_stencils) { - delete table; - } - return evaluator_descr; -} - -void openSubdiv_deleteEvaluatorInternal(OpenSubdiv_EvaluatorInternal *evaluator) -{ - delete evaluator; -} diff --git a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.h b/intern/opensubdiv/internal/opensubdiv_evaluator_internal.h deleted file mode 100644 index a60b82b02fe..00000000000 --- a/intern/opensubdiv/internal/opensubdiv_evaluator_internal.h +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2018 Blender Foundation. All rights reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// Author: Sergey Sharybin - -#ifndef OPENSUBDIV_EVALUATOR_INTERNAL_H_ -#define OPENSUBDIV_EVALUATOR_INTERNAL_H_ - -#ifdef _MSC_VER -# include -#endif - -#include -#include - -#include "internal/base/memory.h" - -struct OpenSubdiv_PatchCoord; -struct OpenSubdiv_TopologyRefiner; - -namespace blender { -namespace opensubdiv { - -// Anonymous forward declaration of actual evaluator implementation. -class CpuEvalOutput; - -// Wrapper around implementaiton, which defines API which we are capable to -// provide over the implementation. -// -// TODO(sergey): It is almost the same as C-API object, so ideally need to -// merge them somehow, but how to do this and keep files with all the templates -// and such separate? -class CpuEvalOutputAPI { - public: - // NOTE: API object becomes an owner of evaluator. Patch we are referencing. - CpuEvalOutputAPI(CpuEvalOutput *implementation, OpenSubdiv::Far::PatchMap *patch_map); - ~CpuEvalOutputAPI(); - - // Set coarse positions from a continuous array of coordinates. - void setCoarsePositions(const float *positions, - const int start_vertex_index, - const int num_vertices); - // Set varying data from a continuous array of data. - void setVaryingData(const float *varying_data, - const int start_vertex_index, - const int num_vertices); - // Set face varying data from a continuous array of data. - // - // TODO(sergey): Find a better name for vertex here. It is not the vertex of - // geometry, but a vertex of UV map. - void setFaceVaryingData(const int face_varying_channel, - const float *varying_data, - const int start_vertex_index, - const int num_vertices); - - // Set coarse vertex position from a continuous memory buffer where - // first coordinate starts at offset of `start_offset` and there is `stride` - // bytes between adjacent vertex coordinates. - void setCoarsePositionsFromBuffer(const void *buffer, - const int start_offset, - const int stride, - const int start_vertex_index, - const int num_vertices); - // Set varying data from a continuous memory buffer where - // first coordinate starts at offset of `start_offset` and there is `stride` - // bytes between adjacent vertex coordinates. - void setVaryingDataFromBuffer(const void *buffer, - const int start_offset, - const int stride, - const int start_vertex_index, - const int num_vertices); - // Set face varying data from a continuous memory buffer where - // first coordinate starts at offset of `start_offset` and there is `stride` - // bytes between adjacent vertex coordinates. - // - // TODO(sergey): Find a better name for vertex here. It is not the vertex of - // geometry, but a vertex of UV map. - void setFaceVaryingDataFromBuffer(const int face_varying_channel, - const void *buffer, - const int start_offset, - const int stride, - const int start_vertex_index, - const int num_vertices); - - // Refine after coarse positions update. - void refine(); - - // Evaluate given ptex face at given bilinear coordinate. - // If derivatives are NULL, they will not be evaluated. - void evaluateLimit(const int ptex_face_index, - float face_u, - float face_v, - float P[3], - float dPdu[3], - float dPdv[3]); - - // Evaluate varying data at a given bilinear coordinate of given ptex face. - void evaluateVarying(const int ptes_face_index, float face_u, float face_v, float varying[3]); - - // Evaluate facee-varying data at a given bilinear coordinate of given - // ptex face. - void evaluateFaceVarying(const int face_varying_channel, - const int ptes_face_index, - float face_u, - 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_; -}; - -} // namespace opensubdiv -} // namespace blender - -struct OpenSubdiv_EvaluatorInternal { - public: - OpenSubdiv_EvaluatorInternal(); - ~OpenSubdiv_EvaluatorInternal(); - - blender::opensubdiv::CpuEvalOutputAPI *eval_output; - const OpenSubdiv::Far::PatchMap *patch_map; - const OpenSubdiv::Far::PatchTable *patch_table; - - MEM_CXX_CLASS_ALLOC_FUNCS("OpenSubdiv_EvaluatorInternal"); -}; - -OpenSubdiv_EvaluatorInternal *openSubdiv_createEvaluatorInternal( - struct OpenSubdiv_TopologyRefiner *topology_refiner); - -void openSubdiv_deleteEvaluatorInternal(OpenSubdiv_EvaluatorInternal *evaluator); - -#endif // OPENSUBDIV_EVALUATOR_INTERNAL_H_ diff --git a/intern/opensubdiv/opensubdiv_evaluator_capi.h b/intern/opensubdiv/opensubdiv_evaluator_capi.h index 1572d01b851..b860ae8db2e 100644 --- a/intern/opensubdiv/opensubdiv_evaluator_capi.h +++ b/intern/opensubdiv/opensubdiv_evaluator_capi.h @@ -122,10 +122,8 @@ typedef struct OpenSubdiv_Evaluator { float *dPdu, float *dPdv); - // Internal storage for the use in this module only. - // - // This is where actual OpenSubdiv's evaluator is living. - struct OpenSubdiv_EvaluatorInternal *internal; + // Implementation of the evaluator. + struct OpenSubdiv_EvaluatorImpl *impl; } OpenSubdiv_Evaluator; OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner( -- cgit v1.2.3