Blender  V2.93
evaluator_impl.cc
Go to the documentation of this file.
1 // Copyright 2018 Blender Foundation. All rights reserved.
2 //
3 // This program is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU General Public License
5 // as published by the Free Software Foundation; either version 2
6 // of the License, or (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software Foundation,
15 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 //
17 // Author: Sergey Sharybin
18 
20 
21 #include <cassert>
22 #include <cstdio>
23 
24 #ifdef _MSC_VER
25 # include <iso646.h>
26 #endif
27 
28 #include <opensubdiv/far/patchMap.h>
29 #include <opensubdiv/far/patchTable.h>
30 #include <opensubdiv/far/patchTableFactory.h>
31 #include <opensubdiv/osd/cpuEvaluator.h>
32 #include <opensubdiv/osd/cpuPatchTable.h>
33 #include <opensubdiv/osd/cpuVertexBuffer.h>
34 #include <opensubdiv/osd/mesh.h>
35 #include <opensubdiv/osd/types.h>
36 #include <opensubdiv/version.h>
37 
38 #include "MEM_guardedalloc.h"
39 
40 #include "internal/base/type.h"
43 
44 using OpenSubdiv::Far::PatchMap;
45 using OpenSubdiv::Far::PatchTable;
46 using OpenSubdiv::Far::PatchTableFactory;
47 using OpenSubdiv::Far::StencilTable;
48 using OpenSubdiv::Far::StencilTableFactory;
49 using OpenSubdiv::Far::TopologyRefiner;
50 using OpenSubdiv::Osd::BufferDescriptor;
51 using OpenSubdiv::Osd::CpuEvaluator;
52 using OpenSubdiv::Osd::CpuPatchTable;
53 using OpenSubdiv::Osd::CpuVertexBuffer;
54 using OpenSubdiv::Osd::PatchCoord;
55 
56 namespace blender {
57 namespace opensubdiv {
58 
59 namespace {
60 
61 // Array implementation which stores small data on stack (or, rather, in the class itself).
62 template<typename T, int kNumMaxElementsOnStack> class StackOrHeapArray {
63  public:
64  StackOrHeapArray()
66  {
67  }
68 
69  explicit StackOrHeapArray(int size) : StackOrHeapArray()
70  {
71  resize(size);
72  }
73 
74  ~StackOrHeapArray()
75  {
76  delete[] heap_elements_;
77  }
78 
79  int size() const
80  {
81  return num_elements_;
82  };
83 
84  T *data()
85  {
86  return effective_elements_;
87  }
88 
89  void resize(int num_elements)
90  {
91  const int old_num_elements = num_elements_;
92  num_elements_ = num_elements;
93  // Early output if allcoation size did not change, or allocation size is smaller.
94  // We never re-allocate, sacrificing some memory over performance.
95  if (old_num_elements >= num_elements) {
96  return;
97  }
98  // Simple case: no previously allocated buffer, can simply do one allocation.
99  if (effective_elements_ == NULL) {
100  effective_elements_ = allocate(num_elements);
101  return;
102  }
103  // Make new allocation, and copy elements if needed.
104  T *old_buffer = effective_elements_;
105  effective_elements_ = allocate(num_elements);
106  if (old_buffer != effective_elements_) {
107  memcpy(effective_elements_, old_buffer, sizeof(T) * min(old_num_elements, num_elements));
108  }
109  if (old_buffer != stack_elements_) {
110  delete[] old_buffer;
111  }
112  }
113 
114  protected:
115  T *allocate(int num_elements)
116  {
117  if (num_elements < kNumMaxElementsOnStack) {
118  return stack_elements_;
119  }
120  heap_elements_ = new T[num_elements];
121  return heap_elements_;
122  }
123 
124  // Number of elements in the buffer.
126 
127  // Elements which are allocated on a stack (or, rather, in the same allocation as the buffer
128  // itself).
129  // Is used as long as buffer is smaller than kNumMaxElementsOnStack.
130  T stack_elements_[kNumMaxElementsOnStack];
131 
132  // Heap storage for buffer larger than kNumMaxElementsOnStack.
135 
136  // Depending on the current buffer size points to rither stack_elements_ or heap_elements_.
138 };
139 
140 // 32 is a number of inner vertices along the patch size at subdivision level 6.
141 typedef StackOrHeapArray<PatchCoord, 32 * 32> StackOrHeapPatchCoordArray;
142 
143 // Buffer which implements API required by OpenSubdiv and uses an existing memory as an underlying
144 // storage.
145 template<typename T> class RawDataWrapperBuffer {
146  public:
147  RawDataWrapperBuffer(T *data) : data_(data)
148  {
149  }
150 
151  T *BindCpuBuffer()
152  {
153  return data_;
154  }
155 
156  // TODO(sergey): Support UpdateData().
157 
158  protected:
160 };
161 
162 template<typename T> class RawDataWrapperVertexBuffer : public RawDataWrapperBuffer<T> {
163  public:
164  RawDataWrapperVertexBuffer(T *data, int num_vertices)
165  : RawDataWrapperBuffer<T>(data), num_vertices_(num_vertices)
166  {
167  }
168 
169  int GetNumVertices()
170  {
171  return num_vertices_;
172  }
173 
174  protected:
176 };
177 
178 class ConstPatchCoordWrapperBuffer : public RawDataWrapperVertexBuffer<const PatchCoord> {
179  public:
180  ConstPatchCoordWrapperBuffer(const PatchCoord *data, int num_vertices)
181  : RawDataWrapperVertexBuffer(data, num_vertices)
182  {
183  }
184 };
185 
186 template<typename EVAL_VERTEX_BUFFER,
187  typename STENCIL_TABLE,
188  typename PATCH_TABLE,
189  typename EVALUATOR,
190  typename DEVICE_CONTEXT = void>
191 class FaceVaryingVolatileEval {
192  public:
193  typedef OpenSubdiv::Osd::EvaluatorCacheT<EVALUATOR> EvaluatorCache;
194 
195  FaceVaryingVolatileEval(int face_varying_channel,
196  const StencilTable *face_varying_stencils,
197  int face_varying_width,
198  PATCH_TABLE *patch_table,
199  EvaluatorCache *evaluator_cache = NULL,
200  DEVICE_CONTEXT *device_context = NULL)
201  : face_varying_channel_(face_varying_channel),
202  src_face_varying_desc_(0, face_varying_width, face_varying_width),
203  patch_table_(patch_table),
204  evaluator_cache_(evaluator_cache),
205  device_context_(device_context)
206  {
207  using OpenSubdiv::Osd::convertToCompatibleStencilTable;
208  num_coarse_face_varying_vertices_ = face_varying_stencils->GetNumControlVertices();
209  const int num_total_face_varying_vertices = face_varying_stencils->GetNumControlVertices() +
210  face_varying_stencils->GetNumStencils();
211  src_face_varying_data_ = EVAL_VERTEX_BUFFER::Create(
212  2, num_total_face_varying_vertices, device_context);
213  face_varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(face_varying_stencils,
215  }
216 
217  ~FaceVaryingVolatileEval()
218  {
219  delete src_face_varying_data_;
220  delete face_varying_stencils_;
221  }
222 
223  void updateData(const float *src, int start_vertex, int num_vertices)
224  {
225  src_face_varying_data_->UpdateData(src, start_vertex, num_vertices, device_context_);
226  }
227 
228  void refine()
229  {
230  BufferDescriptor dst_face_varying_desc = src_face_varying_desc_;
231  dst_face_varying_desc.offset += num_coarse_face_varying_vertices_ *
232  src_face_varying_desc_.stride;
233  const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
234  evaluator_cache_, src_face_varying_desc_, dst_face_varying_desc, device_context_);
235  // in and out points to same buffer so output is put directly after coarse vertices, needed in
236  // adaptive mode
237  EVALUATOR::EvalStencils(src_face_varying_data_,
240  dst_face_varying_desc,
242  eval_instance,
244  }
245 
246  // NOTE: face_varying must point to a memory of at least float[2]*num_patch_coords.
247  void evalPatches(const PatchCoord *patch_coord, const int num_patch_coords, float *face_varying)
248  {
249  RawDataWrapperBuffer<float> face_varying_data(face_varying);
250  BufferDescriptor face_varying_desc(0, 2, 2);
251  ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
252  const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
254 
255  // src_face_varying_data_ always contains coarse vertices at the beginning.
256  // In adaptive mode they are followed by number of blocks for intermediate
257  // subdivision levels, and this is what OSD expects in this mode.
258  // In non-adaptive mode (generateIntermediateLevels == false),
259  // they are followed by max subdivision level, but they break interpolation as OSD
260  // expects only one subd level in this buffer.
261  // So in non-adaptive mode we put offset into buffer descriptor to skip over coarse vertices.
262  BufferDescriptor src_desc = src_face_varying_desc_;
263  if (!patch_table_->GetPatchArrayBuffer()[0].GetDescriptor().IsAdaptive()) {
264  src_desc.offset += num_coarse_face_varying_vertices_ * src_face_varying_desc_.stride;
265  }
266 
267  EVALUATOR::EvalPatchesFaceVarying(src_face_varying_data_,
268  src_desc,
269  &face_varying_data,
270  face_varying_desc,
271  patch_coord_buffer.GetNumVertices(),
272  &patch_coord_buffer,
273  patch_table_,
275  eval_instance,
277  }
278 
279  protected:
281 
282  BufferDescriptor src_face_varying_desc_;
283 
285  EVAL_VERTEX_BUFFER *src_face_varying_data_;
286  const STENCIL_TABLE *face_varying_stencils_;
287 
288  // NOTE: We reference this, do not own it.
289  PATCH_TABLE *patch_table_;
290 
291  EvaluatorCache *evaluator_cache_;
292  DEVICE_CONTEXT *device_context_;
293 };
294 
295 // Volatile evaluator which can be used from threads.
296 //
297 // TODO(sergey): Make it possible to evaluate coordinates in chunks.
298 // TODO(sergey): Make it possible to evaluate multiple face varying layers.
299 // (or maybe, it's cheap to create new evaluator for existing
300 // topology to evaluate all needed face varying layers?)
301 template<typename SRC_VERTEX_BUFFER,
302  typename EVAL_VERTEX_BUFFER,
303  typename STENCIL_TABLE,
304  typename PATCH_TABLE,
305  typename EVALUATOR,
306  typename DEVICE_CONTEXT = void>
307 class VolatileEvalOutput {
308  public:
309  typedef OpenSubdiv::Osd::EvaluatorCacheT<EVALUATOR> EvaluatorCache;
310  typedef FaceVaryingVolatileEval<EVAL_VERTEX_BUFFER,
311  STENCIL_TABLE,
312  PATCH_TABLE,
313  EVALUATOR,
314  DEVICE_CONTEXT>
315  FaceVaryingEval;
316 
317  VolatileEvalOutput(const StencilTable *vertex_stencils,
318  const StencilTable *varying_stencils,
319  const vector<const StencilTable *> &all_face_varying_stencils,
320  const int face_varying_width,
321  const PatchTable *patch_table,
322  EvaluatorCache *evaluator_cache = NULL,
323  DEVICE_CONTEXT *device_context = NULL)
324  : src_desc_(0, 3, 3),
325  src_varying_desc_(0, 3, 3),
326  face_varying_width_(face_varying_width),
327  evaluator_cache_(evaluator_cache),
328  device_context_(device_context)
329  {
330  // Total number of vertices = coarse points + refined points + local points.
331  int num_total_vertices = vertex_stencils->GetNumControlVertices() +
332  vertex_stencils->GetNumStencils();
333  num_coarse_vertices_ = vertex_stencils->GetNumControlVertices();
334  using OpenSubdiv::Osd::convertToCompatibleStencilTable;
335  src_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_vertices, device_context_);
336  src_varying_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_vertices, device_context_);
337  patch_table_ = PATCH_TABLE::Create(patch_table, device_context_);
338  vertex_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(vertex_stencils,
340  varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(varying_stencils,
342  // Create evaluators for every face varying channel.
343  face_varying_evaluators.reserve(all_face_varying_stencils.size());
344  int face_varying_channel = 0;
345  for (const StencilTable *face_varying_stencils : all_face_varying_stencils) {
346  face_varying_evaluators.push_back(new FaceVaryingEval(face_varying_channel,
347  face_varying_stencils,
348  face_varying_width,
349  patch_table_,
351  device_context_));
352  ++face_varying_channel;
353  }
354  }
355 
356  ~VolatileEvalOutput()
357  {
358  delete src_data_;
359  delete src_varying_data_;
360  delete patch_table_;
361  delete vertex_stencils_;
362  delete varying_stencils_;
363  for (FaceVaryingEval *face_varying_evaluator : face_varying_evaluators) {
364  delete face_varying_evaluator;
365  }
366  }
367 
368  // TODO(sergey): Implement binding API.
369 
370  void updateData(const float *src, int start_vertex, int num_vertices)
371  {
372  src_data_->UpdateData(src, start_vertex, num_vertices, device_context_);
373  }
374 
375  void updateVaryingData(const float *src, int start_vertex, int num_vertices)
376  {
377  src_varying_data_->UpdateData(src, start_vertex, num_vertices, device_context_);
378  }
379 
380  void updateFaceVaryingData(const int face_varying_channel,
381  const float *src,
382  int start_vertex,
383  int num_vertices)
384  {
385  assert(face_varying_channel >= 0);
386  assert(face_varying_channel < face_varying_evaluators.size());
387  face_varying_evaluators[face_varying_channel]->updateData(src, start_vertex, num_vertices);
388  }
389 
390  bool hasVaryingData() const
391  {
392  // return varying_stencils_ != NULL;
393  // TODO(sergey): Check this based on actual topology.
394  return false;
395  }
396 
397  bool hasFaceVaryingData() const
398  {
399  return face_varying_evaluators.size() != 0;
400  }
401 
402  void refine()
403  {
404  // Evaluate vertex positions.
405  BufferDescriptor dst_desc = src_desc_;
406  dst_desc.offset += num_coarse_vertices_ * src_desc_.stride;
407  const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
408  evaluator_cache_, src_desc_, dst_desc, device_context_);
409  EVALUATOR::EvalStencils(src_data_,
410  src_desc_,
411  src_data_,
412  dst_desc,
413  vertex_stencils_,
414  eval_instance,
416  // Evaluate varying data.
417  if (hasVaryingData()) {
418  BufferDescriptor dst_varying_desc = src_varying_desc_;
419  dst_varying_desc.offset += num_coarse_vertices_ * src_varying_desc_.stride;
420  eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
421  evaluator_cache_, src_varying_desc_, dst_varying_desc, device_context_);
422  EVALUATOR::EvalStencils(src_varying_data_,
423  src_varying_desc_,
424  src_varying_data_,
425  dst_varying_desc,
426  varying_stencils_,
427  eval_instance,
429  }
430  // Evaluate face-varying data.
431  if (hasFaceVaryingData()) {
432  for (FaceVaryingEval *face_varying_evaluator : face_varying_evaluators) {
433  face_varying_evaluator->refine();
434  }
435  }
436  }
437 
438  // NOTE: P must point to a memory of at least float[3]*num_patch_coords.
439  void evalPatches(const PatchCoord *patch_coord, const int num_patch_coords, float *P)
440  {
441  RawDataWrapperBuffer<float> P_data(P);
442  // TODO(sergey): Support interleaved vertex-varying data.
443  BufferDescriptor P_desc(0, 3, 3);
444  ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
445  const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
446  evaluator_cache_, src_desc_, P_desc, device_context_);
447  EVALUATOR::EvalPatches(src_data_,
448  src_desc_,
449  &P_data,
450  P_desc,
451  patch_coord_buffer.GetNumVertices(),
452  &patch_coord_buffer,
453  patch_table_,
454  eval_instance,
456  }
457 
458  // NOTE: P, dPdu, dPdv must point to a memory of at least float[3]*num_patch_coords.
459  void evalPatchesWithDerivatives(const PatchCoord *patch_coord,
460  const int num_patch_coords,
461  float *P,
462  float *dPdu,
463  float *dPdv)
464  {
465  assert(dPdu);
466  assert(dPdv);
467  RawDataWrapperBuffer<float> P_data(P);
468  RawDataWrapperBuffer<float> dPdu_data(dPdu), dPdv_data(dPdv);
469  // TODO(sergey): Support interleaved vertex-varying data.
470  BufferDescriptor P_desc(0, 3, 3);
471  BufferDescriptor dpDu_desc(0, 3, 3), pPdv_desc(0, 3, 3);
472  ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
473  const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
474  evaluator_cache_, src_desc_, P_desc, dpDu_desc, pPdv_desc, device_context_);
475  EVALUATOR::EvalPatches(src_data_,
476  src_desc_,
477  &P_data,
478  P_desc,
479  &dPdu_data,
480  dpDu_desc,
481  &dPdv_data,
482  pPdv_desc,
483  patch_coord_buffer.GetNumVertices(),
484  &patch_coord_buffer,
485  patch_table_,
486  eval_instance,
488  }
489 
490  // NOTE: varying must point to a memory of at least float[3]*num_patch_coords.
491  void evalPatchesVarying(const PatchCoord *patch_coord,
492  const int num_patch_coords,
493  float *varying)
494  {
495  RawDataWrapperBuffer<float> varying_data(varying);
496  BufferDescriptor varying_desc(3, 3, 6);
497  ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords);
498  const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>(
499  evaluator_cache_, src_varying_desc_, varying_desc, device_context_);
500  EVALUATOR::EvalPatchesVarying(src_varying_data_,
501  src_varying_desc_,
502  &varying_data,
503  varying_desc,
504  patch_coord_buffer.GetNumVertices(),
505  &patch_coord_buffer,
506  patch_table_,
507  eval_instance,
509  }
510 
511  void evalPatchesFaceVarying(const int face_varying_channel,
512  const PatchCoord *patch_coord,
513  const int num_patch_coords,
514  float face_varying[2])
515  {
516  assert(face_varying_channel >= 0);
517  assert(face_varying_channel < face_varying_evaluators.size());
518  face_varying_evaluators[face_varying_channel]->evalPatches(
519  patch_coord, num_patch_coords, face_varying);
520  }
521 
522  private:
523  SRC_VERTEX_BUFFER *src_data_;
524  SRC_VERTEX_BUFFER *src_varying_data_;
525  PATCH_TABLE *patch_table_;
526  BufferDescriptor src_desc_;
527  BufferDescriptor src_varying_desc_;
528 
529  int num_coarse_vertices_;
530 
531  const STENCIL_TABLE *vertex_stencils_;
532  const STENCIL_TABLE *varying_stencils_;
533 
534  int face_varying_width_;
535  vector<FaceVaryingEval *> face_varying_evaluators;
536 
537  EvaluatorCache *evaluator_cache_;
538  DEVICE_CONTEXT *device_context_;
539 };
540 
541 void convertPatchCoordsToArray(const OpenSubdiv_PatchCoord *patch_coords,
542  const int num_patch_coords,
543  const OpenSubdiv::Far::PatchMap *patch_map,
544  StackOrHeapPatchCoordArray *array)
545 {
546  array->resize(num_patch_coords);
547  for (int i = 0; i < num_patch_coords; ++i) {
548  const PatchTable::PatchHandle *handle = patch_map->FindPatch(
549  patch_coords[i].ptex_face, patch_coords[i].u, patch_coords[i].v);
550  (array->data())[i] = PatchCoord(*handle, patch_coords[i].u, patch_coords[i].v);
551  }
552 }
553 
554 } // namespace
555 
556 // Note: Define as a class instead of typedcef to make it possible
557 // to have anonymous class in opensubdiv_evaluator_internal.h
558 class CpuEvalOutput : public VolatileEvalOutput<CpuVertexBuffer,
559  CpuVertexBuffer,
560  StencilTable,
561  CpuPatchTable,
562  CpuEvaluator> {
563  public:
564  CpuEvalOutput(const StencilTable *vertex_stencils,
565  const StencilTable *varying_stencils,
566  const vector<const StencilTable *> &all_face_varying_stencils,
567  const int face_varying_width,
568  const PatchTable *patch_table,
569  EvaluatorCache *evaluator_cache = NULL)
570  : VolatileEvalOutput<CpuVertexBuffer,
571  CpuVertexBuffer,
572  StencilTable,
573  CpuPatchTable,
574  CpuEvaluator>(vertex_stencils,
575  varying_stencils,
576  all_face_varying_stencils,
577  face_varying_width,
578  patch_table,
579  evaluator_cache)
580  {
581  }
582 };
583 
585 // Evaluator wrapper for anonymous API.
586 
588  OpenSubdiv::Far::PatchMap *patch_map)
589  : implementation_(implementation), patch_map_(patch_map)
590 {
591 }
592 
594 {
595  delete implementation_;
596 }
597 
598 void CpuEvalOutputAPI::setCoarsePositions(const float *positions,
599  const int start_vertex_index,
600  const int num_vertices)
601 {
602  // TODO(sergey): Add sanity check on indices.
603  implementation_->updateData(positions, start_vertex_index, num_vertices);
604 }
605 
606 void CpuEvalOutputAPI::setVaryingData(const float *varying_data,
607  const int start_vertex_index,
608  const int num_vertices)
609 {
610  // TODO(sergey): Add sanity check on indices.
611  implementation_->updateVaryingData(varying_data, start_vertex_index, num_vertices);
612 }
613 
614 void CpuEvalOutputAPI::setFaceVaryingData(const int face_varying_channel,
615  const float *face_varying_data,
616  const int start_vertex_index,
617  const int num_vertices)
618 {
619  // TODO(sergey): Add sanity check on indices.
620  implementation_->updateFaceVaryingData(
621  face_varying_channel, face_varying_data, start_vertex_index, num_vertices);
622 }
623 
625  const int start_offset,
626  const int stride,
627  const int start_vertex_index,
628  const int num_vertices)
629 {
630  // TODO(sergey): Add sanity check on indices.
631  const unsigned char *current_buffer = (unsigned char *)buffer;
632  current_buffer += start_offset;
633  for (int i = 0; i < num_vertices; ++i) {
634  const int current_vertex_index = start_vertex_index + i;
635  implementation_->updateData(
636  reinterpret_cast<const float *>(current_buffer), current_vertex_index, 1);
637  current_buffer += stride;
638  }
639 }
640 
642  const int start_offset,
643  const int stride,
644  const int start_vertex_index,
645  const int num_vertices)
646 {
647  // TODO(sergey): Add sanity check on indices.
648  const unsigned char *current_buffer = (unsigned char *)buffer;
649  current_buffer += start_offset;
650  for (int i = 0; i < num_vertices; ++i) {
651  const int current_vertex_index = start_vertex_index + i;
652  implementation_->updateVaryingData(
653  reinterpret_cast<const float *>(current_buffer), current_vertex_index, 1);
654  current_buffer += stride;
655  }
656 }
657 
658 void CpuEvalOutputAPI::setFaceVaryingDataFromBuffer(const int face_varying_channel,
659  const void *buffer,
660  const int start_offset,
661  const int stride,
662  const int start_vertex_index,
663  const int num_vertices)
664 {
665  // TODO(sergey): Add sanity check on indices.
666  const unsigned char *current_buffer = (unsigned char *)buffer;
667  current_buffer += start_offset;
668  for (int i = 0; i < num_vertices; ++i) {
669  const int current_vertex_index = start_vertex_index + i;
670  implementation_->updateFaceVaryingData(face_varying_channel,
671  reinterpret_cast<const float *>(current_buffer),
672  current_vertex_index,
673  1);
674  current_buffer += stride;
675  }
676 }
677 
679 {
680  implementation_->refine();
681 }
682 
683 void CpuEvalOutputAPI::evaluateLimit(const int ptex_face_index,
684  float face_u,
685  float face_v,
686  float P[3],
687  float dPdu[3],
688  float dPdv[3])
689 {
690  assert(face_u >= 0.0f);
691  assert(face_u <= 1.0f);
692  assert(face_v >= 0.0f);
693  assert(face_v <= 1.0f);
694  const PatchTable::PatchHandle *handle = patch_map_->FindPatch(ptex_face_index, face_u, face_v);
695  PatchCoord patch_coord(*handle, face_u, face_v);
696  if (dPdu != NULL || dPdv != NULL) {
697  implementation_->evalPatchesWithDerivatives(&patch_coord, 1, P, dPdu, dPdv);
698  }
699  else {
700  implementation_->evalPatches(&patch_coord, 1, P);
701  }
702 }
703 
704 void CpuEvalOutputAPI::evaluateVarying(const int ptex_face_index,
705  float face_u,
706  float face_v,
707  float varying[3])
708 {
709  assert(face_u >= 0.0f);
710  assert(face_u <= 1.0f);
711  assert(face_v >= 0.0f);
712  assert(face_v <= 1.0f);
713  const PatchTable::PatchHandle *handle = patch_map_->FindPatch(ptex_face_index, face_u, face_v);
714  PatchCoord patch_coord(*handle, face_u, face_v);
715  implementation_->evalPatchesVarying(&patch_coord, 1, varying);
716 }
717 
718 void CpuEvalOutputAPI::evaluateFaceVarying(const int face_varying_channel,
719  const int ptex_face_index,
720  float face_u,
721  float face_v,
722  float face_varying[2])
723 {
724  assert(face_u >= 0.0f);
725  assert(face_u <= 1.0f);
726  assert(face_v >= 0.0f);
727  assert(face_v <= 1.0f);
728  const PatchTable::PatchHandle *handle = patch_map_->FindPatch(ptex_face_index, face_u, face_v);
729  PatchCoord patch_coord(*handle, face_u, face_v);
730  implementation_->evalPatchesFaceVarying(face_varying_channel, &patch_coord, 1, face_varying);
731 }
732 
734  const int num_patch_coords,
735  float *P,
736  float *dPdu,
737  float *dPdv)
738 {
739  StackOrHeapPatchCoordArray patch_coords_array;
740  convertPatchCoordsToArray(patch_coords, num_patch_coords, patch_map_, &patch_coords_array);
741  if (dPdu != NULL || dPdv != NULL) {
742  implementation_->evalPatchesWithDerivatives(
743  patch_coords_array.data(), num_patch_coords, P, dPdu, dPdv);
744  }
745  else {
746  implementation_->evalPatches(patch_coords_array.data(), num_patch_coords, P);
747  }
748 }
749 
750 } // namespace opensubdiv
751 } // namespace blender
752 
754  : eval_output(NULL), patch_map(NULL), patch_table(NULL)
755 {
756 }
757 
759 {
760  delete eval_output;
761  delete patch_map;
762  delete patch_table;
763 }
764 
766  OpenSubdiv_TopologyRefiner *topology_refiner)
767 {
769  TopologyRefiner *refiner = topology_refiner->impl->topology_refiner;
770  if (refiner == NULL) {
771  // Happens on bad topology.
772  return NULL;
773  }
774  // TODO(sergey): Base this on actual topology.
775  const bool has_varying_data = false;
776  const int num_face_varying_channels = refiner->GetNumFVarChannels();
777  const bool has_face_varying_data = (num_face_varying_channels != 0);
778  const int level = topology_refiner->getSubdivisionLevel(topology_refiner);
779  const bool is_adaptive = topology_refiner->getIsAdaptive(topology_refiner);
780  // Common settings for stencils and patches.
781  const bool stencil_generate_intermediate_levels = is_adaptive;
782  const bool stencil_generate_offsets = true;
783  const bool use_inf_sharp_patch = true;
784  // Refine the topology with given settings.
785  // TODO(sergey): What if topology is already refined?
786  if (is_adaptive) {
787  TopologyRefiner::AdaptiveOptions options(level);
788  options.considerFVarChannels = has_face_varying_data;
789  options.useInfSharpPatch = use_inf_sharp_patch;
790  refiner->RefineAdaptive(options);
791  }
792  else {
793  TopologyRefiner::UniformOptions options(level);
794  refiner->RefineUniform(options);
795  }
796  // Generate stencil table to update the bi-cubic patches control vertices
797  // after they have been re-posed (both for vertex & varying interpolation).
798  //
799  // Vertex stencils.
800  StencilTableFactory::Options vertex_stencil_options;
801  vertex_stencil_options.generateOffsets = stencil_generate_offsets;
802  vertex_stencil_options.generateIntermediateLevels = stencil_generate_intermediate_levels;
803  const StencilTable *vertex_stencils = StencilTableFactory::Create(*refiner,
804  vertex_stencil_options);
805  // Varying stencils.
806  //
807  // TODO(sergey): Seems currently varying stencils are always required in
808  // OpenSubdiv itself.
809  const StencilTable *varying_stencils = NULL;
810  if (has_varying_data) {
811  StencilTableFactory::Options varying_stencil_options;
812  varying_stencil_options.generateOffsets = stencil_generate_offsets;
813  varying_stencil_options.generateIntermediateLevels = stencil_generate_intermediate_levels;
814  varying_stencil_options.interpolationMode = StencilTableFactory::INTERPOLATE_VARYING;
815  varying_stencils = StencilTableFactory::Create(*refiner, varying_stencil_options);
816  }
817  // Face warying stencil.
818  vector<const StencilTable *> all_face_varying_stencils;
819  all_face_varying_stencils.reserve(num_face_varying_channels);
820  for (int face_varying_channel = 0; face_varying_channel < num_face_varying_channels;
821  ++face_varying_channel) {
822  StencilTableFactory::Options face_varying_stencil_options;
823  face_varying_stencil_options.generateOffsets = stencil_generate_offsets;
824  face_varying_stencil_options.generateIntermediateLevels = stencil_generate_intermediate_levels;
825  face_varying_stencil_options.interpolationMode = StencilTableFactory::INTERPOLATE_FACE_VARYING;
826  face_varying_stencil_options.fvarChannel = face_varying_channel;
827  all_face_varying_stencils.push_back(
828  StencilTableFactory::Create(*refiner, face_varying_stencil_options));
829  }
830  // Generate bi-cubic patch table for the limit surface.
831  PatchTableFactory::Options patch_options(level);
832  patch_options.SetEndCapType(PatchTableFactory::Options::ENDCAP_GREGORY_BASIS);
833  patch_options.useInfSharpPatch = use_inf_sharp_patch;
834  patch_options.generateFVarTables = has_face_varying_data;
835  patch_options.generateFVarLegacyLinearPatches = false;
836  const PatchTable *patch_table = PatchTableFactory::Create(*refiner, patch_options);
837  // Append local points stencils.
838  // Point stencils.
839  const StencilTable *local_point_stencil_table = patch_table->GetLocalPointStencilTable();
840  if (local_point_stencil_table != NULL) {
841  const StencilTable *table = StencilTableFactory::AppendLocalPointStencilTable(
842  *refiner, vertex_stencils, local_point_stencil_table);
843  delete vertex_stencils;
844  vertex_stencils = table;
845  }
846  // Varying stencils.
847  if (has_varying_data) {
848  const StencilTable *local_point_varying_stencil_table =
849  patch_table->GetLocalPointVaryingStencilTable();
850  if (local_point_varying_stencil_table != NULL) {
851  const StencilTable *table = StencilTableFactory::AppendLocalPointStencilTable(
852  *refiner, varying_stencils, local_point_varying_stencil_table);
853  delete varying_stencils;
854  varying_stencils = table;
855  }
856  }
857  for (int face_varying_channel = 0; face_varying_channel < num_face_varying_channels;
858  ++face_varying_channel) {
859  const StencilTable *table = StencilTableFactory::AppendLocalPointStencilTableFaceVarying(
860  *refiner,
861  all_face_varying_stencils[face_varying_channel],
862  patch_table->GetLocalPointFaceVaryingStencilTable(face_varying_channel),
863  face_varying_channel);
864  if (table != NULL) {
865  delete all_face_varying_stencils[face_varying_channel];
866  all_face_varying_stencils[face_varying_channel] = table;
867  }
868  }
869  // Create OpenSubdiv's CPU side evaluator.
870  // TODO(sergey): Make it possible to use different evaluators.
872  vertex_stencils, varying_stencils, all_face_varying_stencils, 2, patch_table);
873  OpenSubdiv::Far::PatchMap *patch_map = new PatchMap(*patch_table);
874  // Wrap everything we need into an object which we control from our side.
875  OpenSubdiv_EvaluatorImpl *evaluator_descr;
876  evaluator_descr = new OpenSubdiv_EvaluatorImpl();
877  evaluator_descr->eval_output = new blender::opensubdiv::CpuEvalOutputAPI(eval_output, patch_map);
878  evaluator_descr->patch_map = patch_map;
879  evaluator_descr->patch_table = patch_table;
880  // TOOD(sergey): Look into whether we've got duplicated stencils arrays.
881  delete vertex_stencils;
882  delete varying_stencils;
883  for (const StencilTable *table : all_face_varying_stencils) {
884  delete table;
885  }
886  return evaluator_descr;
887 }
888 
890 {
891  delete evaluator;
892 }
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei stride
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
T * data()
Definition: util_array.h:208
T * resize(size_t newsize)
Definition: util_array.h:150
OpenSubdiv::Far::PatchMap * patch_map_
void setFaceVaryingData(const int face_varying_channel, const float *varying_data, const int start_vertex_index, const int num_vertices)
void evaluateFaceVarying(const int face_varying_channel, const int ptes_face_index, float face_u, float face_v, float face_varying[2])
void setCoarsePositions(const float *positions, const int start_vertex_index, const int num_vertices)
void evaluateLimit(const int ptex_face_index, float face_u, float face_v, float P[3], float dPdu[3], float dPdv[3])
void setCoarsePositionsFromBuffer(const void *buffer, const int start_offset, const int stride, const int start_vertex_index, const int num_vertices)
void setVaryingDataFromBuffer(const void *buffer, const int start_offset, const int stride, const int start_vertex_index, const int num_vertices)
void evaluateVarying(const int ptes_face_index, float face_u, float face_v, float varying[3])
void evaluatePatchesLimit(const OpenSubdiv_PatchCoord *patch_coords, const int num_patch_coords, float *P, float *dPdu, float *dPdv)
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)
CpuEvalOutputAPI(CpuEvalOutput *implementation, OpenSubdiv::Far::PatchMap *patch_map)
void setVaryingData(const float *varying_data, const int start_vertex_index, const int num_vertices)
CpuEvalOutput(const StencilTable *vertex_stencils, const StencilTable *varying_stencils, const vector< const StencilTable * > &all_face_varying_stencils, const int face_varying_width, const PatchTable *patch_table, EvaluatorCache *evaluator_cache=NULL)
OpenSubdiv::Far::TopologyRefiner * topology_refiner
CCL_NAMESPACE_BEGIN struct Options options
PATCH_TABLE * patch_table_
int num_coarse_face_varying_vertices_
BufferDescriptor src_face_varying_desc_
T * effective_elements_
DEVICE_CONTEXT * device_context_
void openSubdiv_deleteEvaluatorInternal(OpenSubdiv_EvaluatorImpl *evaluator)
int num_elements_
int num_heap_elements_
int num_vertices_
EvaluatorCache * evaluator_cache_
EVAL_VERTEX_BUFFER * src_face_varying_data_
T * data_
OpenSubdiv_EvaluatorImpl * openSubdiv_createEvaluatorInternal(OpenSubdiv_TopologyRefiner *topology_refiner)
const STENCIL_TABLE * face_varying_stencils_
T * heap_elements_
T stack_elements_[kNumMaxElementsOnStack]
int face_varying_channel_
CCL_NAMESPACE_BEGIN struct PatchHandle PatchHandle
__kernel void ccl_constant KernelData ccl_global void ccl_global char ccl_global int ccl_global char ccl_global unsigned int ccl_global float * buffer
static float P(float k)
Definition: math_interp.c:41
#define T
std::vector< ElementType, Eigen::aligned_allocator< ElementType > > vector
Definition: vector.h:39
#define min(a, b)
Definition: sort.c:51
blender::opensubdiv::CpuEvalOutputAPI * eval_output
const OpenSubdiv::Far::PatchMap * patch_map
const OpenSubdiv::Far::PatchTable * patch_table
struct OpenSubdiv_TopologyRefinerImpl * impl
bool(* getIsAdaptive)(const struct OpenSubdiv_TopologyRefiner *topology_refiner)
int(* getSubdivisionLevel)(const struct OpenSubdiv_TopologyRefiner *topology_refiner)