1 /* SPDX-FileCopyrightText: 2018 Blender Foundation
3 * SPDX-License-Identifier: GPL-2.0-or-later
5 * Author: Sergey Sharybin. */
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
{
44 heap_elements_(nullptr),
45 num_heap_elements_(0),
46 effective_elements_(nullptr)
50 explicit StackOrHeapArray(int size
) : StackOrHeapArray()
57 delete[] heap_elements_
;
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
) {
79 // Simple case: no previously allocated buffer, can simply do one allocation.
80 if (effective_elements_
== nullptr) {
81 effective_elements_
= allocate(num_elements
);
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_
) {
89 effective_elements_
, old_buffer
, sizeof(T
) * std::min(old_num_elements
, num_elements
));
91 if (old_buffer
!= stack_elements_
) {
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.
109 // Elements which are allocated on a stack (or, rather, in the same allocation as the buffer
111 // Is used as long as buffer is smaller than kNumMaxElementsOnStack.
112 T stack_elements_
[kNumMaxElementsOnStack
];
114 // Heap storage for buffer larger than kNumMaxElementsOnStack.
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
,
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
,
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
,
226 const int start_offset
,
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
,
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
);
266 implementation_
->evalPatches(&patch_coord
, 1, P
);
270 void EvalOutputAPI::evaluateVarying(const int ptex_face_index
,
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
,
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
,
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
,
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
);
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
,
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()
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.
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?
444 TopologyRefiner::AdaptiveOptions
options(level
);
445 options
.considerFVarChannels
= has_face_varying_data
;
446 options
.useInfSharpPatch
= use_inf_sharp_patch
;
447 refiner
->RefineAdaptive(options
);
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).
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
);
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.
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
;
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(
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
,
549 all_face_varying_stencils
,
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
);