dbd93a0a5e9996fbc4cae246c70537793904c2e7
[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
73 #include "MEM_guardedalloc.h"
74
75 /* **************** Types declaration **************** */
76
77 using OpenSubdiv::Osd::GLMeshInterface;
78 using OpenSubdiv::Osd::Mesh;
79 using OpenSubdiv::Osd::MeshBitset;
80 using OpenSubdiv::Far::StencilTable;
81 using OpenSubdiv::Osd::GLPatchTable;
82
83 using OpenSubdiv::Osd::Mesh;
84
85 /* CPU backend */
86 using OpenSubdiv::Osd::CpuGLVertexBuffer;
87 using OpenSubdiv::Osd::CpuEvaluator;
88 typedef Mesh<CpuGLVertexBuffer,
89              StencilTable,
90              CpuEvaluator,
91              GLPatchTable> OsdCpuMesh;
92
93 #ifdef OPENSUBDIV_HAS_OPENMP
94 using OpenSubdiv::Osd::OmpEvaluator;
95 typedef Mesh<CpuGLVertexBuffer,
96              StencilTable,
97              OmpEvaluator,
98              GLPatchTable> OsdOmpMesh;
99 #endif  /* OPENSUBDIV_HAS_OPENMP */
100
101 #ifdef OPENSUBDIV_HAS_OPENCL
102 using OpenSubdiv::Osd::CLEvaluator;
103 using OpenSubdiv::Osd::CLGLVertexBuffer;
104 using OpenSubdiv::Osd::CLStencilTable;
105 /* TODO(sergey): Use CLDeviceCOntext similar to OSD examples? */
106 typedef Mesh<CLGLVertexBuffer,
107              CLStencilTable,
108              CLEvaluator,
109              GLPatchTable,
110              CLDeviceContext> OsdCLMesh;
111 static CLDeviceContext g_clDeviceContext;
112 #endif  /* OPENSUBDIV_HAS_OPENCL */
113
114 #ifdef OPENSUBDIV_HAS_CUDA
115 using OpenSubdiv::Osd::CudaEvaluator;
116 using OpenSubdiv::Osd::CudaGLVertexBuffer;
117 using OpenSubdiv::Osd::CudaStencilTable;
118 typedef Mesh<CudaGLVertexBuffer,
119              CudaStencilTable,
120              CudaEvaluator,
121              GLPatchTable> OsdCudaMesh;
122 static CudaDeviceContext g_cudaDeviceContext;
123 #endif  /* OPENSUBDIV_HAS_CUDA */
124
125 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
126 using OpenSubdiv::Osd::GLXFBEvaluator;
127 using OpenSubdiv::Osd::GLStencilTableTBO;
128 using OpenSubdiv::Osd::GLVertexBuffer;
129 typedef Mesh<GLVertexBuffer,
130              GLStencilTableTBO,
131              GLXFBEvaluator,
132              GLPatchTable> OsdGLSLTransformFeedbackMesh;
133 #endif  /* OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK */
134
135 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
136 using OpenSubdiv::Osd::GLComputeEvaluator;
137 using OpenSubdiv::Osd::GLStencilTableSSBO;
138 using OpenSubdiv::Osd::GLVertexBuffer;
139 typedef Mesh<GLVertexBuffer,
140              GLStencilTableSSBO,
141              GLComputeEvaluator,
142              GLPatchTable> OsdGLSLComputeMesh;
143 #endif
144
145 struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
146         OpenSubdiv_TopologyRefinerDescr *topology_refiner,
147         int evaluator_type,
148         int level,
149         int /*subdivide_uvs*/)
150 {
151         using OpenSubdiv::Far::TopologyRefiner;
152
153         MeshBitset bits;
154         /* TODO(sergey): Adaptive subdivisions are not currently
155          * possible because of the lack of tessellation shader.
156          */
157         bits.set(OpenSubdiv::Osd::MeshAdaptive, 0);
158         bits.set(OpenSubdiv::Osd::MeshUseSingleCreasePatch, 0);
159         bits.set(OpenSubdiv::Osd::MeshInterleaveVarying, 1);
160         bits.set(OpenSubdiv::Osd::MeshFVarData, 1);
161         bits.set(OpenSubdiv::Osd::MeshEndCapBSplineBasis, 1);
162
163         const int num_vertex_elements = 3;
164         const int num_varying_elements = 3;
165
166         GLMeshInterface *mesh = NULL;
167         TopologyRefiner *refiner = (TopologyRefiner*)topology_refiner;
168
169         switch(evaluator_type) {
170 #define CHECK_EVALUATOR_TYPE(type, class) \
171                 case OPENSUBDIV_EVALUATOR_ ## type: \
172                         mesh = new class(refiner, \
173                                          num_vertex_elements, \
174                                          num_varying_elements, \
175                                          level, \
176                                          bits); \
177                         break;
178
179                 CHECK_EVALUATOR_TYPE(CPU, OsdCpuMesh)
180
181 #ifdef OPENSUBDIV_HAS_OPENMP
182                 CHECK_EVALUATOR_TYPE(OPENMP, OsdOmpMesh)
183 #endif
184
185 #ifdef OPENSUBDIV_HAS_OPENCL
186                 CHECK_EVALUATOR_TYPE(OPENCL, OsdCLMesh)
187 #endif
188
189 #ifdef OPENSUBDIV_HAS_CUDA
190                 CHECK_EVALUATOR_TYPE(CUDA, OsdCudaMesh)
191 #endif
192
193 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
194                 CHECK_EVALUATOR_TYPE(GLSL_TRANSFORM_FEEDBACK,
195                                      OsdGLSLTransformFeedbackMesh)
196 #endif
197
198 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
199                 CHECK_EVALUATOR_TYPE(GLSL_COMPUTE, OsdGLSLComputeMesh)
200 #endif
201
202 #undef CHECK_EVALUATOR_TYPE
203         }
204
205         if (mesh == NULL) {
206                 return NULL;
207         }
208
209         OpenSubdiv_GLMesh *gl_mesh =
210                 (OpenSubdiv_GLMesh *) OBJECT_GUARDED_NEW(OpenSubdiv_GLMesh);
211         gl_mesh->evaluator_type = evaluator_type;
212         gl_mesh->descriptor = (OpenSubdiv_GLMeshDescr *) mesh;
213         gl_mesh->topology_refiner = (OpenSubdiv_TopologyRefinerDescr*)refiner;
214
215         return gl_mesh;
216 }
217
218 void openSubdiv_deleteOsdGLMesh(struct OpenSubdiv_GLMesh *gl_mesh)
219 {
220         switch (gl_mesh->evaluator_type) {
221 #define CHECK_EVALUATOR_TYPE(type, class) \
222                 case OPENSUBDIV_EVALUATOR_ ## type: \
223                         delete (class *) gl_mesh->descriptor; \
224                         break;
225
226                 CHECK_EVALUATOR_TYPE(CPU, OsdCpuMesh)
227
228 #ifdef OPENSUBDIV_HAS_OPENMP
229                 CHECK_EVALUATOR_TYPE(OPENMP, OsdOmpMesh)
230 #endif
231
232 #ifdef OPENSUBDIV_HAS_OPENCL
233                 CHECK_EVALUATOR_TYPE(OPENCL, OsdCLMesh)
234 #endif
235
236 #ifdef OPENSUBDIV_HAS_CUDA
237                 CHECK_EVALUATOR_TYPE(CUDA, OsdCudaMesh)
238 #endif
239
240 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
241                 CHECK_EVALUATOR_TYPE(GLSL_TRANSFORM_FEEDBACK,
242                                      OsdGLSLTransformFeedbackMesh)
243 #endif
244
245 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
246                 CHECK_EVALUATOR_TYPE(GLSL_COMPUTE, OsdGLSLComputeMesh)
247 #endif
248
249 #undef CHECK_EVALUATOR_TYPE
250         }
251
252         OBJECT_GUARDED_DELETE(gl_mesh, OpenSubdiv_GLMesh);
253 }
254
255 unsigned int openSubdiv_getOsdGLMeshPatchIndexBuffer(struct OpenSubdiv_GLMesh *gl_mesh)
256 {
257         return ((GLMeshInterface *)gl_mesh->descriptor)->GetPatchTable()->GetPatchIndexBuffer();
258 }
259
260 unsigned int openSubdiv_getOsdGLMeshVertexBuffer(struct OpenSubdiv_GLMesh *gl_mesh)
261 {
262         return ((GLMeshInterface *)gl_mesh->descriptor)->BindVertexBuffer();
263 }
264
265 void openSubdiv_osdGLMeshUpdateVertexBuffer(struct OpenSubdiv_GLMesh *gl_mesh,
266                                             const float *vertex_data,
267                                             int start_vertex,
268                                             int num_verts)
269 {
270         ((GLMeshInterface *)gl_mesh->descriptor)->UpdateVertexBuffer(vertex_data,
271                                                                      start_vertex,
272                                                                      num_verts);
273 }
274
275 void openSubdiv_osdGLMeshRefine(struct OpenSubdiv_GLMesh *gl_mesh)
276 {
277         ((GLMeshInterface *)gl_mesh->descriptor)->Refine();
278 }
279
280 void openSubdiv_osdGLMeshSynchronize(struct OpenSubdiv_GLMesh *gl_mesh)
281 {
282         ((GLMeshInterface *)gl_mesh->descriptor)->Synchronize();
283 }
284
285 void openSubdiv_osdGLMeshBindVertexBuffer(OpenSubdiv_GLMesh *gl_mesh)
286 {
287         ((GLMeshInterface *)gl_mesh->descriptor)->BindVertexBuffer();
288 }
289
290 const struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_getGLMeshTopologyRefiner(
291         OpenSubdiv_GLMesh *gl_mesh)
292 {
293         return gl_mesh->topology_refiner;
294 }
295
296 int openSubdiv_supportGPUDisplay(void)
297 {
298         {
299                 /* Currently Intel GPUs has hard time working on Windows.
300                  *
301                  * For until we've got access to a hardware which demonstrates
302                  * the issue we disable OpenSubdiv on Intel GPUs.
303                  */
304                 static bool vendor_checked = false;
305                 static bool is_intel = false;
306                 if (!vendor_checked) {
307                         const char *vendor = (const char *)glGetString(GL_VENDOR);
308                         const char *renderer = (const char *)glGetString(GL_RENDERER);
309                         if (strstr(vendor, "Intel")) {
310                                 if(getenv("OPENSUBDIV_ALLOW_INTEL") == NULL) {
311                                         is_intel = true;
312                                 }
313                         }
314                 }
315                 if (is_intel) {
316                         return false;
317                 }
318         }
319
320         return GLEW_EXT_geometry_shader4 &&
321                GLEW_ARB_gpu_shader5 &&
322                GLEW_ARB_uniform_buffer_object;
323 }