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