Cleanup: fix compiler warnings.
[blender.git] / intern / opensubdiv / opensubdiv_evaluator_capi.cc
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2015 Blender Foundation.
17  * All rights reserved.
18  */
19
20 #include "opensubdiv_capi.h"
21
22 #include <cstdio>
23 #include <vector>
24
25 #ifdef _MSC_VER
26 #  include "iso646.h"
27 #endif
28
29 #include <opensubdiv/far/patchMap.h>
30 #include <opensubdiv/far/patchTable.h>
31 #include <opensubdiv/far/patchTableFactory.h>
32 #include <opensubdiv/osd/cpuEvaluator.h>
33 #include <opensubdiv/osd/cpuPatchTable.h>
34 #include <opensubdiv/osd/cpuVertexBuffer.h>
35 #include <opensubdiv/osd/mesh.h>
36 #include <opensubdiv/osd/types.h>
37
38 #include "opensubdiv_intern.h"
39 #include "opensubdiv_topology_refiner.h"
40
41 #include "MEM_guardedalloc.h"
42
43 using OpenSubdiv::Osd::BufferDescriptor;
44 using OpenSubdiv::Osd::PatchCoord;
45 using OpenSubdiv::Far::PatchMap;
46 using OpenSubdiv::Far::PatchTable;
47 using OpenSubdiv::Far::PatchTableFactory;
48 using OpenSubdiv::Far::StencilTable;
49 using OpenSubdiv::Far::StencilTableFactory;
50 using OpenSubdiv::Far::TopologyRefiner;
51
52 namespace {
53
54 /* Helper class to wrap numerous of patch coords into a buffer.
55  * Used to pass coordinates to the CPU evaluator. Other evaluators
56  * are not supported.
57  */
58 class PatchCoordBuffer : public std::vector<PatchCoord> {
59 public:
60         static PatchCoordBuffer *Create(int size)
61         {
62                 PatchCoordBuffer *buffer = new PatchCoordBuffer();
63                 buffer->resize(size);
64                 return buffer;
65         }
66         PatchCoord *BindCpuBuffer() {
67                 return (PatchCoord*)&(*this)[0];
68         }
69         int GetNumVertices() {
70                 return size();
71         }
72         void UpdateData(const PatchCoord *patch_coords,
73                         int num_patch_coords)
74         {
75                 memcpy(&(*this)[0],
76                        (void*)patch_coords,
77                        num_patch_coords * sizeof(PatchCoord));
78         }
79 };
80
81 /* Helper class to wrap single of patch coord into a buffer.
82  * Used to pass coordinates to the CPU evaluator. Other evaluators
83  * are not supported.
84  */
85 class SinglePatchCoordBuffer {
86 public:
87         SinglePatchCoordBuffer() {
88         }
89         SinglePatchCoordBuffer(const PatchCoord& patch_coord)
90                 : patch_coord_(patch_coord){
91         }
92         static SinglePatchCoordBuffer *Create()
93         {
94                 SinglePatchCoordBuffer *buffer = new SinglePatchCoordBuffer();
95                 return buffer;
96         }
97         PatchCoord *BindCpuBuffer() {
98                 return (PatchCoord*)&patch_coord_;
99         }
100         int GetNumVertices() {
101                 return 1;
102         }
103         void UpdateData(const PatchCoord& patch_coord)
104         {
105                 patch_coord_ = patch_coord;
106         }
107 protected:
108         PatchCoord patch_coord_;
109 };
110
111 /* Helper class which is aimed to be used in cases when buffer
112  * is small enough and better to be allocated in stack rather
113  * than in heap.
114  *
115  * TODO(sergey): Check if bare arrays could be used by CPU evalautor.
116  */
117 template <int element_size, int num_verts>
118 class StackAllocatedBuffer {
119 public:
120         static PatchCoordBuffer *Create(int /*size*/)
121         {
122                 StackAllocatedBuffer<element_size, num_verts> *buffer =
123                         new StackAllocatedBuffer<element_size, num_verts>();
124                 return buffer;
125         }
126         float *BindCpuBuffer() {
127                 return &data_[0];
128         }
129         int GetNumVertices() {
130                 return num_verts;
131         }
132         /* TODO(sergey): Support UpdateData(). */
133 protected:
134         float data_[element_size * num_verts];
135 };
136
137 /* Volatile evaluator which can be used from threads.
138  *
139  * TODO(sergey): Make it possible to evaluate coordinates in chuncks.
140  */
141 template<typename SRC_VERTEX_BUFFER,
142          typename EVAL_VERTEX_BUFFER,
143          typename STENCIL_TABLE,
144          typename PATCH_TABLE,
145          typename EVALUATOR,
146          typename DEVICE_CONTEXT = void>
147 class VolatileEvalOutput {
148 public:
149         typedef OpenSubdiv::Osd::EvaluatorCacheT<EVALUATOR> EvaluatorCache;
150
151         VolatileEvalOutput(const StencilTable *vertex_stencils,
152                            const StencilTable *varying_stencils,
153                            int num_coarse_verts,
154                            int num_total_verts,
155                            const PatchTable *patch_table,
156                            EvaluatorCache *evaluator_cache = NULL,
157                            DEVICE_CONTEXT *device_context = NULL)
158             : src_desc_(        /*offset*/ 0, /*length*/ 3, /*stride*/ 3),
159               src_varying_desc_(/*offset*/ 0, /*length*/ 3, /*stride*/ 3),
160               num_coarse_verts_(num_coarse_verts),
161               evaluator_cache_ (evaluator_cache),
162               device_context_(device_context)
163         {
164                 using OpenSubdiv::Osd::convertToCompatibleStencilTable;
165                 src_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_verts, device_context_);
166                 src_varying_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_verts, device_context_);
167                 patch_table_ = PATCH_TABLE::Create(patch_table, device_context_);
168                 patch_coords_ = NULL;
169                 vertex_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(vertex_stencils,
170                                                                                   device_context_);
171                 varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(varying_stencils,
172                                                                                    device_context_);
173         }
174
175         ~VolatileEvalOutput()
176         {
177                 delete src_data_;
178                 delete src_varying_data_;
179                 delete patch_table_;
180                 delete vertex_stencils_;
181                 delete varying_stencils_;
182         }
183
184         void UpdateData(const float *src, int start_vertex, int num_vertices)
185         {
186                 src_data_->UpdateData(src, start_vertex, num_vertices, device_context_);
187         }
188
189         void UpdateVaryingData(const float *src, int start_vertex, int num_vertices)
190         {
191                 src_varying_data_->UpdateData(src,
192                                               start_vertex,
193                                               num_vertices,
194                                               device_context_);
195         }
196
197         void Refine()
198         {
199                 BufferDescriptor dst_desc = src_desc_;
200                 dst_desc.offset += num_coarse_verts_ * src_desc_.stride;
201
202                 const EVALUATOR *eval_instance =
203                         OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_,
204                                                                  src_desc_,
205                                                                  dst_desc,
206                                                                  device_context_);
207
208                 EVALUATOR::EvalStencils(src_data_, src_desc_,
209                                         src_data_, dst_desc,
210                                         vertex_stencils_,
211                                         eval_instance,
212                                         device_context_);
213
214                 dst_desc = src_varying_desc_;
215                 dst_desc.offset += num_coarse_verts_ * src_varying_desc_.stride;
216                 eval_instance =
217                         OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_,
218                                                                  src_varying_desc_,
219                                                                  dst_desc,
220                                                                  device_context_);
221
222                 EVALUATOR::EvalStencils(src_varying_data_, src_varying_desc_,
223                                         src_varying_data_, dst_desc,
224                                         varying_stencils_,
225                                         eval_instance,
226                                         device_context_);
227         }
228
229         void EvalPatchCoord(PatchCoord& patch_coord, float P[3])
230         {
231                 StackAllocatedBuffer<6, 1> vertex_data;
232                 BufferDescriptor vertex_desc(0, 3, 6);
233                 SinglePatchCoordBuffer patch_coord_buffer(patch_coord);
234                 const EVALUATOR *eval_instance =
235                         OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_,
236                                                                  src_desc_,
237                                                                  vertex_desc,
238                                                                  device_context_);
239                 EVALUATOR::EvalPatches(src_data_, src_desc_,
240                                        &vertex_data, vertex_desc,
241                                        patch_coord_buffer.GetNumVertices(),
242                                        &patch_coord_buffer,
243                                        patch_table_, eval_instance, device_context_);
244                 float *refined_verts = vertex_data.BindCpuBuffer();
245                 memcpy(P, refined_verts, sizeof(float) * 3);
246         }
247
248         void EvalPatchesWithDerivatives(PatchCoord& patch_coord,
249                                         float P[3],
250                                         float dPdu[3],
251                                         float dPdv[3])
252         {
253                 StackAllocatedBuffer<6, 1> vertex_data, derivatives;
254                 BufferDescriptor vertex_desc(0, 3, 6),
255                                  du_desc(0, 3, 6),
256                                  dv_desc(3, 3, 6);
257                 SinglePatchCoordBuffer patch_coord_buffer(patch_coord);
258                 const EVALUATOR *eval_instance =
259                         OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_,
260                                                                  src_desc_,
261                                                                  vertex_desc,
262                                                                  du_desc,
263                                                                  dv_desc,
264                                                                  device_context_);
265                 EVALUATOR::EvalPatches(src_data_, src_desc_,
266                                        &vertex_data, vertex_desc,
267                                        &derivatives, du_desc,
268                                        &derivatives, dv_desc,
269                                        patch_coord_buffer.GetNumVertices(),
270                                        &patch_coord_buffer,
271                                        patch_table_, eval_instance, device_context_);
272                 float *refined_verts = vertex_data.BindCpuBuffer();
273                 memcpy(P, refined_verts, sizeof(float) * 3);
274                 if (dPdu != NULL || dPdv != NULL) {
275                         float *refined_drivatives = derivatives.BindCpuBuffer();
276                         if (dPdu) {
277                                 memcpy(dPdu, refined_drivatives, sizeof(float) * 3);
278                         }
279                         if (dPdv) {
280                                 memcpy(dPdv, refined_drivatives + 3, sizeof(float) * 3);
281                         }
282                 }
283         }
284
285         void EvalPatchVarying(PatchCoord& patch_coord,
286                               float varying[3]) {
287                 StackAllocatedBuffer<3, 1> varying_data;
288                 BufferDescriptor varying_desc(0, 3, 3);
289                 SinglePatchCoordBuffer patch_coord_buffer(patch_coord);
290                 EVALUATOR const *eval_instance =
291                         OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(evaluator_cache_,
292                                                                  src_varying_desc_,
293                                                                  varying_desc,
294                                                                  device_context_);
295
296                 EVALUATOR::EvalPatches(src_varying_data_, src_varying_desc_,
297                                        &varying_data, varying_desc,
298                                        patch_coord_buffer.GetNumVertices(),
299                                        &patch_coord_buffer,
300                                        patch_table_, eval_instance, device_context_);
301                 float *refined_varying = varying_data.BindCpuBuffer();
302                 memcpy(varying, refined_varying, sizeof(float) * 3);
303         }
304 private:
305         SRC_VERTEX_BUFFER *src_data_;
306         SRC_VERTEX_BUFFER *src_varying_data_;
307         PatchCoordBuffer *patch_coords_;
308         PATCH_TABLE *patch_table_;
309         BufferDescriptor src_desc_;
310         BufferDescriptor src_varying_desc_;
311         int num_coarse_verts_;
312
313         const STENCIL_TABLE *vertex_stencils_;
314         const STENCIL_TABLE *varying_stencils_;
315
316         EvaluatorCache *evaluator_cache_;
317         DEVICE_CONTEXT *device_context_;
318 };
319
320 }  /* namespace */
321
322 typedef VolatileEvalOutput<OpenSubdiv::Osd::CpuVertexBuffer,
323                            OpenSubdiv::Osd::CpuVertexBuffer,
324                            OpenSubdiv::Far::StencilTable,
325                            OpenSubdiv::Osd::CpuPatchTable,
326                            OpenSubdiv::Osd::CpuEvaluator> CpuEvalOutput;
327
328 typedef struct OpenSubdiv_EvaluatorDescr {
329         CpuEvalOutput *eval_output;
330         const PatchMap *patch_map;
331         const PatchTable *patch_table;
332 } OpenSubdiv_EvaluatorDescr;
333
334 OpenSubdiv_EvaluatorDescr *openSubdiv_createEvaluatorDescr(
335         OpenSubdiv_TopologyRefinerDescr *topology_refiner,
336         int subsurf_level)
337 {
338         /* TODO(sergey): Look into re-using refiner with GLMesh. */
339         TopologyRefiner *refiner = topology_refiner->osd_refiner;
340         if(refiner == NULL) {
341                 /* Happens on bad topology. */
342                 return NULL;
343         }
344
345         const StencilTable *vertex_stencils = NULL;
346         const StencilTable *varying_stencils = NULL;
347         int num_total_verts = 0;
348
349         /* Apply uniform refinement to the mesh so that we can use the
350          * limit evaluation API features.
351          */
352         TopologyRefiner::UniformOptions options(subsurf_level);
353         refiner->RefineUniform(options);
354
355         /* Generate stencil table to update the bi-cubic patches control
356          * vertices after they have been re-posed (both for vertex & varying
357          * interpolation).
358          */
359         StencilTableFactory::Options soptions;
360         soptions.generateOffsets = true;
361         soptions.generateIntermediateLevels = false;
362
363         vertex_stencils = StencilTableFactory::Create(*refiner, soptions);
364
365         soptions.interpolationMode = StencilTableFactory::INTERPOLATE_VARYING;
366         varying_stencils = StencilTableFactory::Create(*refiner, soptions);
367
368         /* Generate bi-cubic patch table for the limit surface. */
369         PatchTableFactory::Options poptions;
370         poptions.SetEndCapType(PatchTableFactory::Options::ENDCAP_BSPLINE_BASIS);
371
372         const PatchTable *patch_table = PatchTableFactory::Create(*refiner, poptions);
373
374         /* Append local points stencils. */
375         /* TODO(sergey): Do we really need to worry about local points stencils? */
376         if (const StencilTable *local_point_stencil_table =
377             patch_table->GetLocalPointStencilTable())
378         {
379                 const StencilTable *table =
380                         StencilTableFactory::AppendLocalPointStencilTable(*refiner,
381                                                                           vertex_stencils,
382                                                                           local_point_stencil_table);
383                 delete vertex_stencils;
384                 vertex_stencils = table;
385         }
386         if (const StencilTable *local_point_varying_stencil_table =
387              patch_table->GetLocalPointVaryingStencilTable())
388         {
389                 const StencilTable *table =
390                         StencilTableFactory::AppendLocalPointStencilTable(*refiner,
391                                                                           varying_stencils,
392                                                                           local_point_varying_stencil_table);
393                 delete varying_stencils;
394                 varying_stencils = table;
395         }
396
397         /* Total number of vertices = coarse verts + refined verts + gregory basis verts. */
398         num_total_verts = vertex_stencils->GetNumControlVertices() +
399                 vertex_stencils->GetNumStencils();
400
401         const int num_coarse_verts = refiner->GetLevel(0).GetNumVertices();
402
403         CpuEvalOutput *eval_output = new CpuEvalOutput(vertex_stencils,
404                                                        varying_stencils,
405                                                        num_coarse_verts,
406                                                        num_total_verts,
407                                                        patch_table);
408
409         OpenSubdiv::Far::PatchMap *patch_map = new PatchMap(*patch_table);
410
411         OpenSubdiv_EvaluatorDescr *evaluator_descr;
412         evaluator_descr = OBJECT_GUARDED_NEW(OpenSubdiv_EvaluatorDescr);
413         evaluator_descr->eval_output = eval_output;
414         evaluator_descr->patch_map = patch_map;
415         evaluator_descr->patch_table = patch_table;
416
417         /* TOOD(sergey): Look into whether w've got duplicated stencils arrays. */
418         delete varying_stencils;
419         delete vertex_stencils;
420
421         delete refiner;
422
423         return evaluator_descr;
424 }
425
426 void openSubdiv_deleteEvaluatorDescr(OpenSubdiv_EvaluatorDescr *evaluator_descr)
427 {
428         delete evaluator_descr->eval_output;
429         delete evaluator_descr->patch_map;
430         delete evaluator_descr->patch_table;
431         OBJECT_GUARDED_DELETE(evaluator_descr, OpenSubdiv_EvaluatorDescr);
432 }
433
434 void openSubdiv_setEvaluatorCoarsePositions(OpenSubdiv_EvaluatorDescr *evaluator_descr,
435                                             float *positions,
436                                             int start_vert,
437                                             int num_verts)
438 {
439         /* TODO(sergey): Add sanity check on indices. */
440         evaluator_descr->eval_output->UpdateData(positions, start_vert, num_verts);
441         /* TODO(sergey): Consider moving this to a separate call,
442          * so we can updatwe coordinates in chunks.
443          */
444         evaluator_descr->eval_output->Refine();
445 }
446
447 void openSubdiv_setEvaluatorVaryingData(OpenSubdiv_EvaluatorDescr *evaluator_descr,
448                                         float *varying_data,
449                                         int start_vert,
450                                         int num_verts)
451 {
452         /* TODO(sergey): Add sanity check on indices. */
453         evaluator_descr->eval_output->UpdateVaryingData(varying_data, start_vert, num_verts);
454         /* TODO(sergey): Get rid of this ASAP. */
455         evaluator_descr->eval_output->Refine();
456 }
457
458 void openSubdiv_evaluateLimit(OpenSubdiv_EvaluatorDescr *evaluator_descr,
459                               int osd_face_index,
460                               float face_u, float face_v,
461                               float P[3],
462                               float dPdu[3],
463                               float dPdv[3])
464 {
465         assert((face_u >= 0.0f) && (face_u <= 1.0f) && (face_v >= 0.0f) && (face_v <= 1.0f));
466         const PatchTable::PatchHandle *handle =
467                 evaluator_descr->patch_map->FindPatch(osd_face_index, face_u, face_v);
468         PatchCoord patch_coord(*handle, face_u, face_v);
469         if (dPdu != NULL || dPdv != NULL) {
470                 evaluator_descr->eval_output->EvalPatchesWithDerivatives(patch_coord,
471                                                                          P,
472                                                                          dPdu,
473                                                                          dPdv);
474         }
475         else {
476                 evaluator_descr->eval_output->EvalPatchCoord(patch_coord, P);
477         }
478 }
479
480 void openSubdiv_evaluateVarying(OpenSubdiv_EvaluatorDescr *evaluator_descr,
481                                int osd_face_index,
482                                float face_u, float face_v,
483                                float varying[3])
484 {
485         assert((face_u >= 0.0f) && (face_u <= 1.0f) && (face_v >= 0.0f) && (face_v <= 1.0f));
486         const PatchTable::PatchHandle *handle =
487                 evaluator_descr->patch_map->FindPatch(osd_face_index, face_u, face_v);
488         PatchCoord patch_coord(*handle, face_u, face_v);
489         evaluator_descr->eval_output->EvalPatchVarying(patch_coord, varying);
490 }