8b3f1446e73120473c9f0da3f026394849e655e8
[blender.git] / intern / opensubdiv / opensubdiv_gpu_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  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /* Do some compatibility hacks in order to make
27  * the code working with GPU_material pipeline.
28  */
29 #define GLSL_COMPAT_WORKAROUND
30
31 #include "opensubdiv_capi.h"
32
33 #ifdef _MSC_VER
34 #  include "iso646.h"
35 #endif
36
37 #include <cstdio>
38 #include <cmath>
39 #include <GL/glew.h>
40
41 #include <opensubdiv/osd/glMesh.h>
42
43 #ifdef OPENSUBDIV_HAS_CUDA
44 #  include <opensubdiv/osd/cudaGLVertexBuffer.h>
45 #endif  /* OPENSUBDIV_HAS_CUDA */
46
47 #include <opensubdiv/osd/cpuGLVertexBuffer.h>
48 #include <opensubdiv/osd/cpuEvaluator.h>
49
50 #include "opensubdiv_partitioned.h"
51
52 //using OpenSubdiv::FarPatchTables;
53 using OpenSubdiv::Osd::GLMeshInterface;
54 //sing OpenSubdiv::PartitionedGLMeshInterface;
55
56 extern "C" char datatoc_gpu_shader_opensubd_display_glsl[];
57
58 #define MAX_LIGHTS 8
59 typedef struct Light {
60         float position[4];
61         float ambient[4];
62         float diffuse[4];
63         float specular[4];
64         float spot_direction[4];
65         float constant_attenuation;
66         float linear_attenuation;
67         float quadratic_attenuation;
68         float spot_cutoff;
69         float spot_exponent;
70         float spot_cos_cutoff;
71         float pad[2];
72 } Light;
73
74 typedef struct Lighting {
75         Light lights[MAX_LIGHTS];
76         int num_enabled;
77         int pad[3];
78 } Lighting;
79
80 typedef struct Transform {
81         float projection_matrix[16];
82         float model_view_matrix[16];
83         float normal_matrix[9];
84 } Transform;
85
86 static bool g_use_osd_glsl = false;
87 static int g_active_uv_index = -1;
88
89 static GLuint g_flat_fill_program = 0;
90 static GLuint g_smooth_fill_program = 0;
91 static GLuint g_wireframe_program = 0;
92
93 static GLuint g_lighting_ub = 0;
94 static Lighting g_lighting_data;
95 static Transform g_transform;
96
97 /* TODO(sergey): This is actually duplicated code from BLI. */
98 namespace {
99 void copy_m3_m3(float m1[3][3], float m2[3][3])
100 {
101         /* destination comes first: */
102         memcpy(&m1[0], &m2[0], 9 * sizeof(float));
103 }
104
105 void copy_m3_m4(float m1[3][3], float m2[4][4])
106 {
107         m1[0][0] = m2[0][0];
108         m1[0][1] = m2[0][1];
109         m1[0][2] = m2[0][2];
110
111         m1[1][0] = m2[1][0];
112         m1[1][1] = m2[1][1];
113         m1[1][2] = m2[1][2];
114
115         m1[2][0] = m2[2][0];
116         m1[2][1] = m2[2][1];
117         m1[2][2] = m2[2][2];
118 }
119
120 void adjoint_m3_m3(float m1[3][3], float m[3][3])
121 {
122         m1[0][0] = m[1][1] * m[2][2] - m[1][2] * m[2][1];
123         m1[0][1] = -m[0][1] * m[2][2] + m[0][2] * m[2][1];
124         m1[0][2] = m[0][1] * m[1][2] - m[0][2] * m[1][1];
125
126         m1[1][0] = -m[1][0] * m[2][2] + m[1][2] * m[2][0];
127         m1[1][1] = m[0][0] * m[2][2] - m[0][2] * m[2][0];
128         m1[1][2] = -m[0][0] * m[1][2] + m[0][2] * m[1][0];
129
130         m1[2][0] = m[1][0] * m[2][1] - m[1][1] * m[2][0];
131         m1[2][1] = -m[0][0] * m[2][1] + m[0][1] * m[2][0];
132         m1[2][2] = m[0][0] * m[1][1] - m[0][1] * m[1][0];
133 }
134
135 float determinant_m3_array(float m[3][3])
136 {
137         return (m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) -
138                 m[1][0] * (m[0][1] * m[2][2] - m[0][2] * m[2][1]) +
139                 m[2][0] * (m[0][1] * m[1][2] - m[0][2] * m[1][1]));
140 }
141
142 bool invert_m3_m3(float m1[3][3], float m2[3][3])
143 {
144         float det;
145         int a, b;
146         bool success;
147
148         /* calc adjoint */
149         adjoint_m3_m3(m1, m2);
150
151         /* then determinant old matrix! */
152         det = determinant_m3_array(m2);
153
154         success = (det != 0.0f);
155
156         if (det != 0.0f) {
157                 det = 1.0f / det;
158                 for (a = 0; a < 3; a++) {
159                         for (b = 0; b < 3; b++) {
160                                 m1[a][b] *= det;
161                         }
162                 }
163         }
164
165         return success;
166 }
167
168 bool invert_m3(float m[3][3])
169 {
170         float tmp[3][3];
171         bool success;
172
173         success = invert_m3_m3(tmp, m);
174         copy_m3_m3(m, tmp);
175
176         return success;
177 }
178
179 void transpose_m3(float mat[3][3])
180 {
181         float t;
182
183         t = mat[0][1];
184         mat[0][1] = mat[1][0];
185         mat[1][0] = t;
186         t = mat[0][2];
187         mat[0][2] = mat[2][0];
188         mat[2][0] = t;
189         t = mat[1][2];
190         mat[1][2] = mat[2][1];
191         mat[2][1] = t;
192 }
193
194 GLuint compileShader(GLenum shaderType,
195                      const char *section,
196                      const char *define)
197 {
198         const char *sources[3];
199         char sdefine[64];
200         sprintf(sdefine, "#define %s\n#define GLSL_COMPAT_WORKAROUND\n", section);
201
202         sources[0] = define;
203         sources[1] = sdefine;
204         sources[2] = datatoc_gpu_shader_opensubd_display_glsl;
205
206         GLuint shader = glCreateShader(shaderType);
207         glShaderSource(shader, 3, sources, NULL);
208         glCompileShader(shader);
209
210         GLint status;
211         glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
212         if (status == GL_FALSE) {
213                 GLchar emsg[1024];
214                 glGetShaderInfoLog(shader, sizeof(emsg), 0, emsg);
215                 fprintf(stderr, "Error compiling GLSL shader (%s): %s\n", section, emsg);
216                 fprintf(stderr, "Section: %s\n", sdefine);
217                 fprintf(stderr, "Defines: %s\n", define);
218                 fprintf(stderr, "Source: %s\n", sources[2]);
219                 exit(1);
220         }
221
222         return shader;
223 }
224
225 GLuint linkProgram(const char *define)
226 {
227         GLuint vertexShader = compileShader(GL_VERTEX_SHADER,
228                                             "VERTEX_SHADER",
229                                             define);
230         GLuint geometryShader = compileShader(GL_GEOMETRY_SHADER,
231                                               "GEOMETRY_SHADER",
232                                               define);
233         GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER,
234                                               "FRAGMENT_SHADER",
235                                               define);
236
237         GLuint program = glCreateProgram();
238
239         glAttachShader(program, vertexShader);
240         glAttachShader(program, geometryShader);
241         glAttachShader(program, fragmentShader);
242
243         glBindAttribLocation(program, 0, "position");
244         glBindAttribLocation(program, 1, "normal");
245
246 #ifdef GLSL_COMPAT_WORKAROUND
247         glProgramParameteriEXT(program,
248                                GL_GEOMETRY_INPUT_TYPE_EXT,
249                                GL_LINES_ADJACENCY_EXT);
250
251         if (strstr(define, "WIREFRAME") == NULL) {
252                 glProgramParameteriEXT(program,
253                                        GL_GEOMETRY_OUTPUT_TYPE_EXT,
254                                        GL_TRIANGLE_STRIP);
255
256                 glProgramParameteriEXT(program,
257                                        GL_GEOMETRY_VERTICES_OUT_EXT,
258                                        4);
259         }
260         else {
261                 glProgramParameteriEXT(program,
262                                        GL_GEOMETRY_OUTPUT_TYPE_EXT,
263                                        GL_LINE_STRIP);
264
265                 glProgramParameteriEXT(program,
266                                        GL_GEOMETRY_VERTICES_OUT_EXT,
267                                        8);
268         }
269 #endif
270
271         glLinkProgram(program);
272
273         glDeleteShader(vertexShader);
274         glDeleteShader(geometryShader);
275         glDeleteShader(fragmentShader);
276
277         GLint status;
278         glGetProgramiv(program, GL_LINK_STATUS, &status);
279         if (status == GL_FALSE) {
280                 GLchar emsg[1024];
281                 glGetProgramInfoLog(program, sizeof(emsg), 0, emsg);
282                 fprintf(stderr, "Error linking GLSL program : %s\n", emsg);
283                 fprintf(stderr, "Defines: %s\n", define);
284                 exit(1);
285         }
286
287         glUniformBlockBinding(program,
288                               glGetUniformBlockIndex(program, "Lighting"),
289                               0);
290
291         glProgramUniform1i(program,
292                            glGetUniformLocation(program, "texture_buffer"),
293                            0);  /* GL_TEXTURE0 */
294
295         glProgramUniform1i(program,
296                            glGetUniformLocation(program, "FVarDataBuffer"),
297                            31);  /* GL_TEXTURE31 */
298
299         return program;
300 }
301
302 void bindProgram(PartitionedGLMeshInterface * /*mesh*/,
303                  int program)
304 {
305         glUseProgram(program);
306
307         /* Matricies */
308         glUniformMatrix4fv(glGetUniformLocation(program, "modelViewMatrix"),
309                            1, false,
310                            g_transform.model_view_matrix);
311         glUniformMatrix4fv(glGetUniformLocation(program, "projectionMatrix"),
312                            1, false,
313                            g_transform.projection_matrix);
314         glUniformMatrix3fv(glGetUniformLocation(program, "normalMatrix"),
315                            1, false,
316                            g_transform.normal_matrix);
317
318         /* Ligthing */
319         glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub);
320         glBufferSubData(GL_UNIFORM_BUFFER,
321                         0, sizeof(g_lighting_data), &g_lighting_data);
322         glBindBuffer(GL_UNIFORM_BUFFER, 0);
323
324         glBindBufferBase(GL_UNIFORM_BUFFER, 0, g_lighting_ub);
325
326         /* Color */
327         GLboolean use_lighting, use_color_material, use_texture_2d;
328         glGetBooleanv(GL_LIGHTING, &use_lighting);
329         glGetBooleanv(GL_COLOR_MATERIAL, &use_color_material);
330         glGetBooleanv(GL_TEXTURE_2D, &use_texture_2d);
331
332         glUniform1i(glGetUniformLocation(program, "use_color_material"),
333                     use_color_material);
334         glUniform1i(glGetUniformLocation(program, "use_texture_2d"),
335                     use_texture_2d);
336
337         if (use_lighting) {
338                 float color[4];
339                 glGetMaterialfv(GL_FRONT, GL_DIFFUSE, color);
340                 glUniform4fv(glGetUniformLocation(program, "diffuse"), 1, color);
341
342                 glGetMaterialfv(GL_FRONT, GL_SPECULAR, color);
343                 glUniform4fv(glGetUniformLocation(program, "specular"), 1, color);
344
345                 glGetMaterialfv(GL_FRONT, GL_SHININESS, color);
346                 glUniform1f(glGetUniformLocation(program, "shininess"), color[0]);
347         }
348         else {
349                 float color[4];
350                 glGetFloatv(GL_CURRENT_COLOR, color);
351                 glUniform4fv(glGetUniformLocation(program, "diffuse"), 1, color);
352         }
353
354         /* TODO(sergey): Bring face varying back. */
355 #if 0
356         /* Face-vertex data */
357         if (mesh->GetDrawContext()->GetFvarDataTextureBuffer()) {
358                 glActiveTexture(GL_TEXTURE31);
359                 glBindTexture(GL_TEXTURE_BUFFER,
360                               mesh->GetDrawContext()->GetFvarDataTextureBuffer());
361                 glActiveTexture(GL_TEXTURE0);
362         }
363 #endif
364
365         /* TODO(sergey): Bring face varying back. */
366         glUniform1i(glGetUniformLocation(program, "osd_fvar_count"),
367                     0/* * mesh->GetFVarCount()*/);
368
369         glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"),
370                     g_active_uv_index * 2);
371 }
372
373 }  /* namespace */
374
375 void openSubdiv_osdGLDisplayInit(void)
376 {
377         static bool need_init = true;
378         if (need_init) {
379                 g_flat_fill_program = linkProgram("#define FLAT_SHADING\n");
380                 g_smooth_fill_program = linkProgram("#define SMOOTH_SHADING\n");
381                 g_wireframe_program = linkProgram("#define WIREFRAME\n");
382
383                 glGenBuffers(1, &g_lighting_ub);
384                 glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub);
385                 glBufferData(GL_UNIFORM_BUFFER,
386                              sizeof(g_lighting_data), NULL, GL_STATIC_DRAW);
387
388                 need_init = false;
389         }
390 }
391
392 void openSubdiv_osdGLDisplayDeinit(void)
393 {
394         if (g_lighting_ub != 0) {
395                 glDeleteBuffers(1, &g_lighting_ub);
396         }
397         if (g_flat_fill_program) {
398                 glDeleteProgram(g_flat_fill_program);
399         }
400         if (g_smooth_fill_program) {
401                 glDeleteProgram(g_flat_fill_program);
402         }
403         if (g_wireframe_program) {
404                 glDeleteProgram(g_wireframe_program);
405         }
406 }
407
408 void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl,
409                                         int active_uv_index)
410 {
411         g_use_osd_glsl = use_osd_glsl != 0;
412         g_active_uv_index = active_uv_index;
413
414         /* Update transformation matricies. */
415         glGetFloatv(GL_PROJECTION_MATRIX, g_transform.projection_matrix);
416         glGetFloatv(GL_MODELVIEW_MATRIX, g_transform.model_view_matrix);
417
418         copy_m3_m4((float (*)[3])g_transform.normal_matrix,
419                    (float (*)[4])g_transform.model_view_matrix);
420         invert_m3((float (*)[3])g_transform.normal_matrix);
421         transpose_m3((float (*)[3])g_transform.normal_matrix);
422
423         /* Update OpenGL lights positions, colors etc. */
424         g_lighting_data.num_enabled = 0;
425         for (int i = 0; i < MAX_LIGHTS; ++i) {
426                 GLboolean enabled;
427                 glGetBooleanv(GL_LIGHT0 + i, &enabled);
428                 if (enabled) {
429                         g_lighting_data.num_enabled++;
430                 }
431
432                 glGetLightfv(GL_LIGHT0 + i,
433                              GL_POSITION,
434                              g_lighting_data.lights[i].position);
435                 glGetLightfv(GL_LIGHT0 + i,
436                              GL_AMBIENT,
437                              g_lighting_data.lights[i].ambient);
438                 glGetLightfv(GL_LIGHT0 + i,
439                              GL_DIFFUSE,
440                              g_lighting_data.lights[i].diffuse);
441                 glGetLightfv(GL_LIGHT0 + i,
442                              GL_SPECULAR,
443                              g_lighting_data.lights[i].specular);
444                 glGetLightfv(GL_LIGHT0 + i,
445                              GL_SPOT_DIRECTION,
446                              g_lighting_data.lights[i].spot_direction);
447                 glGetLightfv(GL_LIGHT0 + i,
448                              GL_CONSTANT_ATTENUATION,
449                              &g_lighting_data.lights[i].constant_attenuation);
450                 glGetLightfv(GL_LIGHT0 + i,
451                              GL_LINEAR_ATTENUATION,
452                              &g_lighting_data.lights[i].linear_attenuation);
453                 glGetLightfv(GL_LIGHT0 + i,
454                              GL_QUADRATIC_ATTENUATION,
455                              &g_lighting_data.lights[i].quadratic_attenuation);
456                 glGetLightfv(GL_LIGHT0 + i,
457                              GL_SPOT_CUTOFF,
458                              &g_lighting_data.lights[i].spot_cutoff);
459                 glGetLightfv(GL_LIGHT0 + i,
460                              GL_SPOT_EXPONENT,
461                              &g_lighting_data.lights[i].spot_exponent);
462                 g_lighting_data.lights[i].spot_cos_cutoff =
463                         cos(g_lighting_data.lights[i].spot_cutoff);
464         }
465 }
466
467 static GLuint preapre_patchDraw(PartitionedGLMeshInterface *mesh,
468                                 bool fill_quads)
469 {
470         GLint program = 0;
471         if (!g_use_osd_glsl) {
472                 glGetIntegerv(GL_CURRENT_PROGRAM, &program);
473                 if (program) {
474                         GLint model;
475                         glGetIntegerv(GL_SHADE_MODEL, &model);
476
477                         GLint location = glGetUniformLocation(program, "osd_flat_shading");
478                         if (location != -1) {
479                                 glUniform1i(location, model == GL_FLAT);
480                         }
481
482                         /* TODO(sergey): Bring this back. */
483 #if 0
484                         /* Face-vertex data */
485                         if (mesh->GetDrawContext()->GetFvarDataTextureBuffer()) {
486                                 glActiveTexture(GL_TEXTURE31);
487                                 glBindTexture(GL_TEXTURE_BUFFER,
488                                               mesh->GetDrawContext()->GetFvarDataTextureBuffer());
489                                 glActiveTexture(GL_TEXTURE0);
490
491                                 GLint location = glGetUniformLocation(program, "osd_fvar_count");
492                                 if (location != -1) {
493                                         glUniform1i(location, mesh->GetFVarCount());
494                                 }
495
496                                 location = glGetUniformLocation(program, "osd_active_uv_offset");
497                                 if (location != -1) {
498                                         glUniform1i(location,
499                                                     g_active_uv_index * 2);
500                                 }
501                         }
502 #endif
503
504                 }
505                 return program;
506         }
507
508         program = g_smooth_fill_program;
509         if (fill_quads) {
510                 int model;
511                 glGetIntegerv(GL_SHADE_MODEL, &model);
512                 if (model == GL_FLAT) {
513                         program = g_flat_fill_program;
514                 }
515         }
516         else {
517                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
518                 program = g_wireframe_program;
519         }
520
521         bindProgram(mesh, program);
522
523         return program;
524 }
525
526 static void perform_drawElements(GLuint program,
527                                  int patch_index,
528                                  int num_elements,
529                                  int start_element)
530 {
531         int mode = GL_QUADS;
532         if (program) {
533                 glUniform1i(glGetUniformLocation(program, "PrimitiveIdBase"),
534                             patch_index);
535         }
536         mode = GL_LINES_ADJACENCY;
537         glDrawElements(mode,
538                        num_elements,
539                        GL_UNSIGNED_INT,
540                        (void *)(start_element * sizeof(unsigned int)));
541 }
542
543 static void finish_patchDraw(bool fill_quads)
544 {
545         /* TODO(sergey): Some of the stuff could be done once after the whole
546          * mesh is displayed.
547          */
548
549         /* Restore state. */
550         if (!fill_quads) {
551                 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
552         }
553         glBindVertexArray(0);
554
555         if (g_use_osd_glsl) {
556                 /* TODO(sergey): Store previously used program and roll back to it? */
557                 glUseProgram(0);
558         }
559 }
560
561 static void draw_partition_patches_range(PartitionedGLMeshInterface *mesh,
562                                          GLuint program,
563                                          int start_partition,
564                                          int num_partitions)
565 {
566 #if 0
567         /* Glue patches from all partitions in the range together. */
568         int patch_index = -1, start_element = -1, num_elements = 0;
569         for (int partition = start_partition;
570              partition < start_partition + num_partitions;
571              ++partition)
572         {
573                 OsdDrawContext::PatchArrayVector const &patches =
574                         mesh->GetPatchArrays(partition);
575                 for (int i = 0; i < (int)patches.size(); ++i) {
576                         OsdDrawContext::PatchArray const &patch = patches[i];
577                         OsdDrawContext::PatchDescriptor desc = patch.GetDescriptor();
578                         OpenSubdiv::FarPatchTables::Type patchType = desc.GetType();
579                         if (patchType == OpenSubdiv::FarPatchTables::QUADS) {
580                                 if (start_element == -1) {
581                                         patch_index = patch.GetPatchIndex();
582                                         start_element = patch.GetVertIndex();
583                                 }
584
585                                 assert(patch.GetVertIndex() == start_element + num_elements);
586                                 num_elements += patch.GetNumIndices();
587                         }
588                         else {
589                                 assert(!"Discontinuitied are not supported yet.");
590                         }
591                 }
592         }
593
594         /* Perform actual draw. */
595         perform_drawElements(program,
596                              patch_index,
597                              num_elements,
598                              start_element);
599 #else
600         (void)mesh;
601         (void)program;
602         (void)start_partition;
603         (void)num_partitions;
604 #endif
605 }
606
607 static void draw_all_patches(PartitionedGLMeshInterface *mesh,
608                              GLuint program)
609 {
610         const OpenSubdiv::Osd::PatchArrayVector& patches =
611                 mesh->GetPatchTable()->GetPatchArrays();
612         for (int i = 0; i < (int)patches.size(); ++i) {
613                 const OpenSubdiv::Osd::PatchArray& patch = patches[i];
614                 OpenSubdiv::Far::PatchDescriptor desc = patch.GetDescriptor();
615                 OpenSubdiv::Far::PatchDescriptor::Type patchType = desc.GetType();
616
617                 if (patchType == OpenSubdiv::Far::PatchDescriptor::QUADS) {
618                         perform_drawElements(program,
619                                              i,
620                                              patch.GetNumPatches() * desc.GetNumControlVertices(),
621                                              patch.GetIndexBase());
622                 }
623     }
624 }
625
626 void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
627                                  int fill_quads,
628                                  int start_partition,
629                                  int num_partitions)
630 {
631         PartitionedGLMeshInterface *mesh =
632                 (PartitionedGLMeshInterface *)(gl_mesh->descriptor);
633
634         /* Make sure all global invariants are initialized. */
635         openSubdiv_osdGLDisplayInit();
636
637         /* Setup GLSL/OpenGL to draw patches in current context. */
638         GLuint program = preapre_patchDraw(mesh, fill_quads != 0);
639
640         if (start_partition != -1) {
641 #if 0
642                 draw_partition_patches_range(mesh,
643                                              program,
644                                              start_partition,
645                                              num_partitions);
646 #else
647                 (void)num_partitions;
648                 if(start_partition == 0) {
649                         draw_all_patches(mesh, program);
650                 }
651 #endif
652         }
653         else {
654                 draw_all_patches(mesh, program);
655         }
656
657         /* Finish patch drawing by restoring all changes to the OpenGL context. */
658         finish_patchDraw(fill_quads != 0);
659 }