Merge branch 'blender-v4.4-release'
[blender.git] / intern / opensubdiv / internal / evaluator / evaluator_impl.cc
blob152b42c81eb539d4bfc80842e44233af6bbe780a
1 /* SPDX-FileCopyrightText: 2018 Blender Foundation
3 * SPDX-License-Identifier: GPL-2.0-or-later
5 * Author: Sergey Sharybin. */
7 #include <cassert>
9 #ifdef _MSC_VER
10 # include <iso646.h>
11 #endif
13 #include <opensubdiv/far/patchMap.h>
14 #include <opensubdiv/far/patchTable.h>
15 #include <opensubdiv/far/patchTableFactory.h>
16 #include <opensubdiv/osd/mesh.h>
17 #include <opensubdiv/osd/types.h>
18 #include <opensubdiv/version.h>
20 #include "internal/evaluator/eval_output_cpu.h"
21 #include "internal/evaluator/eval_output_gpu.h"
22 #include "internal/evaluator/evaluator_cache_impl.h"
23 #include "internal/evaluator/patch_map.h"
24 #include "opensubdiv_evaluator.hh"
25 #include "opensubdiv_evaluator_capi.hh"
26 #include "opensubdiv_topology_refiner.hh"
28 using OpenSubdiv::Far::PatchTable;
29 using OpenSubdiv::Far::PatchTableFactory;
30 using OpenSubdiv::Far::StencilTable;
31 using OpenSubdiv::Far::StencilTableFactory;
32 using OpenSubdiv::Far::StencilTableReal;
33 using OpenSubdiv::Far::TopologyRefiner;
34 using OpenSubdiv::Osd::PatchArray;
35 using OpenSubdiv::Osd::PatchCoord;
37 namespace blender::opensubdiv {
39 // Array implementation which stores small data on stack (or, rather, in the class itself).
40 template<typename T, int kNumMaxElementsOnStack> class StackOrHeapArray {
41 public:
42 StackOrHeapArray()
43 : num_elements_(0),
44 heap_elements_(nullptr),
45 num_heap_elements_(0),
46 effective_elements_(nullptr)
50 explicit StackOrHeapArray(int size) : StackOrHeapArray()
52 resize(size);
55 ~StackOrHeapArray()
57 delete[] heap_elements_;
60 int size() const
62 return num_elements_;
65 T *data()
67 return effective_elements_;
70 void resize(int num_elements)
72 const int old_num_elements = num_elements_;
73 num_elements_ = num_elements;
74 // Early output if allcoation size did not change, or allocation size is smaller.
75 // We never re-allocate, sacrificing some memory over performance.
76 if (old_num_elements >= num_elements) {
77 return;
79 // Simple case: no previously allocated buffer, can simply do one allocation.
80 if (effective_elements_ == nullptr) {
81 effective_elements_ = allocate(num_elements);
82 return;
84 // Make new allocation, and copy elements if needed.
85 T *old_buffer = effective_elements_;
86 effective_elements_ = allocate(num_elements);
87 if (old_buffer != effective_elements_) {
88 memcpy(
89 effective_elements_, old_buffer, sizeof(T) * std::min(old_num_elements, num_elements));
91 if (old_buffer != stack_elements_) {
92 delete[] old_buffer;
96 protected:
97 T *allocate(int num_elements)
99 if (num_elements < kNumMaxElementsOnStack) {
100 return stack_elements_;
102 heap_elements_ = new T[num_elements];
103 return heap_elements_;
106 // Number of elements in the buffer.
107 int num_elements_;
109 // Elements which are allocated on a stack (or, rather, in the same allocation as the buffer
110 // itself).
111 // Is used as long as buffer is smaller than kNumMaxElementsOnStack.
112 T stack_elements_[kNumMaxElementsOnStack];
114 // Heap storage for buffer larger than kNumMaxElementsOnStack.
115 T *heap_elements_;
116 int num_heap_elements_;
118 // Depending on the current buffer size points to rither stack_elements_ or heap_elements_.
119 T *effective_elements_;
122 // 32 is a number of inner vertices along the patch size at subdivision level 6.
123 using StackOrHeapPatchCoordArray = StackOrHeapArray<PatchCoord, 32 * 32>;
125 static void convertPatchCoordsToArray(const OpenSubdiv_PatchCoord *patch_coords,
126 const int num_patch_coords,
127 const PatchMap *patch_map,
128 StackOrHeapPatchCoordArray *array)
130 array->resize(num_patch_coords);
131 for (int i = 0; i < num_patch_coords; ++i) {
132 const PatchTable::PatchHandle *handle = patch_map->FindPatch(
133 patch_coords[i].ptex_face, patch_coords[i].u, patch_coords[i].v);
134 (array->data())[i] = PatchCoord(*handle, patch_coords[i].u, patch_coords[i].v);
138 ////////////////////////////////////////////////////////////////////////////////
139 // Evaluator wrapper for anonymous API.
141 EvalOutputAPI::EvalOutputAPI(EvalOutput *implementation, PatchMap *patch_map)
142 : patch_map_(patch_map), implementation_(implementation)
146 EvalOutputAPI::~EvalOutputAPI()
148 delete implementation_;
151 void EvalOutputAPI::setSettings(const OpenSubdiv_EvaluatorSettings *settings)
153 implementation_->updateSettings(settings);
156 void EvalOutputAPI::setCoarsePositions(const float *positions,
157 const int start_vertex_index,
158 const int num_vertices)
160 // TODO(sergey): Add sanity check on indices.
161 implementation_->updateData(positions, start_vertex_index, num_vertices);
164 void EvalOutputAPI::setVaryingData(const float *varying_data,
165 const int start_vertex_index,
166 const int num_vertices)
168 // TODO(sergey): Add sanity check on indices.
169 implementation_->updateVaryingData(varying_data, start_vertex_index, num_vertices);
172 void EvalOutputAPI::setVertexData(const float *vertex_data,
173 const int start_vertex_index,
174 const int num_vertices)
176 // TODO(sergey): Add sanity check on indices.
177 implementation_->updateVertexData(vertex_data, start_vertex_index, num_vertices);
180 void EvalOutputAPI::setFaceVaryingData(const int face_varying_channel,
181 const float *face_varying_data,
182 const int start_vertex_index,
183 const int num_vertices)
185 // TODO(sergey): Add sanity check on indices.
186 implementation_->updateFaceVaryingData(
187 face_varying_channel, face_varying_data, start_vertex_index, num_vertices);
190 void EvalOutputAPI::setCoarsePositionsFromBuffer(const void *buffer,
191 const int start_offset,
192 const int stride,
193 const int start_vertex_index,
194 const int num_vertices)
196 // TODO(sergey): Add sanity check on indices.
197 const unsigned char *current_buffer = (unsigned char *)buffer;
198 current_buffer += start_offset;
199 for (int i = 0; i < num_vertices; ++i) {
200 const int current_vertex_index = start_vertex_index + i;
201 implementation_->updateData(
202 reinterpret_cast<const float *>(current_buffer), current_vertex_index, 1);
203 current_buffer += stride;
207 void EvalOutputAPI::setVaryingDataFromBuffer(const void *buffer,
208 const int start_offset,
209 const int stride,
210 const int start_vertex_index,
211 const int num_vertices)
213 // TODO(sergey): Add sanity check on indices.
214 const unsigned char *current_buffer = (unsigned char *)buffer;
215 current_buffer += start_offset;
216 for (int i = 0; i < num_vertices; ++i) {
217 const int current_vertex_index = start_vertex_index + i;
218 implementation_->updateVaryingData(
219 reinterpret_cast<const float *>(current_buffer), current_vertex_index, 1);
220 current_buffer += stride;
224 void EvalOutputAPI::setFaceVaryingDataFromBuffer(const int face_varying_channel,
225 const void *buffer,
226 const int start_offset,
227 const int stride,
228 const int start_vertex_index,
229 const int num_vertices)
231 // TODO(sergey): Add sanity check on indices.
232 const unsigned char *current_buffer = (unsigned char *)buffer;
233 current_buffer += start_offset;
234 for (int i = 0; i < num_vertices; ++i) {
235 const int current_vertex_index = start_vertex_index + i;
236 implementation_->updateFaceVaryingData(face_varying_channel,
237 reinterpret_cast<const float *>(current_buffer),
238 current_vertex_index,
240 current_buffer += stride;
244 void EvalOutputAPI::refine()
246 implementation_->refine();
249 void EvalOutputAPI::evaluateLimit(const int ptex_face_index,
250 float face_u,
251 float face_v,
252 float P[3],
253 float dPdu[3],
254 float dPdv[3])
256 assert(face_u >= 0.0f);
257 assert(face_u <= 1.0f);
258 assert(face_v >= 0.0f);
259 assert(face_v <= 1.0f);
260 const PatchTable::PatchHandle *handle = patch_map_->FindPatch(ptex_face_index, face_u, face_v);
261 PatchCoord patch_coord(*handle, face_u, face_v);
262 if (dPdu != nullptr || dPdv != nullptr) {
263 implementation_->evalPatchesWithDerivatives(&patch_coord, 1, P, dPdu, dPdv);
265 else {
266 implementation_->evalPatches(&patch_coord, 1, P);
270 void EvalOutputAPI::evaluateVarying(const int ptex_face_index,
271 float face_u,
272 float face_v,
273 float varying[3])
275 assert(face_u >= 0.0f);
276 assert(face_u <= 1.0f);
277 assert(face_v >= 0.0f);
278 assert(face_v <= 1.0f);
279 const PatchTable::PatchHandle *handle = patch_map_->FindPatch(ptex_face_index, face_u, face_v);
280 PatchCoord patch_coord(*handle, face_u, face_v);
281 implementation_->evalPatchesVarying(&patch_coord, 1, varying);
284 void EvalOutputAPI::evaluateVertexData(const int ptex_face_index,
285 float face_u,
286 float face_v,
287 float vertex_data[])
289 assert(face_u >= 0.0f);
290 assert(face_u <= 1.0f);
291 assert(face_v >= 0.0f);
292 assert(face_v <= 1.0f);
293 const PatchTable::PatchHandle *handle = patch_map_->FindPatch(ptex_face_index, face_u, face_v);
294 PatchCoord patch_coord(*handle, face_u, face_v);
295 implementation_->evalPatchesVertexData(&patch_coord, 1, vertex_data);
298 void EvalOutputAPI::evaluateFaceVarying(const int face_varying_channel,
299 const int ptex_face_index,
300 float face_u,
301 float face_v,
302 float face_varying[2])
304 assert(face_u >= 0.0f);
305 assert(face_u <= 1.0f);
306 assert(face_v >= 0.0f);
307 assert(face_v <= 1.0f);
308 const PatchTable::PatchHandle *handle = patch_map_->FindPatch(ptex_face_index, face_u, face_v);
309 PatchCoord patch_coord(*handle, face_u, face_v);
310 implementation_->evalPatchesFaceVarying(face_varying_channel, &patch_coord, 1, face_varying);
313 void EvalOutputAPI::evaluatePatchesLimit(const OpenSubdiv_PatchCoord *patch_coords,
314 const int num_patch_coords,
315 float *P,
316 float *dPdu,
317 float *dPdv)
319 StackOrHeapPatchCoordArray patch_coords_array;
320 convertPatchCoordsToArray(patch_coords, num_patch_coords, patch_map_, &patch_coords_array);
321 if (dPdu != nullptr || dPdv != nullptr) {
322 implementation_->evalPatchesWithDerivatives(
323 patch_coords_array.data(), num_patch_coords, P, dPdu, dPdv);
325 else {
326 implementation_->evalPatches(patch_coords_array.data(), num_patch_coords, P);
330 void EvalOutputAPI::getPatchMap(OpenSubdiv_Buffer *patch_map_handles,
331 OpenSubdiv_Buffer *patch_map_quadtree,
332 int *min_patch_face,
333 int *max_patch_face,
334 int *max_depth,
335 int *patches_are_triangular)
337 *min_patch_face = patch_map_->getMinPatchFace();
338 *max_patch_face = patch_map_->getMaxPatchFace();
339 *max_depth = patch_map_->getMaxDepth();
340 *patches_are_triangular = patch_map_->getPatchesAreTriangular();
342 const std::vector<PatchTable::PatchHandle> &handles = patch_map_->getHandles();
343 PatchTable::PatchHandle *buffer_handles = static_cast<PatchTable::PatchHandle *>(
344 patch_map_handles->alloc(patch_map_handles, handles.size()));
345 memcpy(buffer_handles, handles.data(), sizeof(PatchTable::PatchHandle) * handles.size());
347 const std::vector<PatchMap::QuadNode> &quadtree = patch_map_->nodes();
348 PatchMap::QuadNode *buffer_nodes = static_cast<PatchMap::QuadNode *>(
349 patch_map_quadtree->alloc(patch_map_quadtree, quadtree.size()));
350 memcpy(buffer_nodes, quadtree.data(), sizeof(PatchMap::QuadNode) * quadtree.size());
353 void EvalOutputAPI::fillPatchArraysBuffer(OpenSubdiv_Buffer *patch_arrays_buffer)
355 implementation_->fillPatchArraysBuffer(patch_arrays_buffer);
358 void EvalOutputAPI::wrapPatchIndexBuffer(OpenSubdiv_Buffer *patch_index_buffer)
360 implementation_->wrapPatchIndexBuffer(patch_index_buffer);
363 void EvalOutputAPI::wrapPatchParamBuffer(OpenSubdiv_Buffer *patch_param_buffer)
365 implementation_->wrapPatchParamBuffer(patch_param_buffer);
368 void EvalOutputAPI::wrapSrcBuffer(OpenSubdiv_Buffer *src_buffer)
370 implementation_->wrapSrcBuffer(src_buffer);
373 void EvalOutputAPI::wrapSrcVertexDataBuffer(OpenSubdiv_Buffer *src_buffer)
375 implementation_->wrapSrcVertexDataBuffer(src_buffer);
378 void EvalOutputAPI::fillFVarPatchArraysBuffer(const int face_varying_channel,
379 OpenSubdiv_Buffer *patch_arrays_buffer)
381 implementation_->fillFVarPatchArraysBuffer(face_varying_channel, patch_arrays_buffer);
384 void EvalOutputAPI::wrapFVarPatchIndexBuffer(const int face_varying_channel,
385 OpenSubdiv_Buffer *patch_index_buffer)
387 implementation_->wrapFVarPatchIndexBuffer(face_varying_channel, patch_index_buffer);
390 void EvalOutputAPI::wrapFVarPatchParamBuffer(const int face_varying_channel,
391 OpenSubdiv_Buffer *patch_param_buffer)
393 implementation_->wrapFVarPatchParamBuffer(face_varying_channel, patch_param_buffer);
396 void EvalOutputAPI::wrapFVarSrcBuffer(const int face_varying_channel,
397 OpenSubdiv_Buffer *src_buffer)
399 implementation_->wrapFVarSrcBuffer(face_varying_channel, src_buffer);
402 bool EvalOutputAPI::hasVertexData() const
404 return implementation_->hasVertexData();
407 } // namespace blender::opensubdiv
409 OpenSubdiv_Evaluator::OpenSubdiv_Evaluator()
410 : eval_output(nullptr), patch_map(nullptr), patch_table(nullptr)
414 OpenSubdiv_Evaluator::~OpenSubdiv_Evaluator()
416 delete eval_output;
417 delete patch_map;
418 delete patch_table;
421 OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner(
422 blender::opensubdiv::TopologyRefinerImpl *topology_refiner,
423 eOpenSubdivEvaluator evaluator_type,
424 OpenSubdiv_EvaluatorCache *evaluator_cache_descr)
426 TopologyRefiner *refiner = topology_refiner->topology_refiner;
427 if (refiner == nullptr) {
428 // Happens on bad topology.
429 return nullptr;
431 // TODO(sergey): Base this on actual topology.
432 const bool has_varying_data = false;
433 const int num_face_varying_channels = refiner->GetNumFVarChannels();
434 const bool has_face_varying_data = (num_face_varying_channels != 0);
435 const int level = topology_refiner->settings.level;
436 const bool is_adaptive = topology_refiner->settings.is_adaptive;
437 // Common settings for stencils and patches.
438 const bool stencil_generate_intermediate_levels = is_adaptive;
439 const bool stencil_generate_offsets = true;
440 const bool use_inf_sharp_patch = true;
441 // Refine the topology with given settings.
442 // TODO(sergey): What if topology is already refined?
443 if (is_adaptive) {
444 TopologyRefiner::AdaptiveOptions options(level);
445 options.considerFVarChannels = has_face_varying_data;
446 options.useInfSharpPatch = use_inf_sharp_patch;
447 refiner->RefineAdaptive(options);
449 else {
450 TopologyRefiner::UniformOptions options(level);
451 refiner->RefineUniform(options);
454 // Work around ASAN warnings, due to OpenSubdiv pretending to have an actual StencilTable
455 // instance while it's really its base class.
456 auto delete_stencil_table = [](const StencilTable *table) {
457 static_assert(std::is_base_of_v<StencilTableReal<float>, StencilTable>);
458 delete reinterpret_cast<const StencilTableReal<float> *>(table);
461 // Generate stencil table to update the bi-cubic patches control vertices
462 // after they have been re-posed (both for vertex & varying interpolation).
464 // Vertex stencils.
465 StencilTableFactory::Options vertex_stencil_options;
466 vertex_stencil_options.generateOffsets = stencil_generate_offsets;
467 vertex_stencil_options.generateIntermediateLevels = stencil_generate_intermediate_levels;
468 const StencilTable *vertex_stencils = StencilTableFactory::Create(*refiner,
469 vertex_stencil_options);
470 // Varying stencils.
472 // TODO(sergey): Seems currently varying stencils are always required in
473 // OpenSubdiv itself.
474 const StencilTable *varying_stencils = nullptr;
475 if (has_varying_data) {
476 StencilTableFactory::Options varying_stencil_options;
477 varying_stencil_options.generateOffsets = stencil_generate_offsets;
478 varying_stencil_options.generateIntermediateLevels = stencil_generate_intermediate_levels;
479 varying_stencil_options.interpolationMode = StencilTableFactory::INTERPOLATE_VARYING;
480 varying_stencils = StencilTableFactory::Create(*refiner, varying_stencil_options);
482 // Face warying stencil.
483 std::vector<const StencilTable *> all_face_varying_stencils;
484 all_face_varying_stencils.reserve(num_face_varying_channels);
485 for (int face_varying_channel = 0; face_varying_channel < num_face_varying_channels;
486 ++face_varying_channel)
488 StencilTableFactory::Options face_varying_stencil_options;
489 face_varying_stencil_options.generateOffsets = stencil_generate_offsets;
490 face_varying_stencil_options.generateIntermediateLevels = stencil_generate_intermediate_levels;
491 face_varying_stencil_options.interpolationMode = StencilTableFactory::INTERPOLATE_FACE_VARYING;
492 face_varying_stencil_options.fvarChannel = face_varying_channel;
493 all_face_varying_stencils.push_back(
494 StencilTableFactory::Create(*refiner, face_varying_stencil_options));
496 // Generate bi-cubic patch table for the limit surface.
497 PatchTableFactory::Options patch_options(level);
498 patch_options.SetEndCapType(PatchTableFactory::Options::ENDCAP_GREGORY_BASIS);
499 patch_options.useInfSharpPatch = use_inf_sharp_patch;
500 patch_options.generateFVarTables = has_face_varying_data;
501 patch_options.generateFVarLegacyLinearPatches = false;
502 const PatchTable *patch_table = PatchTableFactory::Create(*refiner, patch_options);
503 // Append local points stencils.
504 // Point stencils.
505 const StencilTable *local_point_stencil_table = patch_table->GetLocalPointStencilTable();
506 if (local_point_stencil_table != nullptr) {
507 const StencilTable *table = StencilTableFactory::AppendLocalPointStencilTable(
508 *refiner, vertex_stencils, local_point_stencil_table);
509 delete_stencil_table(vertex_stencils);
510 vertex_stencils = table;
512 // Varying stencils.
513 if (has_varying_data) {
514 const StencilTable *local_point_varying_stencil_table =
515 patch_table->GetLocalPointVaryingStencilTable();
516 if (local_point_varying_stencil_table != nullptr) {
517 const StencilTable *table = StencilTableFactory::AppendLocalPointStencilTable(
518 *refiner, varying_stencils, local_point_varying_stencil_table);
519 delete_stencil_table(varying_stencils);
520 varying_stencils = table;
523 for (int face_varying_channel = 0; face_varying_channel < num_face_varying_channels;
524 ++face_varying_channel)
526 const StencilTable *table = StencilTableFactory::AppendLocalPointStencilTableFaceVarying(
527 *refiner,
528 all_face_varying_stencils[face_varying_channel],
529 patch_table->GetLocalPointFaceVaryingStencilTable(face_varying_channel),
530 face_varying_channel);
531 if (table != nullptr) {
532 delete_stencil_table(all_face_varying_stencils[face_varying_channel]);
533 all_face_varying_stencils[face_varying_channel] = table;
536 // Create OpenSubdiv's CPU side evaluator.
537 blender::opensubdiv::EvalOutputAPI::EvalOutput *eval_output = nullptr;
539 const bool use_gpu_evaluator = evaluator_type == OPENSUBDIV_EVALUATOR_GPU;
540 if (use_gpu_evaluator) {
541 blender::opensubdiv::GpuEvalOutput::EvaluatorCache *evaluator_cache = nullptr;
542 if (evaluator_cache_descr) {
543 evaluator_cache = static_cast<blender::opensubdiv::GpuEvalOutput::EvaluatorCache *>(
544 evaluator_cache_descr->impl->eval_cache);
547 eval_output = new blender::opensubdiv::GpuEvalOutput(vertex_stencils,
548 varying_stencils,
549 all_face_varying_stencils,
551 patch_table,
552 evaluator_cache);
554 else {
555 eval_output = new blender::opensubdiv::CpuEvalOutput(
556 vertex_stencils, varying_stencils, all_face_varying_stencils, 2, patch_table);
559 blender::opensubdiv::PatchMap *patch_map = new blender::opensubdiv::PatchMap(*patch_table);
560 // Wrap everything we need into an object which we control from our side.
561 OpenSubdiv_Evaluator *evaluator = new OpenSubdiv_Evaluator();
562 evaluator->type = evaluator_type;
564 evaluator->eval_output = new blender::opensubdiv::EvalOutputAPI(eval_output, patch_map);
565 evaluator->patch_map = patch_map;
566 evaluator->patch_table = patch_table;
567 // TODO(sergey): Look into whether we've got duplicated stencils arrays.
568 delete_stencil_table(vertex_stencils);
569 delete_stencil_table(varying_stencils);
570 for (const StencilTable *table : all_face_varying_stencils) {
571 delete_stencil_table(table);
574 return evaluator;