build: Start moving to a non-recursive layout
[profile/ivi/clutter.git] / clutter / cogl / cogl / driver / gles / cogl-gles2-wrapper.c
1 /*
2  * Cogl
3  *
4  * An object oriented GL/GLES Abstraction/Utility Layer
5  *
6  * Copyright (C) 2008,2009 Intel Corporation.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20  *
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <string.h>
29 #include <math.h>
30
31 /* We don't want to get the remaps from the gl* functions to the
32    cogl_wrap_gl* functions in this file because we need to be able to
33    call the base version */
34 #define COGL_GLES2_WRAPPER_NO_REMAP 1
35
36 #include "cogl.h"
37 #include "cogl-gles2-wrapper.h"
38 #include "cogl-fixed-vertex-shader.h"
39 #include "cogl-fixed-fragment-shader.h"
40 #include "cogl-context.h"
41 #include "cogl-shader-private.h"
42 #include "cogl-program.h"
43 #include "cogl-internal.h"
44
45 #define _COGL_GET_GLES2_WRAPPER(wvar, retval)                   \
46   CoglGles2Wrapper *wvar;                                       \
47   {                                                             \
48     CoglContext *__ctxvar = _cogl_context_get_default ();       \
49     if (__ctxvar == NULL) return retval;                        \
50     wvar = &__ctxvar->drv.gles2;                                \
51   }
52
53 #define _COGL_GLES2_CHANGE_SETTING(w, var, val) \
54   do                                            \
55     if ((w)->settings.var != (val))             \
56       {                                         \
57         (w)->settings.var = (val);              \
58         (w)->settings_dirty = TRUE;             \
59       }                                         \
60   while (0)
61
62 #define _COGL_GLES2_CHANGE_UNIFORM(w, flag, var, val)           \
63   do                                                            \
64     if ((w)->var != (val))                                      \
65       {                                                         \
66         (w)->var = (val);                                       \
67         (w)->dirty_uniforms |= COGL_GLES2_DIRTY_ ## flag;       \
68       }                                                         \
69   while (0)
70
71 #define COGL_GLES2_WRAPPER_VERTEX_ATTRIB    0
72 #define COGL_GLES2_WRAPPER_COLOR_ATTRIB     1
73 #define COGL_GLES2_WRAPPER_NORMAL_ATTRIB    2
74
75
76 static GLuint
77 cogl_gles2_wrapper_create_shader (GLenum type, const char *source)
78 {
79   GLuint shader;
80   GLint source_len = strlen (source);
81   GLint status;
82
83   shader = glCreateShader (type);
84   glShaderSource (shader, 1, &source, &source_len);
85   glCompileShader (shader);
86
87   glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
88
89   if (!status)
90     {
91       char shader_log[1024];
92       GLint len;
93
94       glGetShaderInfoLog (shader, sizeof (shader_log) - 1, &len, shader_log);
95       shader_log[len] = '\0';
96
97       g_critical ("%s", shader_log);
98
99       glDeleteShader (shader);
100
101       return 0;
102     }
103
104   return shader;
105 }
106
107 static void
108 initialize_texture_units (CoglGles2Wrapper *w)
109 {
110   /* We save the active texture unit since we may need to temporarily
111    * change this to initialise each new texture unit and we want to
112    * restore the active unit afterwards */
113   int initial_active_unit = w->active_texture_unit;
114   GLint prev_mode;
115   int i;
116
117   /* We will need to set the matrix mode to GL_TEXTURE to
118    * initialise any new texture units, so we save the current
119    * mode for restoring afterwards */
120   GE( _cogl_wrap_glGetIntegerv (GL_MATRIX_MODE, &prev_mode));
121
122   for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
123     {
124       CoglGles2WrapperTextureUnit *new_unit;
125
126       new_unit = w->texture_units + i;
127       memset (new_unit, 0, sizeof (CoglGles2WrapperTextureUnit));
128
129       w->active_texture_unit = i;
130       GE( _cogl_wrap_glMatrixMode (GL_TEXTURE));
131       GE( _cogl_wrap_glLoadIdentity ());
132
133       /* The real GL default is GL_MODULATE but the shader only
134          supports GL_COMBINE so let's default to that instead */
135       GE( _cogl_wrap_glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
136                                 GL_COMBINE) );
137       GE( _cogl_wrap_glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB,
138                                 GL_MODULATE) );
139       GE( _cogl_wrap_glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB,
140                                 GL_PREVIOUS) );
141       GE( _cogl_wrap_glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB,
142                                 GL_TEXTURE) );
143       GE( _cogl_wrap_glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB,
144                                 GL_SRC_COLOR) );
145       GE( _cogl_wrap_glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB,
146                                 GL_SRC_COLOR) );
147       GE( _cogl_wrap_glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA,
148                                 GL_MODULATE) );
149       GE( _cogl_wrap_glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA,
150                                 GL_PREVIOUS) );
151       GE( _cogl_wrap_glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA,
152                                 GL_TEXTURE) );
153       GE( _cogl_wrap_glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA,
154                                 GL_SRC_COLOR) );
155       GE( _cogl_wrap_glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA,
156                                 GL_SRC_COLOR) );
157
158       GE( _cogl_wrap_glTexEnvi (GL_POINT_SPRITE, GL_COORD_REPLACE,
159                                 GL_FALSE) );
160     }
161
162   GE( _cogl_wrap_glMatrixMode ((GLenum) prev_mode));
163
164   w->settings.texture_units = 0;
165
166   w->active_texture_unit = initial_active_unit;
167 }
168
169 void
170 _cogl_gles2_wrapper_init (CoglGles2Wrapper *wrapper)
171 {
172   GLfloat default_fog_color[4] = { 0, 0, 0, 0 };
173
174   memset (wrapper, 0, sizeof (CoglGles2Wrapper));
175
176   /* Initialize the stacks */
177   _cogl_wrap_glMatrixMode (GL_PROJECTION);
178   _cogl_wrap_glLoadIdentity ();
179   _cogl_wrap_glMatrixMode (GL_MODELVIEW);
180   _cogl_wrap_glLoadIdentity ();
181
182   /* The gl*ActiveTexture wrappers will initialise the texture
183    * stack for the texture unit when it's first activated */
184   _cogl_wrap_glActiveTexture (GL_TEXTURE0);
185   _cogl_wrap_glClientActiveTexture (GL_TEXTURE0);
186
187   /* Initialize the fogging options */
188   _cogl_wrap_glDisable (GL_FOG);
189   _cogl_wrap_glFogf (GL_FOG_MODE, GL_LINEAR);
190   _cogl_wrap_glFogf (GL_FOG_DENSITY, 1.0);
191   _cogl_wrap_glFogf (GL_FOG_START, 0);
192   _cogl_wrap_glFogf (GL_FOG_END, 1);
193   _cogl_wrap_glFogfv (GL_FOG_COLOR, default_fog_color);
194
195   /* Initialize alpha testing */
196   _cogl_wrap_glDisable (GL_ALPHA_TEST);
197   _cogl_wrap_glAlphaFunc (GL_ALWAYS, 0.0f);
198
199   /* Initialize the point size */
200   _cogl_wrap_glPointSize (1.0f);
201
202   initialize_texture_units (wrapper);
203 }
204
205 static int
206 cogl_gles2_get_n_args_for_combine_func (GLenum func)
207 {
208   switch (func)
209     {
210     case GL_REPLACE:
211       return 1;
212     case GL_MODULATE:
213     case GL_ADD:
214     case GL_ADD_SIGNED:
215     case GL_SUBTRACT:
216     case GL_DOT3_RGB:
217     case GL_DOT3_RGBA:
218       return 2;
219     case GL_INTERPOLATE:
220       return 3;
221     default:
222       return 0;
223     }
224 }
225
226 static gboolean
227 cogl_gles2_settings_equal (const CoglGles2WrapperSettings *a,
228                            const CoglGles2WrapperSettings *b,
229                            gboolean vertex_tests,
230                            gboolean fragment_tests)
231 {
232   int i;
233
234   if (a->texture_units != b->texture_units)
235     return FALSE;
236
237   if (fragment_tests)
238     {
239       if (a->alpha_test_enabled != b->alpha_test_enabled)
240         return FALSE;
241       if (a->alpha_test_enabled && a->alpha_test_func != b->alpha_test_func)
242         return FALSE;
243     }
244
245   if (a->fog_enabled != b->fog_enabled)
246     return FALSE;
247
248   if (vertex_tests && a->fog_enabled && a->fog_mode != b->fog_mode)
249     return FALSE;
250
251   /* Compare layer combine operation for each active unit */
252   if (fragment_tests)
253     for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
254       {
255         if (!!COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (a->texture_units, i) !=
256             !!COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (b->texture_units, i))
257           return FALSE;
258
259         if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (a->texture_units, i))
260           {
261             const CoglGles2WrapperTexEnv *tex_env_a = a->tex_env + i;
262             const CoglGles2WrapperTexEnv *tex_env_b = b->tex_env + i;
263             int arg, n_args;
264             GLenum func;
265
266             if (tex_env_a->texture_target != tex_env_b->texture_target)
267               return FALSE;
268
269             if (tex_env_a->point_sprite_coords !=
270                 tex_env_b->point_sprite_coords)
271               return FALSE;
272
273             func = tex_env_a->texture_combine_rgb_func;
274
275             if (func != tex_env_b->texture_combine_rgb_func)
276               return FALSE;
277
278             n_args = cogl_gles2_get_n_args_for_combine_func (func);
279
280             for (arg = 0; arg < n_args; arg++)
281               {
282                 if (tex_env_a->texture_combine_rgb_src[arg] !=
283                     tex_env_b->texture_combine_rgb_src[arg])
284                   return FALSE;
285                 if (tex_env_a->texture_combine_rgb_op[arg] !=
286                     tex_env_b->texture_combine_rgb_op[arg])
287                   return FALSE;
288               }
289           }
290       }
291
292   return TRUE;
293 }
294
295 static CoglGles2WrapperShader *
296 cogl_gles2_get_vertex_shader (const CoglGles2WrapperSettings *settings)
297 {
298   GString *shader_source;
299   GLuint shader_obj;
300   CoglGles2WrapperShader *shader;
301   GSList *node;
302   int i;
303   int n_texture_units = 0;
304
305   _COGL_GET_GLES2_WRAPPER (w, NULL);
306
307   /* Check if we already have a vertex shader for these settings */
308   for (node = w->compiled_vertex_shaders; node; node = node->next)
309     if (cogl_gles2_settings_equal (settings,
310                                    &((CoglGles2WrapperShader *)
311                                      node->data)->settings,
312                                    TRUE, FALSE))
313       return (CoglGles2WrapperShader *) node->data;
314
315   /* Otherwise create a new shader */
316   shader_source = g_string_new (_cogl_fixed_vertex_shader_per_vertex_attribs);
317
318   for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
319     if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (settings->texture_units, i))
320       g_string_append_printf (shader_source,
321                               "attribute vec4 multi_tex_coord_attrib%d;\n",
322                               i);
323
324   /* Find the biggest enabled texture unit index */
325   for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
326     if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (settings->texture_units, i))
327       n_texture_units = i + 1;
328
329   g_string_append (shader_source, _cogl_fixed_vertex_shader_transform_matrices);
330   g_string_append (shader_source, _cogl_fixed_vertex_shader_output_variables);
331
332   if (n_texture_units > 0)
333     {
334       g_string_append_printf (shader_source,
335                               "uniform mat4           texture_matrix[%d];\n",
336                               n_texture_units);
337
338       g_string_append_printf (shader_source,
339                               "varying vec2       tex_coord[%d];",
340                               n_texture_units);
341     }
342
343   g_string_append (shader_source, _cogl_fixed_vertex_shader_fogging_options);
344   g_string_append (shader_source, _cogl_fixed_vertex_shader_main_start);
345
346   for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
347     if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (settings->texture_units, i) &&
348         !settings->tex_env[i].point_sprite_coords)
349       {
350         g_string_append_printf (shader_source,
351                                 "transformed_tex_coord = "
352                                 "texture_matrix[%d] "
353                                 " * multi_tex_coord_attrib%d;\n",
354                                 i, i);
355         g_string_append_printf (shader_source,
356                                 "tex_coord[%d] = transformed_tex_coord.st "
357                                 " / transformed_tex_coord.q;\n",
358                                 i);
359       }
360
361   g_string_append (shader_source, _cogl_fixed_vertex_shader_frag_color_start);
362
363   if (settings->fog_enabled)
364     {
365       g_string_append (shader_source, _cogl_fixed_vertex_shader_fog_start);
366
367       switch (settings->fog_mode)
368         {
369         case GL_EXP:
370           g_string_append (shader_source, _cogl_fixed_vertex_shader_fog_exp);
371           break;
372
373         case GL_EXP2:
374           g_string_append (shader_source, _cogl_fixed_vertex_shader_fog_exp2);
375           break;
376
377         default:
378           g_string_append (shader_source, _cogl_fixed_vertex_shader_fog_linear);
379           break;
380         }
381
382       g_string_append (shader_source, _cogl_fixed_vertex_shader_fog_end);
383     }
384
385   g_string_append (shader_source, _cogl_fixed_vertex_shader_end);
386
387   shader_obj = cogl_gles2_wrapper_create_shader (GL_VERTEX_SHADER,
388                                                  shader_source->str);
389
390   g_string_free (shader_source, TRUE);
391
392   if (shader_obj == 0)
393     return NULL;
394
395   shader = g_slice_new (CoglGles2WrapperShader);
396   shader->shader = shader_obj;
397   shader->settings = *settings;
398
399   w->compiled_vertex_shaders = g_slist_prepend (w->compiled_vertex_shaders,
400                                                 shader);
401
402   return shader;
403 }
404
405 static void
406 cogl_gles2_add_texture_lookup (int unit,
407                                const char *swizzle,
408                                GString *shader_source)
409 {
410   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
411
412   if (w->settings.tex_env[unit].texture_target == GL_TEXTURE_3D_OES)
413     g_string_append_printf (shader_source, "texture3D (texture_unit[%d], ",
414                             unit);
415   else
416     g_string_append_printf (shader_source, "texture2D (texture_unit[%d], ",
417                             unit);
418
419   /* If point sprite coord generation is being used then divert to the
420      built-in varying var for that instead of the texture
421      coordinates */
422   if (w->settings.tex_env[unit].point_sprite_coords)
423     g_string_append (shader_source, "gl_PointCoord");
424   else
425     g_string_append_printf (shader_source, "tex_coord[%d]", unit);
426
427   g_string_append_printf (shader_source, ").%s", swizzle);
428 }
429
430 static void
431 cogl_gles2_add_arg (int unit,
432                     GLenum src,
433                     GLenum operand,
434                     const char *swizzle,
435                     GString *shader_source)
436 {
437   char alpha_swizzle[5] = "aaaa";
438
439   g_string_append_c (shader_source, '(');
440
441   if (operand == GL_ONE_MINUS_SRC_COLOR || operand == GL_ONE_MINUS_SRC_ALPHA)
442     g_string_append_printf (shader_source,
443                             "vec4(1.0, 1.0, 1.0, 1.0).%s - ",
444                             swizzle);
445
446   /* If the operand is reading from the alpha then replace the swizzle
447      with the same number of copies of the alpha */
448   if (operand == GL_SRC_ALPHA || operand == GL_ONE_MINUS_SRC_ALPHA)
449     {
450       alpha_swizzle[strlen (swizzle)] = '\0';
451       swizzle = alpha_swizzle;
452     }
453
454   switch (src)
455     {
456     case GL_TEXTURE:
457       cogl_gles2_add_texture_lookup (unit, swizzle, shader_source);
458       break;
459
460     case GL_CONSTANT:
461       g_string_append_printf (shader_source, "combine_constant[%d].%s",
462                               unit, swizzle);
463       break;
464
465     case GL_PREVIOUS:
466       if (unit > 0)
467         {
468           g_string_append_printf (shader_source, "gl_FragColor.%s", swizzle);
469           break;
470         }
471       /* flow through */
472     case GL_PRIMARY_COLOR:
473       g_string_append_printf (shader_source, "frag_color.%s", swizzle);
474       break;
475
476     default:
477       if (src >= GL_TEXTURE0 &&
478           src < GL_TEXTURE0 + COGL_GLES2_MAX_TEXTURE_UNITS)
479         cogl_gles2_add_texture_lookup (src - GL_TEXTURE0,
480                                        swizzle, shader_source);
481       break;
482     }
483
484   g_string_append_c (shader_source, ')');
485 }
486
487 static void
488 cogl_gles2_add_operation (int unit,
489                           GLenum combine_func,
490                           const GLenum *sources,
491                           const GLenum *operands,
492                           const char *swizzle,
493                           GString *shader_source)
494 {
495   switch (combine_func)
496     {
497     case GL_REPLACE:
498       cogl_gles2_add_arg (unit, sources[0], operands[0],
499                           swizzle, shader_source);
500       break;
501
502     case GL_MODULATE:
503       cogl_gles2_add_arg (unit, sources[0], operands[0],
504                           swizzle, shader_source);
505       g_string_append (shader_source, " * ");
506       cogl_gles2_add_arg (unit, sources[1], operands[1],
507                           swizzle, shader_source);
508       break;
509
510     case GL_ADD:
511       cogl_gles2_add_arg (unit, sources[0], operands[0],
512                           swizzle, shader_source);
513       g_string_append (shader_source, " + ");
514       cogl_gles2_add_arg (unit, sources[1], operands[1],
515                           swizzle, shader_source);
516       break;
517
518     case GL_ADD_SIGNED:
519       cogl_gles2_add_arg (unit, sources[0], operands[0],
520                           swizzle, shader_source);
521       g_string_append (shader_source, " + ");
522       cogl_gles2_add_arg (unit, sources[1], operands[1],
523                           swizzle, shader_source);
524       g_string_append_printf (shader_source,
525                               " - vec4(0.5, 0.5, 0.5, 0.5).%s",
526                               swizzle);
527       break;
528
529     case GL_SUBTRACT:
530       cogl_gles2_add_arg (unit, sources[0], operands[0],
531                           swizzle, shader_source);
532       g_string_append (shader_source, " - ");
533       cogl_gles2_add_arg (unit, sources[1], operands[1],
534                           swizzle, shader_source);
535       break;
536
537     case GL_INTERPOLATE:
538       cogl_gles2_add_arg (unit, sources[0], operands[0],
539                           swizzle, shader_source);
540       g_string_append (shader_source, " * ");
541       cogl_gles2_add_arg (unit, sources[2], operands[2],
542                           swizzle, shader_source);
543       g_string_append (shader_source, " + ");
544       cogl_gles2_add_arg (unit, sources[1], operands[1],
545                           swizzle, shader_source);
546       g_string_append_printf (shader_source,
547                               " * (vec4(1.0, 1.0, 1.0, 1.0).%s - ",
548                               swizzle);
549       cogl_gles2_add_arg (unit, sources[2], operands[2],
550                           swizzle, shader_source);
551       g_string_append_c (shader_source, ')');
552       break;
553
554     case GL_DOT3_RGB:
555     case GL_DOT3_RGBA:
556       g_string_append (shader_source, "vec4(4 * ((");
557       cogl_gles2_add_arg (unit, sources[0], operands[0],
558                           "r", shader_source);
559       g_string_append (shader_source, " - 0.5) * (");
560       cogl_gles2_add_arg (unit, sources[1], operands[1],
561                           "r", shader_source);
562       g_string_append (shader_source, " - 0.5) + (");
563       cogl_gles2_add_arg (unit, sources[0], operands[0],
564                           "g", shader_source);
565       g_string_append (shader_source, " - 0.5) * (");
566       cogl_gles2_add_arg (unit, sources[1], operands[1],
567                           "g", shader_source);
568       g_string_append (shader_source, " - 0.5) + (");
569       cogl_gles2_add_arg (unit, sources[0], operands[0],
570                           "b", shader_source);
571       g_string_append (shader_source, " - 0.5) * (");
572       cogl_gles2_add_arg (unit, sources[1], operands[1],
573                           "b", shader_source);
574       g_string_append_printf (shader_source, " - 0.5))).%s", swizzle);
575       break;
576     }
577 }
578
579 static gboolean
580 cogl_gles2_rgb_and_alpha_equal (const CoglGles2WrapperTexEnv *tex_env)
581 {
582   int arg, n_args;
583
584   if (tex_env->texture_combine_rgb_func != tex_env->texture_combine_alpha_func)
585     return FALSE;
586
587   n_args =
588     cogl_gles2_get_n_args_for_combine_func (tex_env->texture_combine_rgb_func);
589
590   for (arg = 0; arg < n_args; arg++)
591     {
592       if (tex_env->texture_combine_rgb_src[arg] !=
593           tex_env->texture_combine_alpha_src[arg])
594         return FALSE;
595
596       if (tex_env->texture_combine_rgb_op[arg] != GL_SRC_COLOR ||
597           tex_env->texture_combine_alpha_op[arg] != GL_SRC_ALPHA)
598         return FALSE;
599     }
600
601   return TRUE;
602 }
603
604
605 static CoglGles2WrapperShader *
606 cogl_gles2_get_fragment_shader (const CoglGles2WrapperSettings *settings)
607 {
608   GString *shader_source;
609   GLuint shader_obj;
610   CoglGles2WrapperShader *shader;
611   GSList *node;
612   int i;
613   int n_texture_units = 0;
614
615   _COGL_GET_GLES2_WRAPPER (w, NULL);
616
617   /* Check if we already have a fragment shader for these settings */
618   for (node = w->compiled_fragment_shaders; node; node = node->next)
619     if (cogl_gles2_settings_equal (settings,
620                                    &((CoglGles2WrapperShader *)
621                                      node->data)->settings,
622                                    FALSE, TRUE))
623       return (CoglGles2WrapperShader *) node->data;
624
625   /* Otherwise create a new shader */
626   shader_source = g_string_new (_cogl_fixed_fragment_shader_variables_start);
627
628   /* Find the biggest enabled texture unit index */
629   for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
630     if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (settings->texture_units, i))
631       n_texture_units = i + 1;
632
633   g_string_append (shader_source, _cogl_fixed_fragment_shader_inputs);
634
635   if (n_texture_units > 0)
636     {
637       g_string_append_printf (shader_source,
638                               "varying vec2       tex_coord[%d];\n",
639                               n_texture_units);
640
641       g_string_append (shader_source,
642                        _cogl_fixed_fragment_shader_texturing_options);
643       g_string_append_printf (shader_source,
644                               "uniform sampler2D  texture_unit[%d];\n",
645                               n_texture_units);
646     }
647
648   g_string_append (shader_source, _cogl_fixed_fragment_shader_fogging_options);
649
650   g_string_append (shader_source, _cogl_fixed_fragment_shader_main_declare);
651
652   g_string_append (shader_source, _cogl_fixed_fragment_shader_main_start);
653
654   /* This pointless extra variable is needed to work around an
655      apparent bug in the PowerVR drivers. Without it the alpha
656      blending seems to stop working */
657   g_string_append (shader_source,
658                    "vec4 frag_color_copy = frag_color;\n");
659
660   /* If there are no textures units enabled then we can just directly
661      use the color from the vertex shader */
662   if (n_texture_units == 0)
663     g_string_append (shader_source, "gl_FragColor = frag_color;\n");
664   else
665     /* Otherwise we need to calculate the value based on the layer
666        combine settings */
667     for (i = 0; i < n_texture_units; i++)
668       if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (settings->texture_units, i))
669         {
670           const CoglGles2WrapperTexEnv *tex_env = settings->tex_env + i;
671
672           /* If the rgb and alpha combine functions are the same then
673              we can do both with a single statement, otherwise we need
674              to do them separately */
675           if (cogl_gles2_rgb_and_alpha_equal (tex_env))
676             {
677               g_string_append (shader_source, "gl_FragColor.rgba = ");
678               cogl_gles2_add_operation (i,
679                                         tex_env->texture_combine_rgb_func,
680                                         tex_env->texture_combine_rgb_src,
681                                         tex_env->texture_combine_rgb_op,
682                                         "rgba",
683                                         shader_source);
684               g_string_append (shader_source, ";\n");
685             }
686           else
687             {
688               g_string_append (shader_source, "gl_FragColor.rgb = ");
689               cogl_gles2_add_operation (i,
690                                         tex_env->texture_combine_rgb_func,
691                                         tex_env->texture_combine_rgb_src,
692                                         tex_env->texture_combine_rgb_op,
693                                         "rgb",
694                                         shader_source);
695               g_string_append (shader_source,
696                                ";\n"
697                                "gl_FragColor.a = ");
698               cogl_gles2_add_operation (i,
699                                         tex_env->texture_combine_alpha_func,
700                                         tex_env->texture_combine_alpha_src,
701                                         tex_env->texture_combine_alpha_op,
702                                         "a",
703                                         shader_source);
704               g_string_append (shader_source, ";\n");
705             }
706         }
707
708   if (settings->fog_enabled)
709     g_string_append (shader_source, _cogl_fixed_fragment_shader_fog);
710
711   if (settings->alpha_test_enabled)
712     switch (settings->alpha_test_func)
713       {
714       case GL_NEVER:
715         g_string_append (shader_source,
716                          _cogl_fixed_fragment_shader_alpha_never);
717         break;
718       case GL_LESS:
719         g_string_append (shader_source,
720                          _cogl_fixed_fragment_shader_alpha_less);
721         break;
722       case GL_EQUAL:
723         g_string_append (shader_source,
724                          _cogl_fixed_fragment_shader_alpha_equal);
725         break;
726       case GL_LEQUAL:
727         g_string_append (shader_source,
728                          _cogl_fixed_fragment_shader_alpha_lequal);
729         break;
730       case GL_GREATER:
731         g_string_append (shader_source,
732                          _cogl_fixed_fragment_shader_alpha_greater);
733         break;
734       case GL_NOTEQUAL:
735         g_string_append (shader_source,
736                          _cogl_fixed_fragment_shader_alpha_notequal);
737         break;
738       case GL_GEQUAL:
739         g_string_append (shader_source,
740                          _cogl_fixed_fragment_shader_alpha_gequal);
741       }
742
743   g_string_append (shader_source, _cogl_fixed_fragment_shader_end);
744
745   shader_obj = cogl_gles2_wrapper_create_shader (GL_FRAGMENT_SHADER,
746                                                  shader_source->str);
747
748   g_string_free (shader_source, TRUE);
749
750   if (shader_obj == 0)
751     return NULL;
752
753   shader = g_slice_new (CoglGles2WrapperShader);
754   shader->shader = shader_obj;
755   shader->settings = *settings;
756
757   w->compiled_fragment_shaders = g_slist_prepend (w->compiled_fragment_shaders,
758                                                   shader);
759
760   return shader;
761 }
762
763 static void
764 cogl_gles2_wrapper_get_locations (GLuint program,
765                                   CoglGles2WrapperSettings *settings,
766                                   CoglGles2WrapperUniforms *uniforms,
767                                   CoglGles2WrapperAttributes *attribs)
768 {
769   int i;
770
771   uniforms->mvp_matrix_uniform
772     = glGetUniformLocation (program, "mvp_matrix");
773   uniforms->modelview_matrix_uniform
774     = glGetUniformLocation (program, "modelview_matrix");
775
776   for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
777     if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (settings->texture_units, i))
778       {
779         char *matrix_var_name = g_strdup_printf ("texture_matrix[%d]", i);
780         char *sampler_var_name = g_strdup_printf ("texture_unit[%d]", i);
781         char *tex_coord_var_name =
782           g_strdup_printf ("multi_tex_coord_attrib%d", i);
783
784         uniforms->texture_matrix_uniforms[i]
785           = glGetUniformLocation (program, matrix_var_name);
786         uniforms->texture_sampler_uniforms[i]
787           = glGetUniformLocation (program, sampler_var_name);
788         attribs->multi_texture_coords[i]
789           = glGetAttribLocation (program, tex_coord_var_name);
790
791         g_free (tex_coord_var_name);
792         g_free (sampler_var_name);
793         g_free (matrix_var_name);
794       }
795     else
796       {
797         uniforms->texture_matrix_uniforms[i] = -1;
798         uniforms->texture_sampler_uniforms[i] = -1;
799         attribs->multi_texture_coords[i] = -1;
800       }
801
802   uniforms->fog_density_uniform
803     = glGetUniformLocation (program, "fog_density");
804   uniforms->fog_start_uniform
805     = glGetUniformLocation (program, "fog_start");
806   uniforms->fog_end_uniform
807     = glGetUniformLocation (program, "fog_end");
808   uniforms->fog_color_uniform
809     = glGetUniformLocation (program, "fog_color");
810
811   uniforms->alpha_test_ref_uniform
812     = glGetUniformLocation (program, "alpha_test_ref");
813
814   uniforms->point_size_uniform
815     = glGetUniformLocation (program, "point_size");
816 }
817
818 static void
819 cogl_gles2_wrapper_bind_attributes (GLuint program)
820 {
821   glBindAttribLocation (program, COGL_GLES2_WRAPPER_VERTEX_ATTRIB,
822                         "vertex_attrib");
823   glBindAttribLocation (program, COGL_GLES2_WRAPPER_COLOR_ATTRIB,
824                         "color_attrib");
825   glBindAttribLocation (program, COGL_GLES2_WRAPPER_NORMAL_ATTRIB,
826                         "normal_attrib");
827 }
828
829 static CoglGles2WrapperProgram *
830 cogl_gles2_wrapper_get_program (const CoglGles2WrapperSettings *settings)
831 {
832   GSList *node;
833   CoglGles2WrapperProgram *program;
834   CoglGles2WrapperShader *vertex_shader, *fragment_shader;
835   GLint status;
836   gboolean custom_vertex_shader = FALSE, custom_fragment_shader = FALSE;
837   CoglProgram *user_program = NULL;
838   int i;
839
840   _COGL_GET_GLES2_WRAPPER (w, NULL);
841
842   /* Check if we've already got a program for these settings */
843   for (node = w->compiled_programs; node; node = node->next)
844     {
845       program = (CoglGles2WrapperProgram *) node->data;
846
847       if (cogl_gles2_settings_equal (settings, &program->settings, TRUE, TRUE)
848           && program->settings.user_program == settings->user_program)
849         return (CoglGles2WrapperProgram *) node->data;
850     }
851
852   /* Otherwise create a new program */
853
854   /* Check whether the currently used custom program has vertex and
855      fragment shaders */
856   if (w->settings.user_program != COGL_INVALID_HANDLE)
857     {
858       user_program
859         = _cogl_program_pointer_from_handle (w->settings.user_program);
860
861       for (node = user_program->attached_shaders; node; node = node->next)
862         {
863           CoglShader *shader
864             = _cogl_shader_pointer_from_handle ((CoglHandle) node->data);
865
866           if (shader->type == COGL_SHADER_TYPE_VERTEX)
867             custom_vertex_shader = TRUE;
868           else if (shader->type == COGL_SHADER_TYPE_FRAGMENT)
869             custom_fragment_shader = TRUE;
870         }
871     }
872
873   /* Get or create the fixed functionality shaders for these settings
874      if there is no custom replacement */
875   if (!custom_vertex_shader)
876     {
877       vertex_shader = cogl_gles2_get_vertex_shader (settings);
878       if (vertex_shader == NULL)
879         return NULL;
880     }
881   if (!custom_fragment_shader)
882     {
883       fragment_shader = cogl_gles2_get_fragment_shader (settings);
884       if (fragment_shader == NULL)
885         return NULL;
886     }
887
888   program = g_slice_new (CoglGles2WrapperProgram);
889
890   program->program = glCreateProgram ();
891   if (!custom_vertex_shader)
892     glAttachShader (program->program, vertex_shader->shader);
893   if (!custom_fragment_shader)
894     glAttachShader (program->program, fragment_shader->shader);
895   if (user_program)
896     for (node = user_program->attached_shaders; node; node = node->next)
897       {
898         CoglShader *shader
899           = _cogl_shader_pointer_from_handle ((CoglHandle) node->data);
900         glAttachShader (program->program, shader->gl_handle);
901       }
902   cogl_gles2_wrapper_bind_attributes (program->program);
903   glLinkProgram (program->program);
904
905   glGetProgramiv (program->program, GL_LINK_STATUS, &status);
906
907   if (!status)
908     {
909       char shader_log[1024];
910       GLint len;
911
912       glGetProgramInfoLog (program->program, sizeof (shader_log) - 1, &len, shader_log);
913       shader_log[len] = '\0';
914
915       g_critical ("%s", shader_log);
916
917       glDeleteProgram (program->program);
918       g_slice_free (CoglGles2WrapperProgram, program);
919
920       return NULL;
921     }
922
923   program->settings = *settings;
924
925   cogl_gles2_wrapper_get_locations (program->program,
926                                     &program->settings,
927                                     &program->uniforms,
928                                     &program->attributes);
929
930   /* We haven't tried to get a location for any of the custom uniforms
931      yet */
932   for (i = 0; i < COGL_PROGRAM_NUM_CUSTOM_UNIFORMS; i++)
933     program->custom_gl_uniforms[i] = COGL_PROGRAM_UNBOUND_CUSTOM_UNIFORM;
934
935   w->compiled_programs = g_slist_append (w->compiled_programs, program);
936
937   return program;
938 }
939
940 void
941 _cogl_gles2_wrapper_deinit (CoglGles2Wrapper *wrapper)
942 {
943   GSList *node, *next;
944
945   for (node = wrapper->compiled_programs; node; node = next)
946     {
947       next = node->next;
948       glDeleteProgram (((CoglGles2WrapperProgram *) node->data)->program);
949       g_slist_free1 (node);
950     }
951   wrapper->compiled_programs = NULL;
952
953   for (node = wrapper->compiled_vertex_shaders; node; node = next)
954     {
955       next = node->next;
956       glDeleteShader (((CoglGles2WrapperShader *) node->data)->shader);
957       g_slist_free1 (node);
958     }
959   wrapper->compiled_vertex_shaders = NULL;
960
961   for (node = wrapper->compiled_fragment_shaders; node; node = next)
962     {
963       next = node->next;
964       glDeleteShader (((CoglGles2WrapperShader *) node->data)->shader);
965       g_slist_free1 (node);
966     }
967   wrapper->compiled_fragment_shaders = NULL;
968 }
969
970 static void
971 cogl_gles2_wrapper_notify_matrix_changed (CoglGles2Wrapper *wrapper,
972                                           GLenum mode)
973 {
974   CoglGles2WrapperTextureUnit *texture_unit;
975
976   switch (mode)
977     {
978     case GL_MODELVIEW:
979       wrapper->dirty_uniforms |= COGL_GLES2_DIRTY_MVP_MATRIX
980         | COGL_GLES2_DIRTY_MODELVIEW_MATRIX;
981       break;
982
983     case GL_PROJECTION:
984       wrapper->dirty_uniforms |= COGL_GLES2_DIRTY_MVP_MATRIX;
985       break;
986
987     case GL_TEXTURE:
988       wrapper->dirty_uniforms |= COGL_GLES2_DIRTY_TEXTURE_MATRICES;
989       texture_unit = wrapper->texture_units + wrapper->active_texture_unit;
990       texture_unit->dirty_matrix = 1;
991       break;
992
993     default:
994       g_critical ("%s: Unexpected matrix mode %d\n", G_STRFUNC, mode);
995     }
996 }
997
998 void
999 _cogl_wrap_glMatrixMode (GLenum mode)
1000 {
1001   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1002
1003   w->matrix_mode = mode;
1004 }
1005
1006 static CoglMatrix *
1007 cogl_gles2_get_current_matrix (CoglGles2Wrapper *wrapper)
1008 {
1009   CoglGles2WrapperTextureUnit *texture_unit;
1010
1011   switch (wrapper->matrix_mode)
1012     {
1013     default:
1014       g_critical ("%s: Unexpected matrix mode %d\n",
1015                   G_STRFUNC, wrapper->matrix_mode);
1016       /* flow through */
1017
1018     case GL_MODELVIEW:
1019       return &wrapper->modelview_matrix;
1020
1021     case GL_PROJECTION:
1022       return &wrapper->projection_matrix;
1023
1024     case GL_TEXTURE:
1025       texture_unit = wrapper->texture_units + wrapper->active_texture_unit;
1026       return &texture_unit->texture_matrix;
1027     }
1028 }
1029
1030 void
1031 _cogl_wrap_glLoadIdentity (void)
1032 {
1033   CoglMatrix *matrix;
1034
1035   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1036
1037   matrix = cogl_gles2_get_current_matrix (w);
1038
1039   cogl_matrix_init_identity (matrix);
1040
1041   cogl_gles2_wrapper_notify_matrix_changed (w, w->matrix_mode);
1042 }
1043
1044 void
1045 _cogl_wrap_glLoadMatrixf (const GLfloat *m)
1046 {
1047   CoglMatrix *matrix;
1048
1049   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1050
1051   matrix = cogl_gles2_get_current_matrix (w);
1052
1053   cogl_matrix_init_from_array (matrix, m);
1054
1055   cogl_gles2_wrapper_notify_matrix_changed (w, w->matrix_mode);
1056 }
1057
1058 void
1059 _cogl_wrap_glVertexPointer (GLint size, GLenum type, GLsizei stride,
1060                            const GLvoid *pointer)
1061 {
1062   glVertexAttribPointer (COGL_GLES2_WRAPPER_VERTEX_ATTRIB, size, type,
1063                          GL_FALSE, stride, pointer);
1064 }
1065
1066 void
1067 _cogl_wrap_glTexCoordPointer (GLint size, GLenum type, GLsizei stride,
1068                              const GLvoid *pointer)
1069 {
1070   int active_unit;
1071   CoglGles2WrapperTextureUnit *texture_unit;
1072   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1073
1074   active_unit = w->active_client_texture_unit;
1075
1076   texture_unit = w->texture_units + active_unit;
1077   texture_unit->texture_coords_size = size;
1078   texture_unit->texture_coords_type = type;
1079   texture_unit->texture_coords_stride = stride;
1080   texture_unit->texture_coords_pointer = pointer;
1081
1082   w->dirty_attribute_pointers
1083     |= COGL_GLES2_DIRTY_TEX_COORD_VERTEX_ATTRIB;
1084 }
1085
1086 void
1087 _cogl_wrap_glColorPointer (GLint size, GLenum type, GLsizei stride,
1088                            const GLvoid *pointer)
1089 {
1090   glVertexAttribPointer (COGL_GLES2_WRAPPER_COLOR_ATTRIB, size, type,
1091                          GL_TRUE, stride, pointer);
1092 }
1093
1094 void
1095 _cogl_wrap_glNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer)
1096 {
1097   glVertexAttribPointer (COGL_GLES2_WRAPPER_NORMAL_ATTRIB, 1, type,
1098                          GL_FALSE, stride, pointer);
1099 }
1100
1101 static void
1102 cogl_gles2_do_set_uniform (GLint location, CoglBoxedValue *value)
1103 {
1104   switch (value->type)
1105     {
1106     case COGL_BOXED_NONE:
1107       break;
1108
1109     case COGL_BOXED_INT:
1110       {
1111         int *ptr;
1112
1113         if (value->count == 1)
1114           ptr = value->v.int_value;
1115         else
1116           ptr = value->v.int_array;
1117
1118         switch (value->size)
1119           {
1120           case 1: glUniform1iv (location, value->count, ptr); break;
1121           case 2: glUniform2iv (location, value->count, ptr); break;
1122           case 3: glUniform3iv (location, value->count, ptr); break;
1123           case 4: glUniform4iv (location, value->count, ptr); break;
1124           }
1125       }
1126       break;
1127
1128     case COGL_BOXED_FLOAT:
1129       {
1130         float *ptr;
1131
1132         if (value->count == 1)
1133           ptr = value->v.float_value;
1134         else
1135           ptr = value->v.float_array;
1136
1137         switch (value->size)
1138           {
1139           case 1: glUniform1fv (location, value->count, ptr); break;
1140           case 2: glUniform2fv (location, value->count, ptr); break;
1141           case 3: glUniform3fv (location, value->count, ptr); break;
1142           case 4: glUniform4fv (location, value->count, ptr); break;
1143           }
1144       }
1145       break;
1146
1147     case COGL_BOXED_MATRIX:
1148       {
1149         float *ptr;
1150
1151         if (value->count == 1)
1152           ptr = value->v.matrix;
1153         else
1154           ptr = value->v.float_array;
1155
1156         switch (value->size)
1157           {
1158           case 2:
1159             glUniformMatrix2fv (location, value->count, value->transpose, ptr);
1160             break;
1161           case 3:
1162             glUniformMatrix3fv (location, value->count, value->transpose, ptr);
1163             break;
1164           case 4:
1165             glUniformMatrix4fv (location, value->count, value->transpose, ptr);
1166             break;
1167           }
1168       }
1169       break;
1170     }
1171 }
1172
1173 static void
1174 _cogl_wrap_prepare_for_draw (void)
1175 {
1176   CoglGles2WrapperProgram *program;
1177   guint32 dirty_custom_uniforms = 0;
1178
1179   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1180
1181   /* Check if we need to switch programs */
1182   if (w->settings_dirty)
1183     {
1184       /* Find or create a program for the current settings */
1185       program = cogl_gles2_wrapper_get_program (&w->settings);
1186
1187       if (program == NULL)
1188         /* Can't compile a shader so there is nothing we can do */
1189         return;
1190
1191       /* Start using it if we aren't already */
1192       if (w->current_program != program)
1193         {
1194           glUseProgram (program->program);
1195           w->current_program = program;
1196           /* All of the uniforms are probably now out of date */
1197           w->dirty_uniforms = COGL_GLES2_DIRTY_ALL;
1198           dirty_custom_uniforms = (1 << COGL_PROGRAM_NUM_CUSTOM_UNIFORMS) - 1;
1199         }
1200       w->settings_dirty = FALSE;
1201     }
1202   else
1203     {
1204       CoglProgram *user_program =
1205         _cogl_program_pointer_from_handle (w->settings.user_program);
1206       if (user_program)
1207         dirty_custom_uniforms = user_program->dirty_custom_uniforms;
1208       program = w->current_program;
1209     }
1210
1211   /* Make sure all of the uniforms are up to date */
1212   if (w->dirty_uniforms)
1213     {
1214       if ((w->dirty_uniforms & (COGL_GLES2_DIRTY_MVP_MATRIX
1215                                 | COGL_GLES2_DIRTY_MODELVIEW_MATRIX)))
1216         {
1217           CoglMatrix mvp_matrix;
1218           CoglMatrix *modelview_matrix = &w->modelview_matrix;
1219           CoglMatrix *projection_matrix = &w->projection_matrix;
1220
1221           /* FIXME: we should have a cogl_matrix_copy () function */
1222           memcpy (&mvp_matrix, projection_matrix, sizeof (CoglMatrix));
1223
1224           cogl_matrix_multiply (&mvp_matrix, &mvp_matrix, modelview_matrix);
1225
1226           if (program->uniforms.mvp_matrix_uniform != -1)
1227             glUniformMatrix4fv (program->uniforms.mvp_matrix_uniform, 1,
1228                                 GL_FALSE, (float *) &mvp_matrix);
1229           if (program->uniforms.modelview_matrix_uniform != -1)
1230             glUniformMatrix4fv (program->uniforms.modelview_matrix_uniform, 1,
1231                                 GL_FALSE, (float *) &modelview_matrix);
1232         }
1233       if ((w->dirty_uniforms & COGL_GLES2_DIRTY_TEXTURE_MATRICES))
1234         {
1235           int i;
1236
1237           /* TODO - we should probably have a per unit dirty flag too */
1238
1239           for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
1240             {
1241               CoglGles2WrapperTextureUnit *texture_unit;
1242               GLint uniform = program->uniforms.texture_matrix_uniforms[i];
1243
1244               texture_unit = w->texture_units + i;
1245               if (uniform != -1)
1246                 glUniformMatrix4fv (uniform, 1, GL_FALSE,
1247                                     (float *) &texture_unit->texture_matrix);
1248             }
1249         }
1250
1251       if ((w->dirty_uniforms & COGL_GLES2_DIRTY_FOG_DENSITY)
1252           && program->uniforms.fog_density_uniform != -1)
1253         glUniform1f (program->uniforms.fog_density_uniform, w->fog_density);
1254       if ((w->dirty_uniforms & COGL_GLES2_DIRTY_FOG_START)
1255           && program->uniforms.fog_start_uniform != -1)
1256         glUniform1f (program->uniforms.fog_start_uniform, w->fog_start);
1257       if ((w->dirty_uniforms & COGL_GLES2_DIRTY_FOG_END)
1258           && program->uniforms.fog_end_uniform != -1)
1259         glUniform1f (program->uniforms.fog_end_uniform, w->fog_end);
1260
1261       if ((w->dirty_uniforms & COGL_GLES2_DIRTY_ALPHA_TEST_REF)
1262           && program->uniforms.alpha_test_ref_uniform != -1)
1263         glUniform1f (program->uniforms.alpha_test_ref_uniform,
1264                      w->alpha_test_ref);
1265
1266       if ((w->dirty_uniforms & COGL_GLES2_DIRTY_TEXTURE_UNITS))
1267         {
1268           int i;
1269
1270           /* TODO - we should probably have a per unit dirty flag too */
1271
1272           for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
1273             {
1274               GLint uniform = program->uniforms.texture_sampler_uniforms[i];
1275
1276               if (uniform != -1)
1277                 glUniform1i (uniform, i);
1278             }
1279         }
1280
1281       if ((w->dirty_uniforms & COGL_GLES2_DIRTY_POINT_SIZE))
1282         glUniform1f (program->uniforms.point_size_uniform,
1283                      w->point_size);
1284
1285       w->dirty_uniforms = 0;
1286     }
1287
1288   if (dirty_custom_uniforms)
1289     {
1290       int i;
1291
1292       if (w->settings.user_program != COGL_INVALID_HANDLE)
1293         {
1294           CoglProgram *user_program
1295             = _cogl_program_pointer_from_handle (w->settings.user_program);
1296           const char *uniform_name;
1297
1298           for (i = 0; i < COGL_PROGRAM_NUM_CUSTOM_UNIFORMS; i++)
1299             if ((dirty_custom_uniforms & (1 << i))
1300                 && (uniform_name = user_program->custom_uniform_names[i]))
1301               {
1302                 if (program->custom_gl_uniforms[i]
1303                     == COGL_PROGRAM_UNBOUND_CUSTOM_UNIFORM)
1304                   program->custom_gl_uniforms[i]
1305                     = glGetUniformLocation (program->program, uniform_name);
1306                 if (program->custom_gl_uniforms[i] >= 0)
1307                   cogl_gles2_do_set_uniform (program->custom_gl_uniforms[i],
1308                                              &user_program->custom_uniforms[i]);
1309               }
1310           user_program->dirty_custom_uniforms = 0;
1311         }
1312     }
1313
1314   if (w->dirty_attribute_pointers
1315       & COGL_GLES2_DIRTY_TEX_COORD_VERTEX_ATTRIB)
1316     {
1317       int i;
1318
1319       /* TODO - coverage test */
1320       for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
1321         if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (w->settings.texture_units, i))
1322           {
1323             GLint tex_coord_var_index;
1324             CoglGles2WrapperTextureUnit *texture_unit;
1325
1326             texture_unit = w->texture_units + i;
1327             if (!texture_unit->texture_coords_enabled)
1328               continue;
1329
1330             /* TODO - we should probably have a per unit dirty flag too */
1331
1332             /* TODO - coverage test */
1333             tex_coord_var_index = program->attributes.multi_texture_coords[i];
1334             glVertexAttribPointer (tex_coord_var_index,
1335                                    texture_unit->texture_coords_size,
1336                                    texture_unit->texture_coords_type,
1337                                    GL_FALSE,
1338                                    texture_unit->texture_coords_stride,
1339                                    texture_unit->texture_coords_pointer);
1340           }
1341     }
1342
1343   if (w->dirty_vertex_attrib_enables)
1344     {
1345       int i;
1346
1347       /* TODO - coverage test */
1348
1349       /* TODO - we should probably have a per unit dirty flag too */
1350
1351       for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
1352         {
1353           CoglGles2WrapperTextureUnit *texture_unit = w->texture_units + i;
1354           GLint attrib = program->attributes.multi_texture_coords[i];
1355
1356           if (attrib != -1)
1357             {
1358               if (texture_unit->texture_coords_enabled)
1359                 glEnableVertexAttribArray (attrib);
1360               else
1361                 glDisableVertexAttribArray (attrib);
1362             }
1363         }
1364
1365       w->dirty_vertex_attrib_enables = 0;
1366     }
1367 }
1368
1369 void
1370 _cogl_wrap_glDrawArrays (GLenum mode, GLint first, GLsizei count)
1371 {
1372   _cogl_wrap_prepare_for_draw ();
1373
1374   glDrawArrays (mode, first, count);
1375 }
1376
1377 void
1378 _cogl_wrap_glDrawElements (GLenum mode, GLsizei count, GLenum type,
1379                           const GLvoid *indices)
1380 {
1381   _cogl_wrap_prepare_for_draw ();
1382
1383   glDrawElements (mode, count, type, indices);
1384 }
1385
1386 void
1387 _cogl_wrap_glTexEnvi (GLenum target, GLenum pname, GLint param)
1388 {
1389   CoglGles2WrapperTexEnv *tex_env;
1390
1391   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1392
1393   tex_env = w->settings.tex_env + w->active_texture_unit;
1394
1395   if (target == GL_TEXTURE_ENV)
1396     {
1397       switch (pname)
1398         {
1399         case GL_COMBINE_RGB:
1400           tex_env->texture_combine_rgb_func = param;
1401           break;
1402         case GL_COMBINE_ALPHA:
1403           tex_env->texture_combine_alpha_func = param;
1404           break;
1405         case GL_SRC0_RGB:
1406         case GL_SRC1_RGB:
1407         case GL_SRC2_RGB:
1408           tex_env->texture_combine_rgb_src[pname - GL_SRC0_RGB] = param;
1409           break;
1410         case GL_SRC0_ALPHA:
1411         case GL_SRC1_ALPHA:
1412         case GL_SRC2_ALPHA:
1413           tex_env->texture_combine_alpha_src[pname - GL_SRC0_ALPHA] = param;
1414           break;
1415         case GL_OPERAND0_RGB:
1416         case GL_OPERAND1_RGB:
1417         case GL_OPERAND2_RGB:
1418           tex_env->texture_combine_rgb_op[pname - GL_OPERAND0_RGB] = param;
1419           break;
1420         case GL_OPERAND0_ALPHA:
1421         case GL_OPERAND1_ALPHA:
1422         case GL_OPERAND2_ALPHA:
1423           tex_env->texture_combine_alpha_op[pname - GL_OPERAND0_ALPHA] = param;
1424           break;
1425         }
1426
1427       w->settings_dirty = TRUE;
1428     }
1429   else if (target == GL_POINT_SPRITE)
1430     {
1431       switch (pname)
1432         {
1433         case GL_COORD_REPLACE:
1434           tex_env->point_sprite_coords = param;
1435           break;
1436         }
1437
1438       w->settings_dirty = TRUE;
1439     }
1440 }
1441
1442 void
1443 _cogl_wrap_glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params)
1444 {
1445   if (target == GL_TEXTURE_ENV && pname == GL_TEXTURE_ENV_COLOR)
1446     {
1447       CoglGles2WrapperTexEnv *tex_env;
1448
1449       _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1450
1451       tex_env = w->settings.tex_env + w->active_texture_unit;
1452
1453       memcpy (tex_env->texture_combine_constant, params, sizeof (GLfloat) * 4);
1454     }
1455 }
1456
1457 void
1458 _cogl_wrap_glClientActiveTexture (GLenum texture)
1459 {
1460   int texture_unit_index = texture - GL_TEXTURE0;
1461   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1462
1463   if (texture_unit_index < COGL_GLES2_MAX_TEXTURE_UNITS)
1464     w->active_client_texture_unit = texture_unit_index;
1465 }
1466
1467 void
1468 _cogl_wrap_glActiveTexture (GLenum texture)
1469 {
1470   int texture_unit_index = texture - GL_TEXTURE0;
1471   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1472
1473   glActiveTexture (texture);
1474
1475   if (texture_unit_index < COGL_GLES2_MAX_TEXTURE_UNITS)
1476     w->active_texture_unit = texture_unit_index;
1477 }
1478
1479 void
1480 _cogl_wrap_glEnable (GLenum cap)
1481 {
1482   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1483
1484   switch (cap)
1485     {
1486     case GL_TEXTURE_2D:
1487     case GL_TEXTURE_3D_OES:
1488       if (!COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (w->settings.texture_units,
1489                                                w->active_texture_unit))
1490         {
1491           COGL_GLES2_TEXTURE_UNIT_SET_ENABLED (w->settings.texture_units,
1492                                                w->active_texture_unit,
1493                                                TRUE);
1494           w->settings_dirty = TRUE;
1495         }
1496       /* Keep track of the last enabled texture unit */
1497       if (w->settings.tex_env[w->active_texture_unit].texture_target != cap)
1498         {
1499           w->settings.tex_env[w->active_texture_unit].texture_target = cap;
1500           w->settings_dirty = TRUE;
1501         }
1502       break;
1503
1504     case GL_FOG:
1505       _COGL_GLES2_CHANGE_SETTING (w, fog_enabled, TRUE);
1506       break;
1507
1508     case GL_ALPHA_TEST:
1509       _COGL_GLES2_CHANGE_SETTING (w, alpha_test_enabled, TRUE);
1510       break;
1511
1512     default:
1513       glEnable (cap);
1514     }
1515 }
1516
1517 void
1518 _cogl_wrap_glDisable (GLenum cap)
1519 {
1520   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1521
1522   switch (cap)
1523     {
1524     case GL_TEXTURE_2D:
1525     case GL_TEXTURE_3D_OES:
1526       /* If this was the last enabled texture target then we'll
1527          completely disable the unit */
1528       if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (w->settings.texture_units,
1529                                               w->active_texture_unit) &&
1530           w->settings.tex_env[w->active_texture_unit].texture_target == cap)
1531         {
1532           COGL_GLES2_TEXTURE_UNIT_SET_ENABLED (w->settings.texture_units,
1533                                                w->active_texture_unit,
1534                                                FALSE);
1535           w->settings_dirty = TRUE;
1536         }
1537       break;
1538
1539     case GL_FOG:
1540       _COGL_GLES2_CHANGE_SETTING (w, fog_enabled, FALSE);
1541       break;
1542
1543     case GL_ALPHA_TEST:
1544       _COGL_GLES2_CHANGE_SETTING (w, alpha_test_enabled, FALSE);
1545       break;
1546
1547     default:
1548       glDisable (cap);
1549     }
1550 }
1551
1552 void
1553 _cogl_wrap_glEnableClientState (GLenum array)
1554 {
1555   CoglGles2WrapperTextureUnit *texture_unit;
1556   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1557
1558   switch (array)
1559     {
1560     case GL_VERTEX_ARRAY:
1561       glEnableVertexAttribArray (COGL_GLES2_WRAPPER_VERTEX_ATTRIB);
1562       break;
1563     case GL_TEXTURE_COORD_ARRAY:
1564       /* TODO - review if this should be in w->settings? */
1565
1566       texture_unit = w->texture_units + w->active_client_texture_unit;
1567       if (texture_unit->texture_coords_enabled != 1)
1568         {
1569           texture_unit->texture_coords_enabled = 1;
1570           w->dirty_vertex_attrib_enables
1571             |= COGL_GLES2_DIRTY_TEX_COORD_ATTRIB_ENABLES;
1572         }
1573       break;
1574     case GL_COLOR_ARRAY:
1575       glEnableVertexAttribArray (COGL_GLES2_WRAPPER_COLOR_ATTRIB);
1576       break;
1577     case GL_NORMAL_ARRAY:
1578       glEnableVertexAttribArray (COGL_GLES2_WRAPPER_NORMAL_ATTRIB);
1579       break;
1580     }
1581 }
1582
1583 void
1584 _cogl_wrap_glDisableClientState (GLenum array)
1585 {
1586   CoglGles2WrapperTextureUnit *texture_unit;
1587   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1588
1589   switch (array)
1590     {
1591     case GL_VERTEX_ARRAY:
1592       glDisableVertexAttribArray (COGL_GLES2_WRAPPER_VERTEX_ATTRIB);
1593       break;
1594     case GL_TEXTURE_COORD_ARRAY:
1595
1596       texture_unit = w->texture_units + w->active_texture_unit;
1597       /* TODO - review if this should be in w->settings? */
1598       if (texture_unit->texture_coords_enabled != 0)
1599         {
1600           texture_unit->texture_coords_enabled = 0;
1601           w->dirty_vertex_attrib_enables
1602             |= COGL_GLES2_DIRTY_TEX_COORD_ATTRIB_ENABLES;
1603         }
1604       break;
1605     case GL_COLOR_ARRAY:
1606       glDisableVertexAttribArray (COGL_GLES2_WRAPPER_COLOR_ATTRIB);
1607       break;
1608     case GL_NORMAL_ARRAY:
1609       glDisableVertexAttribArray (COGL_GLES2_WRAPPER_NORMAL_ATTRIB);
1610       break;
1611     }
1612 }
1613
1614 void
1615 _cogl_wrap_glAlphaFunc (GLenum func, GLclampf ref)
1616 {
1617   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1618
1619   if (ref < 0.0f)
1620     ref = 0.0f;
1621   else if (ref > 1.0f)
1622     ref = 1.0f;
1623
1624   _COGL_GLES2_CHANGE_SETTING (w, alpha_test_func, func);
1625   _COGL_GLES2_CHANGE_UNIFORM (w, ALPHA_TEST_REF, alpha_test_ref, ref);
1626 }
1627
1628 void
1629 _cogl_wrap_glColor4f (GLclampf r, GLclampf g, GLclampf b, GLclampf a)
1630 {
1631   glVertexAttrib4f (COGL_GLES2_WRAPPER_COLOR_ATTRIB, r, g, b, a);
1632 }
1633
1634 void
1635 _cogl_wrap_glColor4ub (GLubyte r, GLubyte g, GLubyte b, GLubyte a)
1636 {
1637   glVertexAttrib4f (COGL_GLES2_WRAPPER_COLOR_ATTRIB,
1638                     r/255.0, g/255.0, b/255.0, a/255.0);
1639 }
1640
1641 void
1642 _cogl_wrap_glClipPlanef (GLenum plane, GLfloat *equation)
1643 {
1644   /* FIXME */
1645 }
1646
1647 void
1648 _cogl_wrap_glGetIntegerv (GLenum pname, GLint *params)
1649 {
1650   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1651
1652   switch (pname)
1653     {
1654     case GL_MAX_CLIP_PLANES:
1655       *params = 0;
1656       break;
1657
1658     case GL_MATRIX_MODE:
1659       *params = w->matrix_mode;
1660       break;
1661
1662     case GL_MAX_TEXTURE_UNITS:
1663       glGetIntegerv (GL_MAX_TEXTURE_IMAGE_UNITS, params);
1664       if (*params > COGL_GLES2_MAX_TEXTURE_UNITS)
1665         *params = COGL_GLES2_MAX_TEXTURE_UNITS;
1666       break;
1667
1668     default:
1669       glGetIntegerv (pname, params);
1670       break;
1671     }
1672 }
1673
1674 void
1675 _cogl_wrap_glGetFloatv (GLenum pname, GLfloat *params)
1676 {
1677   CoglGles2WrapperTextureUnit *texture_unit;
1678
1679   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1680
1681   switch (pname)
1682     {
1683     case GL_MODELVIEW_MATRIX:
1684       memcpy (params, &w->modelview_matrix, sizeof (GLfloat) * 16);
1685       break;
1686
1687     case GL_PROJECTION_MATRIX:
1688       memcpy (params, &w->projection_matrix, sizeof (GLfloat) * 16);
1689       break;
1690
1691     case GL_TEXTURE_MATRIX:
1692       texture_unit = w->texture_units + w->active_texture_unit;
1693       memcpy (params, &texture_unit->texture_matrix, sizeof (GLfloat) * 16);
1694       break;
1695
1696     case GL_VIEWPORT:
1697       glGetFloatv (GL_VIEWPORT, params);
1698       break;
1699     }
1700 }
1701
1702 void
1703 _cogl_wrap_glFogf (GLenum pname, GLfloat param)
1704 {
1705   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1706
1707   switch (pname)
1708     {
1709     case GL_FOG_MODE:
1710       _COGL_GLES2_CHANGE_SETTING (w, fog_mode, param);
1711       break;
1712
1713     case GL_FOG_DENSITY:
1714       _COGL_GLES2_CHANGE_UNIFORM (w, FOG_DENSITY, fog_density,
1715                                    (param));
1716       break;
1717
1718     case GL_FOG_START:
1719       _COGL_GLES2_CHANGE_UNIFORM (w, FOG_START, fog_start,
1720                                    (param));
1721       break;
1722
1723     case GL_FOG_END:
1724       _COGL_GLES2_CHANGE_UNIFORM (w, FOG_END, fog_end,
1725                                    (param));
1726       break;
1727     }
1728 }
1729
1730 void
1731 _cogl_wrap_glFogfv (GLenum pname, const GLfloat *params)
1732 {
1733   int i;
1734   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1735
1736   if (pname == GL_FOG_COLOR)
1737     {
1738       for (i = 0; i < 4; i++)
1739         w->fog_color[i] =  (params[i]);
1740
1741       w->dirty_uniforms |= COGL_GLES2_DIRTY_FOG_COLOR;
1742     }
1743 }
1744
1745 void
1746 _cogl_wrap_glTexParameteri (GLenum target, GLenum pname, GLfloat param)
1747 {
1748   if (pname != GL_GENERATE_MIPMAP)
1749     glTexParameteri (target, pname, param);
1750 }
1751
1752 void
1753 _cogl_wrap_glMaterialfv (GLenum face, GLenum pname, const GLfloat *params)
1754 {
1755   /* FIXME: the GLES 2 backend doesn't yet support lighting so this
1756      function can't do anything */
1757 }
1758
1759 void
1760 _cogl_wrap_glPointSize (GLfloat size)
1761 {
1762   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1763
1764   w->point_size = size;
1765   w->dirty_uniforms |= COGL_GLES2_DIRTY_POINT_SIZE;
1766 }
1767
1768 void
1769 _cogl_gles2_clear_cache_for_program (CoglHandle user_program)
1770 {
1771   GSList *node, *next, *last = NULL;
1772   CoglGles2WrapperProgram *program;
1773
1774   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
1775
1776   /* Remove any cached programs that link against this custom program */
1777   for (node = w->compiled_programs; node; node = next)
1778     {
1779       next = node->next;
1780       program = (CoglGles2WrapperProgram *) node->data;
1781
1782       if (program->settings.user_program == user_program)
1783         {
1784           glDeleteProgram (program->program);
1785
1786           if (last)
1787             last->next = next;
1788           else
1789             w->compiled_programs = next;
1790
1791           g_slist_free1 (node);
1792         }
1793       else
1794         last = node;
1795     }
1796 }