OpenSubdiv: Fix error found by PerfectionCat,
[blender.git] / intern / opensubdiv / opensubdiv_capi.cc
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2013 Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Sergey Sharybin.
22  *                 Brecht van Lommel
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 #include "opensubdiv_capi.h"
28
29 #ifdef _MSC_VER
30 #  include "iso646.h"
31 #endif
32
33 #include <GL/glew.h>
34
35 #include <opensubdiv/osd/glMesh.h>
36
37 /* CPU Backend */
38 #include <opensubdiv/osd/cpuGLVertexBuffer.h>
39 #include <opensubdiv/osd/cpuEvaluator.h>
40
41 #ifdef OPENSUBDIV_HAS_OPENMP
42 #  include <opensubdiv/osd/ompEvaluator.h>
43 #endif  /* OPENSUBDIV_HAS_OPENMP */
44
45 #ifdef OPENSUBDIV_HAS_OPENCL
46 #  include <opensubdiv/osd/clGLVertexBuffer.h>
47 #  include <opensubdiv/osd/clEvaluator.h>
48 #  include "opensubdiv_device_context_opencl.h"
49 #endif  /* OPENSUBDIV_HAS_OPENCL */
50
51 #ifdef OPENSUBDIV_HAS_CUDA
52 #  include <opensubdiv/osd/cudaGLVertexBuffer.h>
53 #  include <opensubdiv/osd/cudaEvaluator.h>
54 #  include "opensubdiv_device_context_cuda.h"
55 #endif  /* OPENSUBDIV_HAS_CUDA */
56
57 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
58 #  include <opensubdiv/osd/glXFBEvaluator.h>
59 #  include <opensubdiv/osd/glVertexBuffer.h>
60 #endif  /* OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK */
61
62 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
63 #  include <opensubdiv/osd/glComputeEvaluator.h>
64 #  include <opensubdiv/osd/glVertexBuffer.h>
65 #endif  /* OPENSUBDIV_HAS_GLSL_COMPUTE */
66
67 #include <opensubdiv/osd/glPatchTable.h>
68 #include <opensubdiv/far/stencilTable.h>
69
70 #include "opensubdiv_intern.h"
71
72 #include "MEM_guardedalloc.h"
73
74 /* **************** Types declaration **************** */
75
76 using OpenSubdiv::Osd::GLMeshInterface;
77 using OpenSubdiv::Osd::Mesh;
78 using OpenSubdiv::Osd::MeshBitset;
79 using OpenSubdiv::Far::StencilTable;
80 using OpenSubdiv::Osd::GLPatchTable;
81
82 using OpenSubdiv::Osd::Mesh;
83
84 /* CPU backend */
85 using OpenSubdiv::Osd::CpuGLVertexBuffer;
86 using OpenSubdiv::Osd::CpuEvaluator;
87 typedef Mesh<CpuGLVertexBuffer,
88              StencilTable,
89              CpuEvaluator,
90              GLPatchTable> OsdCpuMesh;
91
92 #ifdef OPENSUBDIV_HAS_OPENMP
93 using OpenSubdiv::Osd::OmpEvaluator;
94 typedef Mesh<CpuGLVertexBuffer,
95              StencilTable,
96              OmpEvaluator,
97              GLPatchTable> OsdOmpMesh;
98 #endif  /* OPENSUBDIV_HAS_OPENMP */
99
100 #ifdef OPENSUBDIV_HAS_OPENCL
101 using OpenSubdiv::Osd::CLEvaluator;
102 using OpenSubdiv::Osd::CLGLVertexBuffer;
103 using OpenSubdiv::Osd::CLStencilTable;
104 /* TODO(sergey): Use CLDeviceCOntext similar to OSD examples? */
105 typedef Mesh<CLGLVertexBuffer,
106              CLStencilTable,
107              CLEvaluator,
108              GLPatchTable,
109              CLDeviceContext> OsdCLMesh;
110 static CLDeviceContext g_clDeviceContext;
111 #endif  /* OPENSUBDIV_HAS_OPENCL */
112
113 #ifdef OPENSUBDIV_HAS_CUDA
114 using OpenSubdiv::Osd::CudaEvaluator;
115 using OpenSubdiv::Osd::CudaGLVertexBuffer;
116 using OpenSubdiv::Osd::CudaStencilTable;
117 typedef Mesh<CudaGLVertexBuffer,
118              CudaStencilTable,
119              CudaEvaluator,
120              GLPatchTable> OsdCudaMesh;
121 static CudaDeviceContext g_cudaDeviceContext;
122 #endif  /* OPENSUBDIV_HAS_CUDA */
123
124 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
125 using OpenSubdiv::Osd::GLXFBEvaluator;
126 using OpenSubdiv::Osd::GLStencilTableTBO;
127 using OpenSubdiv::Osd::GLVertexBuffer;
128 typedef Mesh<GLVertexBuffer,
129              GLStencilTableTBO,
130              GLXFBEvaluator,
131              GLPatchTable> OsdGLSLTransformFeedbackMesh;
132 #endif  /* OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK */
133
134 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
135 using OpenSubdiv::Osd::GLComputeEvaluator;
136 using OpenSubdiv::Osd::GLStencilTableSSBO;
137 using OpenSubdiv::Osd::GLVertexBuffer;
138 typedef Mesh<GLVertexBuffer,
139              GLStencilTableSSBO,
140              GLComputeEvaluator,
141              GLPatchTable> OsdGLSLComputeMesh;
142 #endif
143
144 struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
145         OpenSubdiv_TopologyRefinerDescr *topology_refiner,
146         int evaluator_type,
147         int level,
148         int /*subdivide_uvs*/)
149 {
150         using OpenSubdiv::Far::TopologyRefiner;
151
152         MeshBitset bits;
153         /* TODO(sergey): Adaptive subdivisions are not currently
154          * possible because of the lack of tessellation shader.
155          */
156         bits.set(OpenSubdiv::Osd::MeshAdaptive, 0);
157         bits.set(OpenSubdiv::Osd::MeshUseSingleCreasePatch, 0);
158         bits.set(OpenSubdiv::Osd::MeshInterleaveVarying, 1);
159         bits.set(OpenSubdiv::Osd::MeshFVarData, 1);
160         bits.set(OpenSubdiv::Osd::MeshEndCapBSplineBasis, 1);
161         // bits.set(Osd::MeshEndCapGregoryBasis, 1);
162         // bits.set(Osd::MeshEndCapLegacyGregory, 1);
163
164         const int num_vertex_elements = 3;
165         const int num_varying_elements = 3;
166
167         GLMeshInterface *mesh = NULL;
168         TopologyRefiner *refiner = (TopologyRefiner*)topology_refiner;
169
170         switch(evaluator_type) {
171 #define CHECK_EVALUATOR_TYPE(type, class) \
172                 case OPENSUBDIV_EVALUATOR_ ## type: \
173                         mesh = new class(refiner, \
174                                          num_vertex_elements, \
175                                          num_varying_elements, \
176                                          level, \
177                                          bits); \
178                         break;
179
180                 CHECK_EVALUATOR_TYPE(CPU, OsdCpuMesh)
181
182 #ifdef OPENSUBDIV_HAS_OPENMP
183                 CHECK_EVALUATOR_TYPE(OPENMP, OsdOmpMesh)
184 #endif
185
186 #ifdef OPENSUBDIV_HAS_OPENCL
187                 CHECK_EVALUATOR_TYPE(OPENCL, OsdCLMesh)
188 #endif
189
190 #ifdef OPENSUBDIV_HAS_CUDA
191                 CHECK_EVALUATOR_TYPE(CUDA, OsdCudaMesh)
192 #endif
193
194 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
195                 CHECK_EVALUATOR_TYPE(GLSL_TRANSFORM_FEEDBACK,
196                                      OsdGLSLTransformFeedbackMesh)
197 #endif
198
199 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
200                 CHECK_EVALUATOR_TYPE(GLSL_COMPUTE, OsdGLSLComputeMesh)
201 #endif
202
203 #undef CHECK_EVALUATOR_TYPE
204         }
205
206         if (mesh == NULL) {
207                 return NULL;
208         }
209
210         OpenSubdiv_GLMesh *gl_mesh =
211                 (OpenSubdiv_GLMesh *) OBJECT_GUARDED_NEW(OpenSubdiv_GLMesh);
212         gl_mesh->evaluator_type = evaluator_type;
213         gl_mesh->descriptor = (OpenSubdiv_GLMeshDescr *) mesh;
214         gl_mesh->topology_refiner = (OpenSubdiv_TopologyRefinerDescr*)refiner;
215
216         return gl_mesh;
217 }
218
219 void openSubdiv_deleteOsdGLMesh(struct OpenSubdiv_GLMesh *gl_mesh)
220 {
221         switch (gl_mesh->evaluator_type) {
222 #define CHECK_EVALUATOR_TYPE(type, class) \
223                 case OPENSUBDIV_EVALUATOR_ ## type: \
224                         delete (class *) gl_mesh->descriptor; \
225                         break;
226
227                 CHECK_EVALUATOR_TYPE(CPU, OsdCpuMesh)
228
229 #ifdef OPENSUBDIV_HAS_OPENMP
230                 CHECK_EVALUATOR_TYPE(OPENMP, OsdOmpMesh)
231 #endif
232
233 #ifdef OPENSUBDIV_HAS_OPENCL
234                 CHECK_EVALUATOR_TYPE(OPENCL, OsdCLMesh)
235 #endif
236
237 #ifdef OPENSUBDIV_HAS_CUDA
238                 CHECK_EVALUATOR_TYPE(CUDA, OsdCudaMesh)
239 #endif
240
241 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
242                 CHECK_EVALUATOR_TYPE(GLSL_TRANSFORM_FEEDBACK,
243                                      OsdGLSLTransformFeedbackMesh)
244 #endif
245
246 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
247                 CHECK_EVALUATOR_TYPE(GLSL_COMPUTE, OsdGLSLComputeMesh)
248 #endif
249
250 #undef CHECK_EVALUATOR_TYPE
251         }
252
253         OBJECT_GUARDED_DELETE(gl_mesh, OpenSubdiv_GLMesh);
254 }
255
256 unsigned int openSubdiv_getOsdGLMeshPatchIndexBuffer(struct OpenSubdiv_GLMesh *gl_mesh)
257 {
258         return ((GLMeshInterface *)gl_mesh->descriptor)->GetPatchTable()->GetPatchIndexBuffer();
259 }
260
261 unsigned int openSubdiv_getOsdGLMeshVertexBuffer(struct OpenSubdiv_GLMesh *gl_mesh)
262 {
263         return ((GLMeshInterface *)gl_mesh->descriptor)->BindVertexBuffer();
264 }
265
266 void openSubdiv_osdGLMeshUpdateVertexBuffer(struct OpenSubdiv_GLMesh *gl_mesh,
267                                             const float *vertex_data,
268                                             int start_vertex,
269                                             int num_verts)
270 {
271         ((GLMeshInterface *)gl_mesh->descriptor)->UpdateVertexBuffer(vertex_data,
272                                                                      start_vertex,
273                                                                      num_verts);
274 }
275
276 void openSubdiv_osdGLMeshRefine(struct OpenSubdiv_GLMesh *gl_mesh)
277 {
278         ((GLMeshInterface *)gl_mesh->descriptor)->Refine();
279 }
280
281 void openSubdiv_osdGLMeshSynchronize(struct OpenSubdiv_GLMesh *gl_mesh)
282 {
283         ((GLMeshInterface *)gl_mesh->descriptor)->Synchronize();
284 }
285
286 void openSubdiv_osdGLMeshBindVertexBuffer(OpenSubdiv_GLMesh *gl_mesh)
287 {
288         ((GLMeshInterface *)gl_mesh->descriptor)->BindVertexBuffer();
289 }
290
291 const struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_getGLMeshTopologyRefiner(
292         OpenSubdiv_GLMesh *gl_mesh)
293 {
294         return gl_mesh->topology_refiner;
295 }
296
297 int openSubdiv_supportGPUDisplay(void)
298 {
299         return GLEW_EXT_geometry_shader4 &&
300                GLEW_ARB_gpu_shader5 &&
301                GLEW_ARB_uniform_buffer_object;
302 }