0463982fdf6ce1d28dd52afa376d0485d81ca529
[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 <stdlib.h>
34 #include <GL/glew.h>
35
36 #include <opensubdiv/osd/glMesh.h>
37
38 /* CPU Backend */
39 #include <opensubdiv/osd/cpuGLVertexBuffer.h>
40 #include <opensubdiv/osd/cpuEvaluator.h>
41
42 #ifdef OPENSUBDIV_HAS_OPENMP
43 #  include <opensubdiv/osd/ompEvaluator.h>
44 #endif  /* OPENSUBDIV_HAS_OPENMP */
45
46 #ifdef OPENSUBDIV_HAS_OPENCL
47 #  include <opensubdiv/osd/clGLVertexBuffer.h>
48 #  include <opensubdiv/osd/clEvaluator.h>
49 #  include "opensubdiv_device_context_opencl.h"
50 #endif  /* OPENSUBDIV_HAS_OPENCL */
51
52 #ifdef OPENSUBDIV_HAS_CUDA
53 #  include <opensubdiv/osd/cudaGLVertexBuffer.h>
54 #  include <opensubdiv/osd/cudaEvaluator.h>
55 #  include "opensubdiv_device_context_cuda.h"
56 #endif  /* OPENSUBDIV_HAS_CUDA */
57
58 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
59 #  include <opensubdiv/osd/glXFBEvaluator.h>
60 #  include <opensubdiv/osd/glVertexBuffer.h>
61 #endif  /* OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK */
62
63 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
64 #  include <opensubdiv/osd/glComputeEvaluator.h>
65 #  include <opensubdiv/osd/glVertexBuffer.h>
66 #endif  /* OPENSUBDIV_HAS_GLSL_COMPUTE */
67
68 #include <opensubdiv/osd/glPatchTable.h>
69 #include <opensubdiv/far/stencilTable.h>
70
71 #include "opensubdiv_intern.h"
72 #include "opensubdiv_topology_refiner.h"
73
74 #include "MEM_guardedalloc.h"
75
76 /* **************** Types declaration **************** */
77
78 using OpenSubdiv::Osd::GLMeshInterface;
79 using OpenSubdiv::Osd::Mesh;
80 using OpenSubdiv::Osd::MeshBitset;
81 using OpenSubdiv::Far::StencilTable;
82 using OpenSubdiv::Osd::GLPatchTable;
83
84 using OpenSubdiv::Osd::Mesh;
85
86 /* CPU backend */
87 using OpenSubdiv::Osd::CpuGLVertexBuffer;
88 using OpenSubdiv::Osd::CpuEvaluator;
89 typedef Mesh<CpuGLVertexBuffer,
90              StencilTable,
91              CpuEvaluator,
92              GLPatchTable> OsdCpuMesh;
93
94 #ifdef OPENSUBDIV_HAS_OPENMP
95 using OpenSubdiv::Osd::OmpEvaluator;
96 typedef Mesh<CpuGLVertexBuffer,
97              StencilTable,
98              OmpEvaluator,
99              GLPatchTable> OsdOmpMesh;
100 #endif  /* OPENSUBDIV_HAS_OPENMP */
101
102 #ifdef OPENSUBDIV_HAS_OPENCL
103 using OpenSubdiv::Osd::CLEvaluator;
104 using OpenSubdiv::Osd::CLGLVertexBuffer;
105 using OpenSubdiv::Osd::CLStencilTable;
106 /* TODO(sergey): Use CLDeviceCOntext similar to OSD examples? */
107 typedef Mesh<CLGLVertexBuffer,
108              CLStencilTable,
109              CLEvaluator,
110              GLPatchTable,
111              CLDeviceContext> OsdCLMesh;
112 static CLDeviceContext g_clDeviceContext;
113 #endif  /* OPENSUBDIV_HAS_OPENCL */
114
115 #ifdef OPENSUBDIV_HAS_CUDA
116 using OpenSubdiv::Osd::CudaEvaluator;
117 using OpenSubdiv::Osd::CudaGLVertexBuffer;
118 using OpenSubdiv::Osd::CudaStencilTable;
119 typedef Mesh<CudaGLVertexBuffer,
120              CudaStencilTable,
121              CudaEvaluator,
122              GLPatchTable> OsdCudaMesh;
123 static CudaDeviceContext g_cudaDeviceContext;
124 #endif  /* OPENSUBDIV_HAS_CUDA */
125
126 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
127 using OpenSubdiv::Osd::GLXFBEvaluator;
128 using OpenSubdiv::Osd::GLStencilTableTBO;
129 using OpenSubdiv::Osd::GLVertexBuffer;
130 typedef Mesh<GLVertexBuffer,
131              GLStencilTableTBO,
132              GLXFBEvaluator,
133              GLPatchTable> OsdGLSLTransformFeedbackMesh;
134 #endif  /* OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK */
135
136 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
137 using OpenSubdiv::Osd::GLComputeEvaluator;
138 using OpenSubdiv::Osd::GLStencilTableSSBO;
139 using OpenSubdiv::Osd::GLVertexBuffer;
140 typedef Mesh<GLVertexBuffer,
141              GLStencilTableSSBO,
142              GLComputeEvaluator,
143              GLPatchTable> OsdGLSLComputeMesh;
144 #endif
145
146 struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
147         OpenSubdiv_TopologyRefinerDescr *topology_refiner,
148         int evaluator_type,
149         int level,
150         int /*subdivide_uvs*/)
151 {
152         using OpenSubdiv::Far::TopologyRefiner;
153
154         MeshBitset bits;
155         /* TODO(sergey): Adaptive subdivisions are not currently
156          * possible because of the lack of tessellation shader.
157          */
158         bits.set(OpenSubdiv::Osd::MeshAdaptive, 0);
159         bits.set(OpenSubdiv::Osd::MeshUseSingleCreasePatch, 0);
160         bits.set(OpenSubdiv::Osd::MeshInterleaveVarying, 1);
161         bits.set(OpenSubdiv::Osd::MeshFVarData, 1);
162         bits.set(OpenSubdiv::Osd::MeshEndCapBSplineBasis, 1);
163
164         const int num_vertex_elements = 3;
165         const int num_varying_elements = 3;
166
167         GLMeshInterface *mesh = NULL;
168         TopologyRefiner *refiner = topology_refiner->osd_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 = topology_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         /* NOTE: OSD refiner was owned by gl_mesh, no need to free it here. */
254         OBJECT_GUARDED_DELETE(gl_mesh->topology_refiner, OpenSubdiv_TopologyRefinerDescr);
255         OBJECT_GUARDED_DELETE(gl_mesh, OpenSubdiv_GLMesh);
256 }
257
258 unsigned int openSubdiv_getOsdGLMeshPatchIndexBuffer(struct OpenSubdiv_GLMesh *gl_mesh)
259 {
260         return ((GLMeshInterface *)gl_mesh->descriptor)->GetPatchTable()->GetPatchIndexBuffer();
261 }
262
263 unsigned int openSubdiv_getOsdGLMeshVertexBuffer(struct OpenSubdiv_GLMesh *gl_mesh)
264 {
265         return ((GLMeshInterface *)gl_mesh->descriptor)->BindVertexBuffer();
266 }
267
268 void openSubdiv_osdGLMeshUpdateVertexBuffer(struct OpenSubdiv_GLMesh *gl_mesh,
269                                             const float *vertex_data,
270                                             int start_vertex,
271                                             int num_verts)
272 {
273         ((GLMeshInterface *)gl_mesh->descriptor)->UpdateVertexBuffer(vertex_data,
274                                                                      start_vertex,
275                                                                      num_verts);
276 }
277
278 void openSubdiv_osdGLMeshRefine(struct OpenSubdiv_GLMesh *gl_mesh)
279 {
280         ((GLMeshInterface *)gl_mesh->descriptor)->Refine();
281 }
282
283 void openSubdiv_osdGLMeshSynchronize(struct OpenSubdiv_GLMesh *gl_mesh)
284 {
285         ((GLMeshInterface *)gl_mesh->descriptor)->Synchronize();
286 }
287
288 void openSubdiv_osdGLMeshBindVertexBuffer(OpenSubdiv_GLMesh *gl_mesh)
289 {
290         ((GLMeshInterface *)gl_mesh->descriptor)->BindVertexBuffer();
291 }
292
293 const struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_getGLMeshTopologyRefiner(
294         OpenSubdiv_GLMesh *gl_mesh)
295 {
296         return gl_mesh->topology_refiner;
297 }
298
299 int openSubdiv_supportGPUDisplay(void)
300 {
301         // TODO: simplify extension check once Blender adopts GL 3.2
302         return openSubdiv_gpu_legacy_support() &&
303                (GLEW_VERSION_3_2 ||
304                (GLEW_VERSION_3_1 && GLEW_EXT_geometry_shader4) ||
305                (GLEW_VERSION_3_0 && GLEW_EXT_geometry_shader4 && GLEW_ARB_uniform_buffer_object && (GLEW_ARB_texture_buffer_object || GLEW_EXT_texture_buffer_object)));
306         /* also ARB_explicit_attrib_location? */
307 }