1 /*
2  * Cogl
3  *
4  * A Low Level GPU Graphics and Utilities API
5  *
6  * Copyright (C) 2008,2009,2010 Intel Corporation.
7  *
8  * Permission is hereby granted, free of charge, to any person
9  * obtaining a copy of this software and associated documentation
10  * files (the "Software"), to deal in the Software without
11  * restriction, including without limitation the rights to use, copy,
12  * modify, merge, publish, distribute, sublicense, and/or sell copies
13  * of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be
17  * included in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26  * SOFTWARE.
27  *
28  *
29  *
30  * Authors:
31  *   Robert Bragg <robert@linux.intel.com>
32  */
33 
34 #include "cogl-config.h"
35 
36 #include "cogl-debug.h"
37 #include "cogl-util-gl-private.h"
38 #include "cogl-pipeline-opengl-private.h"
39 #include "cogl-pipeline-private.h"
40 #include "cogl-context-private.h"
41 #include "cogl-texture-private.h"
42 #include "cogl-framebuffer-private.h"
43 #include "cogl-offscreen.h"
44 #include "cogl-texture-gl-private.h"
45 
46 #include "cogl-pipeline-progend-glsl-private.h"
47 
48 #include <test-fixtures/test-unit.h>
49 
50 #include <glib.h>
51 #include <string.h>
52 
53 /*
54  * GL/GLES compatability defines for pipeline thingies:
55  */
56 
57 /* These aren't defined in the GLES headers */
58 #ifndef GL_POINT_SPRITE
59 #define GL_POINT_SPRITE 0x8861
60 #endif
61 #ifndef GL_COORD_REPLACE
62 #define GL_COORD_REPLACE 0x8862
63 #endif
64 #ifndef GL_CLAMP_TO_BORDER
65 #define GL_CLAMP_TO_BORDER 0x812d
66 #endif
67 #ifndef GL_PROGRAM_POINT_SIZE
68 #define GL_PROGRAM_POINT_SIZE 0x8642
69 #endif
70 
71 static void
texture_unit_init(CoglContext * ctx,CoglTextureUnit * unit,int index_)72 texture_unit_init (CoglContext *ctx,
73                    CoglTextureUnit *unit,
74                    int index_)
75 {
76   unit->index = index_;
77   unit->enabled_gl_target = 0;
78   unit->gl_texture = 0;
79   unit->gl_target = 0;
80   unit->is_foreign = FALSE;
81   unit->dirty_gl_texture = FALSE;
82   unit->matrix_stack = cogl_matrix_stack_new (ctx);
83 
84   unit->layer = NULL;
85   unit->layer_changes_since_flush = 0;
86   unit->texture_storage_changed = FALSE;
87 }
88 
89 static void
texture_unit_free(CoglTextureUnit * unit)90 texture_unit_free (CoglTextureUnit *unit)
91 {
92   if (unit->layer)
93     cogl_object_unref (unit->layer);
94   cogl_object_unref (unit->matrix_stack);
95 }
96 
97 CoglTextureUnit *
_cogl_get_texture_unit(int index_)98 _cogl_get_texture_unit (int index_)
99 {
100   _COGL_GET_CONTEXT (ctx, NULL);
101 
102   if (ctx->texture_units->len < (index_ + 1))
103     {
104       int i;
105       int prev_len = ctx->texture_units->len;
106       ctx->texture_units = g_array_set_size (ctx->texture_units, index_ + 1);
107       for (i = prev_len; i <= index_; i++)
108         {
109           CoglTextureUnit *unit =
110             &g_array_index (ctx->texture_units, CoglTextureUnit, i);
111 
112           texture_unit_init (ctx, unit, i);
113         }
114     }
115 
116   return &g_array_index (ctx->texture_units, CoglTextureUnit, index_);
117 }
118 
119 void
_cogl_destroy_texture_units(void)120 _cogl_destroy_texture_units (void)
121 {
122   int i;
123 
124   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
125 
126   for (i = 0; i < ctx->texture_units->len; i++)
127     {
128       CoglTextureUnit *unit =
129         &g_array_index (ctx->texture_units, CoglTextureUnit, i);
130       texture_unit_free (unit);
131     }
132   g_array_free (ctx->texture_units, TRUE);
133 }
134 
135 void
_cogl_set_active_texture_unit(int unit_index)136 _cogl_set_active_texture_unit (int unit_index)
137 {
138   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
139 
140   if (ctx->active_texture_unit != unit_index)
141     {
142       GE (ctx, glActiveTexture (GL_TEXTURE0 + unit_index));
143       ctx->active_texture_unit = unit_index;
144     }
145 }
146 
147 /* Note: _cogl_bind_gl_texture_transient conceptually has slightly
148  * different semantics to OpenGL's glBindTexture because Cogl never
149  * cares about tracking multiple textures bound to different targets
150  * on the same texture unit.
151  *
152  * glBindTexture lets you bind multiple textures to a single texture
153  * unit if they are bound to different targets. So it does something
154  * like:
155  *   unit->current_texture[target] = texture;
156  *
157  * Cogl only lets you associate one texture with the currently active
158  * texture unit, so the target is basically a redundant parameter
159  * that's implicitly set on that texture.
160  *
161  * Technically this is just a thin wrapper around glBindTexture so
162  * actually it does have the GL semantics but it seems worth
163  * mentioning the conceptual difference in case anyone wonders why we
164  * don't associate the gl_texture with a gl_target in the
165  * CoglTextureUnit.
166  */
167 void
_cogl_bind_gl_texture_transient(GLenum gl_target,GLuint gl_texture,CoglBool is_foreign)168 _cogl_bind_gl_texture_transient (GLenum gl_target,
169                                  GLuint gl_texture,
170                                  CoglBool is_foreign)
171 {
172   CoglTextureUnit *unit;
173 
174   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
175 
176   /* We choose to always make texture unit 1 active for transient
177    * binds so that in the common case where multitexturing isn't used
178    * we can simply ignore the state of this texture unit. Notably we
179    * didn't use a large texture unit (.e.g. (GL_MAX_TEXTURE_UNITS - 1)
180    * in case the driver doesn't have a sparse data structure for
181    * texture units.
182    */
183   _cogl_set_active_texture_unit (1);
184   unit = _cogl_get_texture_unit (1);
185 
186   /* NB: If we have previously bound a foreign texture to this texture
187    * unit we don't know if that texture has since been deleted and we
188    * are seeing the texture name recycled */
189   if (unit->gl_texture == gl_texture &&
190       !unit->dirty_gl_texture &&
191       !unit->is_foreign)
192     return;
193 
194   GE (ctx, glBindTexture (gl_target, gl_texture));
195 
196   unit->dirty_gl_texture = TRUE;
197   unit->is_foreign = is_foreign;
198 }
199 
200 void
_cogl_delete_gl_texture(GLuint gl_texture)201 _cogl_delete_gl_texture (GLuint gl_texture)
202 {
203   int i;
204 
205   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
206 
207   for (i = 0; i < ctx->texture_units->len; i++)
208     {
209       CoglTextureUnit *unit =
210         &g_array_index (ctx->texture_units, CoglTextureUnit, i);
211 
212       if (unit->gl_texture == gl_texture)
213         {
214           unit->gl_texture = 0;
215           unit->gl_target = 0;
216           unit->dirty_gl_texture = FALSE;
217         }
218     }
219 
220   GE (ctx, glDeleteTextures (1, &gl_texture));
221 }
222 
223 /* Whenever the underlying GL texture storage of a CoglTexture is
224  * changed (e.g. due to migration out of a texture atlas) then we are
225  * notified. This lets us ensure that we reflush that texture's state
226  * if it is reused again with the same texture unit.
227  */
228 void
_cogl_pipeline_texture_storage_change_notify(CoglTexture * texture)229 _cogl_pipeline_texture_storage_change_notify (CoglTexture *texture)
230 {
231   int i;
232 
233   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
234 
235   for (i = 0; i < ctx->texture_units->len; i++)
236     {
237       CoglTextureUnit *unit =
238         &g_array_index (ctx->texture_units, CoglTextureUnit, i);
239 
240       if (unit->layer &&
241           _cogl_pipeline_layer_get_texture (unit->layer) == texture)
242         unit->texture_storage_changed = TRUE;
243 
244       /* NB: the texture may be bound to multiple texture units so
245        * we continue to check the rest */
246     }
247 }
248 
249 static void
set_glsl_program(GLuint gl_program)250 set_glsl_program (GLuint gl_program)
251 {
252   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
253 
254   if (ctx->current_gl_program != gl_program)
255     {
256       _cogl_gl_util_clear_gl_errors (ctx);
257       ctx->glUseProgram (gl_program);
258       if (_cogl_gl_util_get_error (ctx) == GL_NO_ERROR)
259         ctx->current_gl_program = gl_program;
260       else
261         {
262           GE( ctx, glUseProgram (0) );
263           ctx->current_gl_program = 0;
264         }
265     }
266 }
267 
268 void
_cogl_use_fragment_program(GLuint gl_program,CoglPipelineProgramType type)269 _cogl_use_fragment_program (GLuint gl_program, CoglPipelineProgramType type)
270 {
271   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
272 
273   /* If we're changing program type... */
274   if (type != ctx->current_fragment_program_type)
275     {
276       /* ... disable the old type */
277       switch (ctx->current_fragment_program_type)
278         {
279         case COGL_PIPELINE_PROGRAM_TYPE_GLSL:
280           /* If the program contains a vertex shader then we shouldn't
281              disable it */
282           if (ctx->current_vertex_program_type !=
283               COGL_PIPELINE_PROGRAM_TYPE_GLSL)
284             set_glsl_program (0);
285           break;
286 
287         case COGL_PIPELINE_PROGRAM_TYPE_ARBFP:
288 #ifdef HAVE_COGL_GL
289           GE( ctx, glDisable (GL_FRAGMENT_PROGRAM_ARB) );
290 #endif
291           break;
292 
293         case COGL_PIPELINE_PROGRAM_TYPE_FIXED:
294           /* don't need to to anything */
295           break;
296         }
297 
298       /* ... and enable the new type */
299       switch (type)
300         {
301         case COGL_PIPELINE_PROGRAM_TYPE_ARBFP:
302 #ifdef HAVE_COGL_GL
303           GE( ctx, glEnable (GL_FRAGMENT_PROGRAM_ARB) );
304 #endif
305           break;
306 
307         case COGL_PIPELINE_PROGRAM_TYPE_GLSL:
308         case COGL_PIPELINE_PROGRAM_TYPE_FIXED:
309           /* don't need to to anything */
310           break;
311         }
312     }
313 
314   if (type == COGL_PIPELINE_PROGRAM_TYPE_GLSL)
315     {
316 #ifdef COGL_PIPELINE_FRAGEND_GLSL
317       set_glsl_program (gl_program);
318 
319 #else
320 
321       g_warning ("Unexpected use of GLSL fragend!");
322 
323 #endif /* COGL_PIPELINE_FRAGEND_GLSL */
324     }
325 #ifndef COGL_PIPELINE_FRAGEND_ARBFP
326   else if (type == COGL_PIPELINE_PROGRAM_TYPE_ARBFP)
327     g_warning ("Unexpected use of ARBFP fragend!");
328 #endif /* COGL_PIPELINE_FRAGEND_ARBFP */
329 
330   ctx->current_fragment_program_type = type;
331 }
332 
333 void
_cogl_use_vertex_program(GLuint gl_program,CoglPipelineProgramType type)334 _cogl_use_vertex_program (GLuint gl_program, CoglPipelineProgramType type)
335 {
336   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
337 
338   /* If we're changing program type... */
339   if (type != ctx->current_vertex_program_type)
340     {
341       /* ... disable the old type */
342       switch (ctx->current_vertex_program_type)
343         {
344         case COGL_PIPELINE_PROGRAM_TYPE_GLSL:
345           /* If the program contains a fragment shader then we shouldn't
346              disable it */
347           if (ctx->current_fragment_program_type !=
348               COGL_PIPELINE_PROGRAM_TYPE_GLSL)
349             set_glsl_program (0);
350           break;
351 
352         case COGL_PIPELINE_PROGRAM_TYPE_ARBFP:
353           /* It doesn't make sense to enable ARBfp for the vertex program */
354           g_assert_not_reached ();
355           break;
356 
357         case COGL_PIPELINE_PROGRAM_TYPE_FIXED:
358           /* don't need to to anything */
359           break;
360         }
361 
362       /* ... and enable the new type */
363       switch (type)
364         {
365         case COGL_PIPELINE_PROGRAM_TYPE_ARBFP:
366           /* It doesn't make sense to enable ARBfp for the vertex program */
367           g_assert_not_reached ();
368           break;
369 
370         case COGL_PIPELINE_PROGRAM_TYPE_GLSL:
371         case COGL_PIPELINE_PROGRAM_TYPE_FIXED:
372           /* don't need to to anything */
373           break;
374         }
375     }
376 
377   if (type == COGL_PIPELINE_PROGRAM_TYPE_GLSL)
378     {
379 #ifdef COGL_PIPELINE_VERTEND_GLSL
380       set_glsl_program (gl_program);
381 
382 #else
383 
384       g_warning ("Unexpected use of GLSL vertend!");
385 
386 #endif /* COGL_PIPELINE_VERTEND_GLSL */
387     }
388 #ifndef COGL_PIPELINE_VERTEND_ARBFP
389   else if (type == COGL_PIPELINE_PROGRAM_TYPE_ARBFP)
390     g_warning ("Unexpected use of ARBFP vertend!");
391 #endif /* COGL_PIPELINE_VERTEND_ARBFP */
392 
393   ctx->current_vertex_program_type = type;
394 }
395 
396 #if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL)
397 
398 static CoglBool
blend_factor_uses_constant(GLenum blend_factor)399 blend_factor_uses_constant (GLenum blend_factor)
400 {
401   return (blend_factor == GL_CONSTANT_COLOR ||
402           blend_factor == GL_ONE_MINUS_CONSTANT_COLOR ||
403           blend_factor == GL_CONSTANT_ALPHA ||
404           blend_factor == GL_ONE_MINUS_CONSTANT_ALPHA);
405 }
406 
407 #endif
408 
409 static void
flush_depth_state(CoglContext * ctx,CoglDepthState * depth_state)410 flush_depth_state (CoglContext *ctx,
411                    CoglDepthState *depth_state)
412 {
413   CoglBool depth_writing_enabled = depth_state->write_enabled;
414 
415   if (ctx->current_draw_buffer)
416     depth_writing_enabled &= ctx->current_draw_buffer->depth_writing_enabled;
417 
418   if (ctx->depth_test_enabled_cache != depth_state->test_enabled)
419     {
420       if (depth_state->test_enabled == TRUE)
421         GE (ctx, glEnable (GL_DEPTH_TEST));
422       else
423         GE (ctx, glDisable (GL_DEPTH_TEST));
424       ctx->depth_test_enabled_cache = depth_state->test_enabled;
425     }
426 
427   if (ctx->depth_test_function_cache != depth_state->test_function &&
428       depth_state->test_enabled == TRUE)
429     {
430       GE (ctx, glDepthFunc (depth_state->test_function));
431       ctx->depth_test_function_cache = depth_state->test_function;
432     }
433 
434   if (ctx->depth_writing_enabled_cache != depth_writing_enabled)
435     {
436       GE (ctx, glDepthMask (depth_writing_enabled ?
437                             GL_TRUE : GL_FALSE));
438       ctx->depth_writing_enabled_cache = depth_writing_enabled;
439     }
440 
441   if (ctx->driver != COGL_DRIVER_GLES1 &&
442       (ctx->depth_range_near_cache != depth_state->range_near ||
443        ctx->depth_range_far_cache != depth_state->range_far))
444     {
445       if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_EMBEDDED))
446         GE (ctx, glDepthRangef (depth_state->range_near,
447                                 depth_state->range_far));
448       else
449         GE (ctx, glDepthRange (depth_state->range_near,
450                                depth_state->range_far));
451 
452       ctx->depth_range_near_cache = depth_state->range_near;
453       ctx->depth_range_far_cache = depth_state->range_far;
454     }
455 }
456 
457 UNIT_TEST (check_gl_blend_enable,
458            0 /* no requirements */,
459            0 /* no failure cases */)
460 {
461   CoglPipeline *pipeline = cogl_pipeline_new (test_ctx);
462 
463   /* By default blending should be disabled */
464   g_assert_cmpint (test_ctx->gl_blend_enable_cache, ==, 0);
465 
466   cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 1, 1);
467   _cogl_framebuffer_flush_journal (test_fb);
468 
469   /* After drawing an opaque rectangle blending should still be
470    * disabled */
471   g_assert_cmpint (test_ctx->gl_blend_enable_cache, ==, 0);
472 
473   cogl_pipeline_set_color4f (pipeline, 0, 0, 0, 0);
474   cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 1, 1);
475   _cogl_framebuffer_flush_journal (test_fb);
476 
477   /* After drawing a transparent rectangle blending should be enabled */
478   g_assert_cmpint (test_ctx->gl_blend_enable_cache, ==, 1);
479 
480   cogl_pipeline_set_blend (pipeline, "RGBA=ADD(SRC_COLOR, 0)", NULL);
481   cogl_framebuffer_draw_rectangle (test_fb, pipeline, 0, 0, 1, 1);
482   _cogl_framebuffer_flush_journal (test_fb);
483 
484   /* After setting a blend string that effectively disables blending
485    * then blending should be disabled */
486   g_assert_cmpint (test_ctx->gl_blend_enable_cache, ==, 0);
487 }
488 
489 static void
_cogl_pipeline_flush_color_blend_alpha_depth_state(CoglPipeline * pipeline,unsigned long pipelines_difference,CoglBool with_color_attrib)490 _cogl_pipeline_flush_color_blend_alpha_depth_state (
491                                             CoglPipeline *pipeline,
492                                             unsigned long pipelines_difference,
493                                             CoglBool      with_color_attrib)
494 {
495   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
496 
497   /* On GLES2 we'll flush the color later */
498   if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_FIXED) &&
499       !with_color_attrib)
500     {
501       if ((pipelines_difference & COGL_PIPELINE_STATE_COLOR) ||
502           /* Assume if we were previously told to skip the color, then
503            * the current color needs updating... */
504           ctx->current_pipeline_with_color_attrib)
505         {
506           CoglPipeline *authority =
507             _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR);
508           GE (ctx, glColor4ub (cogl_color_get_red_byte (&authority->color),
509                                cogl_color_get_green_byte (&authority->color),
510                                cogl_color_get_blue_byte (&authority->color),
511                                cogl_color_get_alpha_byte (&authority->color)));
512         }
513     }
514 
515   if (pipelines_difference & COGL_PIPELINE_STATE_BLEND)
516     {
517       CoglPipeline *authority =
518         _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_BLEND);
519       CoglPipelineBlendState *blend_state =
520         &authority->big_state->blend_state;
521 
522       /* GLES 1 only has glBlendFunc */
523       if (ctx->driver == COGL_DRIVER_GLES1)
524         {
525           GE (ctx, glBlendFunc (blend_state->blend_src_factor_rgb,
526                                 blend_state->blend_dst_factor_rgb));
527         }
528 #if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL)
529       else
530         {
531           if (blend_factor_uses_constant (blend_state->blend_src_factor_rgb) ||
532               blend_factor_uses_constant (blend_state
533                                           ->blend_src_factor_alpha) ||
534               blend_factor_uses_constant (blend_state->blend_dst_factor_rgb) ||
535               blend_factor_uses_constant (blend_state->blend_dst_factor_alpha))
536             {
537               float red =
538                 cogl_color_get_red_float (&blend_state->blend_constant);
539               float green =
540                 cogl_color_get_green_float (&blend_state->blend_constant);
541               float blue =
542                 cogl_color_get_blue_float (&blend_state->blend_constant);
543               float alpha =
544                 cogl_color_get_alpha_float (&blend_state->blend_constant);
545 
546 
547               GE (ctx, glBlendColor (red, green, blue, alpha));
548             }
549 
550           if (ctx->glBlendEquationSeparate &&
551               blend_state->blend_equation_rgb !=
552               blend_state->blend_equation_alpha)
553             GE (ctx,
554                 glBlendEquationSeparate (blend_state->blend_equation_rgb,
555                                          blend_state->blend_equation_alpha));
556           else
557             GE (ctx, glBlendEquation (blend_state->blend_equation_rgb));
558 
559           if (ctx->glBlendFuncSeparate &&
560               (blend_state->blend_src_factor_rgb !=
561                blend_state->blend_src_factor_alpha ||
562                (blend_state->blend_dst_factor_rgb !=
563                 blend_state->blend_dst_factor_alpha)))
564             GE (ctx, glBlendFuncSeparate (blend_state->blend_src_factor_rgb,
565                                           blend_state->blend_dst_factor_rgb,
566                                           blend_state->blend_src_factor_alpha,
567                                           blend_state->blend_dst_factor_alpha));
568           else
569             GE (ctx, glBlendFunc (blend_state->blend_src_factor_rgb,
570                                   blend_state->blend_dst_factor_rgb));
571         }
572 #endif
573     }
574 
575 #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
576 
577   if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_ALPHA_TEST))
578     {
579       /* Under GLES2 the alpha function is implemented as part of the
580          fragment shader */
581       if (pipelines_difference & (COGL_PIPELINE_STATE_ALPHA_FUNC |
582                                   COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE))
583         {
584           CoglPipeline *authority =
585             _cogl_pipeline_get_authority (pipeline,
586                                           COGL_PIPELINE_STATE_ALPHA_FUNC);
587           CoglPipelineAlphaFuncState *alpha_state =
588             &authority->big_state->alpha_state;
589 
590           /* NB: Currently the Cogl defines are compatible with the GL ones: */
591           GE (ctx, glAlphaFunc (alpha_state->alpha_func,
592                                 alpha_state->alpha_func_reference));
593         }
594 
595       /* Under GLES2 the lighting parameters are implemented as uniforms
596          in the progend */
597       if (pipelines_difference & COGL_PIPELINE_STATE_LIGHTING)
598         {
599           CoglPipeline *authority =
600             _cogl_pipeline_get_authority (pipeline,
601                                           COGL_PIPELINE_STATE_LIGHTING);
602           CoglPipelineLightingState *lighting_state =
603             &authority->big_state->lighting_state;
604 
605           GE (ctx, glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT,
606                                  lighting_state->ambient));
607           GE (ctx, glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE,
608                                  lighting_state->diffuse));
609           GE (ctx, glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR,
610                                  lighting_state->specular));
611           GE (ctx, glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION,
612                                  lighting_state->emission));
613           GE (ctx, glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS,
614                                  &lighting_state->shininess));
615         }
616     }
617 
618 #endif
619 
620   if (pipelines_difference & COGL_PIPELINE_STATE_DEPTH)
621     {
622       CoglPipeline *authority =
623         _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_DEPTH);
624       CoglDepthState *depth_state = &authority->big_state->depth_state;
625 
626       flush_depth_state (ctx, depth_state);
627     }
628 
629   if (pipelines_difference & COGL_PIPELINE_STATE_LOGIC_OPS)
630     {
631       CoglPipeline *authority =
632         _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LOGIC_OPS);
633       CoglPipelineLogicOpsState *logic_ops_state = &authority->big_state->logic_ops_state;
634       CoglColorMask color_mask = logic_ops_state->color_mask;
635 
636       if (ctx->current_draw_buffer)
637         color_mask &= ctx->current_draw_buffer->color_mask;
638 
639       GE (ctx, glColorMask (!!(color_mask & COGL_COLOR_MASK_RED),
640                             !!(color_mask & COGL_COLOR_MASK_GREEN),
641                             !!(color_mask & COGL_COLOR_MASK_BLUE),
642                             !!(color_mask & COGL_COLOR_MASK_ALPHA)));
643       ctx->current_gl_color_mask = color_mask;
644     }
645 
646   if (pipelines_difference & COGL_PIPELINE_STATE_CULL_FACE)
647     {
648       CoglPipeline *authority =
649         _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_CULL_FACE);
650       CoglPipelineCullFaceState *cull_face_state
651         = &authority->big_state->cull_face_state;
652 
653       if (cull_face_state->mode == COGL_PIPELINE_CULL_FACE_MODE_NONE)
654         GE( ctx, glDisable (GL_CULL_FACE) );
655       else
656         {
657           CoglBool invert_winding;
658 
659           GE( ctx, glEnable (GL_CULL_FACE) );
660 
661           switch (cull_face_state->mode)
662             {
663             case COGL_PIPELINE_CULL_FACE_MODE_NONE:
664               g_assert_not_reached ();
665 
666             case COGL_PIPELINE_CULL_FACE_MODE_FRONT:
667               GE( ctx, glCullFace (GL_FRONT) );
668               break;
669 
670             case COGL_PIPELINE_CULL_FACE_MODE_BACK:
671               GE( ctx, glCullFace (GL_BACK) );
672               break;
673 
674             case COGL_PIPELINE_CULL_FACE_MODE_BOTH:
675               GE( ctx, glCullFace (GL_FRONT_AND_BACK) );
676               break;
677             }
678 
679           /* If we are painting to an offscreen framebuffer then we
680              need to invert the winding of the front face because
681              everything is painted upside down */
682           invert_winding = cogl_is_offscreen (ctx->current_draw_buffer);
683 
684           switch (cull_face_state->front_winding)
685             {
686             case COGL_WINDING_CLOCKWISE:
687               GE( ctx, glFrontFace (invert_winding ? GL_CCW : GL_CW) );
688               break;
689 
690             case COGL_WINDING_COUNTER_CLOCKWISE:
691               GE( ctx, glFrontFace (invert_winding ? GL_CW : GL_CCW) );
692               break;
693             }
694         }
695     }
696 
697 #ifdef HAVE_COGL_GL
698   if (_cogl_has_private_feature
699       (ctx, COGL_PRIVATE_FEATURE_ENABLE_PROGRAM_POINT_SIZE) &&
700       (pipelines_difference & COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE))
701     {
702       unsigned long state = COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE;
703       CoglPipeline *authority = _cogl_pipeline_get_authority (pipeline, state);
704 
705       if (authority->big_state->per_vertex_point_size)
706         GE( ctx, glEnable (GL_PROGRAM_POINT_SIZE) );
707       else
708         GE( ctx, glDisable (GL_PROGRAM_POINT_SIZE) );
709     }
710 #endif
711 
712   if (pipeline->real_blend_enable != ctx->gl_blend_enable_cache)
713     {
714       if (pipeline->real_blend_enable)
715         GE (ctx, glEnable (GL_BLEND));
716       else
717         GE (ctx, glDisable (GL_BLEND));
718       /* XXX: we shouldn't update any other blend state if blending
719        * is disabled! */
720       ctx->gl_blend_enable_cache = pipeline->real_blend_enable;
721     }
722 }
723 
724 static int
get_max_activateable_texture_units(void)725 get_max_activateable_texture_units (void)
726 {
727   _COGL_GET_CONTEXT (ctx, 0);
728 
729   if (G_UNLIKELY (ctx->max_activateable_texture_units == -1))
730     {
731       GLint values[3];
732       int n_values = 0;
733       int i;
734 
735 #ifdef HAVE_COGL_GL
736       if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_EMBEDDED))
737         {
738           /* GL_MAX_TEXTURE_COORDS is provided for both GLSL and ARBfp. It
739              defines the number of texture coordinates that can be
740              uploaded (but doesn't necessarily relate to how many texture
741              images can be sampled) */
742           if (cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL) ||
743               cogl_has_feature (ctx, COGL_FEATURE_ID_ARBFP))
744             /* Previously this code subtracted the value by one but there
745                was no explanation for why it did this and it doesn't seem
746                to make sense so it has been removed */
747             GE (ctx, glGetIntegerv (GL_MAX_TEXTURE_COORDS,
748                                     values + n_values++));
749 
750           /* GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS is defined for GLSL but
751              not ARBfp */
752           if (cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL))
753             GE (ctx, glGetIntegerv (GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
754                                     values + n_values++));
755         }
756 #endif /* HAVE_COGL_GL */
757 
758 #ifdef HAVE_COGL_GLES2
759       if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_EMBEDDED) &&
760           _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_PROGRAMMABLE))
761         {
762           GE (ctx, glGetIntegerv (GL_MAX_VERTEX_ATTRIBS, values + n_values));
763           /* Two of the vertex attribs need to be used for the position
764              and color */
765           values[n_values++] -= 2;
766 
767           GE (ctx, glGetIntegerv (GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
768                                   values + n_values++));
769         }
770 #endif
771 
772 #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
773       if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_FIXED))
774         {
775           /* GL_MAX_TEXTURE_UNITS defines the number of units that are
776              usable from the fixed function pipeline, therefore it isn't
777              available in GLES2. These are also tied to the number of
778              texture coordinates that can be uploaded so it should be less
779              than that available from the shader extensions */
780           GE (ctx, glGetIntegerv (GL_MAX_TEXTURE_UNITS,
781                                   values + n_values++));
782 
783         }
784 #endif
785 
786       g_assert (n_values <= G_N_ELEMENTS (values) &&
787                 n_values > 0);
788 
789       /* Use the maximum value */
790       ctx->max_activateable_texture_units = values[0];
791       for (i = 1; i < n_values; i++)
792         ctx->max_activateable_texture_units =
793           MAX (values[i], ctx->max_activateable_texture_units);
794     }
795 
796   return ctx->max_activateable_texture_units;
797 }
798 
799 typedef struct
800 {
801   int i;
802   unsigned long *layer_differences;
803 } CoglPipelineFlushLayerState;
804 
805 static CoglBool
flush_layers_common_gl_state_cb(CoglPipelineLayer * layer,void * user_data)806 flush_layers_common_gl_state_cb (CoglPipelineLayer *layer, void *user_data)
807 {
808   CoglPipelineFlushLayerState *flush_state = user_data;
809   int                          unit_index = flush_state->i;
810   CoglTextureUnit             *unit = _cogl_get_texture_unit (unit_index);
811   unsigned long                layers_difference =
812     flush_state->layer_differences[unit_index];
813 
814   _COGL_GET_CONTEXT (ctx, FALSE);
815 
816   /* There may not be enough texture units so we can bail out if
817    * that's the case...
818    */
819   if (G_UNLIKELY (unit_index >= get_max_activateable_texture_units ()))
820     {
821       static CoglBool shown_warning = FALSE;
822 
823       if (!shown_warning)
824         {
825           g_warning ("Your hardware does not have enough texture units"
826                      "to handle this many texture layers");
827           shown_warning = TRUE;
828         }
829       return FALSE;
830     }
831 
832   if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA)
833     {
834       CoglTexture *texture = _cogl_pipeline_layer_get_texture_real (layer);
835       GLuint gl_texture;
836       GLenum gl_target;
837 
838       if (texture == NULL)
839         switch (_cogl_pipeline_layer_get_texture_type (layer))
840           {
841           case COGL_TEXTURE_TYPE_2D:
842             texture = COGL_TEXTURE (ctx->default_gl_texture_2d_tex);
843             break;
844           case COGL_TEXTURE_TYPE_3D:
845             texture = COGL_TEXTURE (ctx->default_gl_texture_3d_tex);
846             break;
847           case COGL_TEXTURE_TYPE_RECTANGLE:
848             texture = COGL_TEXTURE (ctx->default_gl_texture_rect_tex);
849             break;
850           }
851 
852       cogl_texture_get_gl_texture (texture,
853                                    &gl_texture,
854                                    &gl_target);
855 
856       _cogl_set_active_texture_unit (unit_index);
857 
858       /* NB: There are several Cogl components and some code in
859        * Clutter that will temporarily bind arbitrary GL textures to
860        * query and modify texture object parameters. If you look at
861        * _cogl_bind_gl_texture_transient() you can see we make sure
862        * that such code always binds to texture unit 1 which means we
863        * can't rely on the unit->gl_texture state if unit->index == 1.
864        *
865        * Because texture unit 1 is a bit special we actually defer any
866        * necessary glBindTexture for it until the end of
867        * _cogl_pipeline_flush_gl_state().
868        *
869        * NB: we get notified whenever glDeleteTextures is used (see
870        * _cogl_delete_gl_texture()) where we invalidate
871        * unit->gl_texture references to deleted textures so it's safe
872        * to compare unit->gl_texture with gl_texture.  (Without the
873        * hook it would be possible to delete a GL texture and create a
874        * new one with the same name and comparing unit->gl_texture and
875        * gl_texture wouldn't detect that.)
876        *
877        * NB: for foreign textures we don't know how the deletion of
878        * the GL texture objects correspond to the deletion of the
879        * CoglTextures so if there was previously a foreign texture
880        * associated with the texture unit then we can't assume that we
881        * aren't seeing a recycled texture name so we have to bind.
882        */
883       if (unit->gl_texture != gl_texture || unit->is_foreign)
884         {
885           if (unit_index == 1)
886             unit->dirty_gl_texture = TRUE;
887           else
888             GE (ctx, glBindTexture (gl_target, gl_texture));
889           unit->gl_texture = gl_texture;
890           unit->gl_target = gl_target;
891         }
892 
893       unit->is_foreign = _cogl_texture_is_foreign (texture);
894 
895       /* The texture_storage_changed boolean indicates if the
896        * CoglTexture's underlying GL texture storage has changed since
897        * it was flushed to the texture unit. We've just flushed the
898        * latest state so we can reset this. */
899       unit->texture_storage_changed = FALSE;
900     }
901 
902   if ((layers_difference & COGL_PIPELINE_LAYER_STATE_SAMPLER) &&
903       _cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS))
904     {
905       const CoglSamplerCacheEntry *sampler_state;
906 
907       sampler_state = _cogl_pipeline_layer_get_sampler_state (layer);
908 
909       GE( ctx, glBindSampler (unit_index, sampler_state->sampler_object) );
910     }
911 
912   /* FIXME: If using GLSL the progend we will use gl_PointCoord
913    * instead of us needing to replace the texture coordinates but at
914    * this point we can't currently tell if we are using the fixed or
915    * glsl progend.
916    */
917 #if defined (HAVE_COGL_GLES) || defined (HAVE_COGL_GL)
918   if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_FIXED) &&
919       (layers_difference & COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS))
920     {
921       CoglPipelineState change = COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS;
922       CoglPipelineLayer *authority =
923         _cogl_pipeline_layer_get_authority (layer, change);
924       CoglPipelineLayerBigState *big_state = authority->big_state;
925 
926       _cogl_set_active_texture_unit (unit_index);
927 
928       GE (ctx, glTexEnvi (GL_POINT_SPRITE, GL_COORD_REPLACE,
929                           big_state->point_sprite_coords));
930     }
931 #endif
932 
933   cogl_object_ref (layer);
934   if (unit->layer != NULL)
935     cogl_object_unref (unit->layer);
936 
937   unit->layer = layer;
938   unit->layer_changes_since_flush = 0;
939 
940   flush_state->i++;
941 
942   return TRUE;
943 }
944 
945 static void
_cogl_pipeline_flush_common_gl_state(CoglPipeline * pipeline,unsigned long pipelines_difference,unsigned long * layer_differences,CoglBool with_color_attrib)946 _cogl_pipeline_flush_common_gl_state (CoglPipeline  *pipeline,
947                                       unsigned long  pipelines_difference,
948                                       unsigned long *layer_differences,
949                                       CoglBool       with_color_attrib)
950 {
951   CoglPipelineFlushLayerState state;
952 
953   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
954 
955   _cogl_pipeline_flush_color_blend_alpha_depth_state (pipeline,
956                                                       pipelines_difference,
957                                                       with_color_attrib);
958 
959   state.i = 0;
960   state.layer_differences = layer_differences;
961   _cogl_pipeline_foreach_layer_internal (pipeline,
962                                          flush_layers_common_gl_state_cb,
963                                          &state);
964 }
965 
966 /* Re-assert the layer's wrap modes on the given CoglTexture.
967  *
968  * Note: we don't simply forward the wrap modes to layer->texture
969  * since the actual texture being used may have been overridden.
970  */
971 static void
_cogl_pipeline_layer_forward_wrap_modes(CoglPipelineLayer * layer,CoglTexture * texture)972 _cogl_pipeline_layer_forward_wrap_modes (CoglPipelineLayer *layer,
973                                          CoglTexture *texture)
974 {
975   CoglSamplerCacheWrapMode wrap_mode_s, wrap_mode_t, wrap_mode_p;
976   GLenum gl_wrap_mode_s, gl_wrap_mode_t, gl_wrap_mode_p;
977 
978   if (texture == NULL)
979     return;
980 
981   _cogl_pipeline_layer_get_wrap_modes (layer,
982                                        &wrap_mode_s,
983                                        &wrap_mode_t,
984                                        &wrap_mode_p);
985 
986   /* Update the wrap mode on the texture object. The texture backend
987      should cache the value so that it will be a no-op if the object
988      already has the same wrap mode set. The backend is best placed to
989      do this because it knows how many of the coordinates will
990      actually be used (ie, a 1D texture only cares about the 's'
991      coordinate but a 3D texture would use all three). GL uses the
992      wrap mode as part of the texture object state but we are
993      pretending it's part of the per-layer environment state. This
994      will break if the application tries to use different modes in
995      different layers using the same texture. */
996 
997   if (wrap_mode_s == COGL_SAMPLER_CACHE_WRAP_MODE_AUTOMATIC)
998     gl_wrap_mode_s = GL_CLAMP_TO_EDGE;
999   else
1000     gl_wrap_mode_s = wrap_mode_s;
1001 
1002   if (wrap_mode_t == COGL_SAMPLER_CACHE_WRAP_MODE_AUTOMATIC)
1003     gl_wrap_mode_t = GL_CLAMP_TO_EDGE;
1004   else
1005     gl_wrap_mode_t = wrap_mode_t;
1006 
1007   if (wrap_mode_p == COGL_SAMPLER_CACHE_WRAP_MODE_AUTOMATIC)
1008     gl_wrap_mode_p = GL_CLAMP_TO_EDGE;
1009   else
1010     gl_wrap_mode_p = wrap_mode_p;
1011 
1012   _cogl_texture_gl_flush_legacy_texobj_wrap_modes (texture,
1013                                                    gl_wrap_mode_s,
1014                                                    gl_wrap_mode_t,
1015                                                    gl_wrap_mode_p);
1016 }
1017 
1018 /* OpenGL associates the min/mag filters and repeat modes with the
1019  * texture object not the texture unit so we always have to re-assert
1020  * the filter and repeat modes whenever we use a texture since it may
1021  * be referenced by multiple pipelines with different modes.
1022  *
1023  * This function is bypassed in favour of sampler objects if
1024  * GL_ARB_sampler_objects is advertised. This fallback won't work if
1025  * the same texture is bound to multiple layers with different sampler
1026  * state.
1027  */
1028 static void
foreach_texture_unit_update_filter_and_wrap_modes(void)1029 foreach_texture_unit_update_filter_and_wrap_modes (void)
1030 {
1031   int i;
1032 
1033   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1034 
1035   for (i = 0; i < ctx->texture_units->len; i++)
1036     {
1037       CoglTextureUnit *unit =
1038         &g_array_index (ctx->texture_units, CoglTextureUnit, i);
1039 
1040       if (unit->layer)
1041         {
1042           CoglTexture *texture = _cogl_pipeline_layer_get_texture (unit->layer);
1043 
1044           if (texture != NULL)
1045             {
1046               CoglPipelineFilter min;
1047               CoglPipelineFilter mag;
1048 
1049               _cogl_pipeline_layer_get_filters (unit->layer, &min, &mag);
1050               _cogl_texture_gl_flush_legacy_texobj_filters (texture, min, mag);
1051 
1052               _cogl_pipeline_layer_forward_wrap_modes (unit->layer, texture);
1053             }
1054         }
1055     }
1056 }
1057 
1058 typedef struct
1059 {
1060   int i;
1061   unsigned long *layer_differences;
1062 } CoglPipelineCompareLayersState;
1063 
1064 static CoglBool
compare_layer_differences_cb(CoglPipelineLayer * layer,void * user_data)1065 compare_layer_differences_cb (CoglPipelineLayer *layer, void *user_data)
1066 {
1067   CoglPipelineCompareLayersState *state = user_data;
1068   CoglTextureUnit *unit = _cogl_get_texture_unit (state->i);
1069 
1070   if (unit->layer == layer)
1071     state->layer_differences[state->i] = unit->layer_changes_since_flush;
1072   else if (unit->layer)
1073     {
1074       state->layer_differences[state->i] = unit->layer_changes_since_flush;
1075       state->layer_differences[state->i] |=
1076         _cogl_pipeline_layer_compare_differences (layer, unit->layer);
1077     }
1078   else
1079     state->layer_differences[state->i] = COGL_PIPELINE_LAYER_STATE_ALL_SPARSE;
1080 
1081   /* XXX: There is always a possibility that a CoglTexture's
1082    * underlying GL texture storage has been changed since it was last
1083    * bound to a texture unit which is why we have a callback into
1084    * _cogl_pipeline_texture_storage_change_notify whenever a textures
1085    * underlying GL texture storage changes which will set the
1086    * unit->texture_intern_changed flag. If we see that's been set here
1087    * then we force an update of the texture state...
1088    */
1089   if (unit->texture_storage_changed)
1090     state->layer_differences[state->i] |=
1091       COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA;
1092 
1093   state->i++;
1094 
1095   return TRUE;
1096 }
1097 
1098 typedef struct
1099 {
1100   CoglFramebuffer *framebuffer;
1101   const CoglPipelineVertend *vertend;
1102   const CoglPipelineFragend *fragend;
1103   CoglPipeline *pipeline;
1104   unsigned long *layer_differences;
1105   CoglBool error_adding_layer;
1106   CoglBool added_layer;
1107 } CoglPipelineAddLayerState;
1108 
1109 static CoglBool
vertend_add_layer_cb(CoglPipelineLayer * layer,void * user_data)1110 vertend_add_layer_cb (CoglPipelineLayer *layer,
1111                       void *user_data)
1112 {
1113   CoglPipelineAddLayerState *state = user_data;
1114   const CoglPipelineVertend *vertend = state->vertend;
1115   CoglPipeline *pipeline = state->pipeline;
1116   int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
1117 
1118   /* Either generate per layer code snippets or setup the
1119    * fixed function glTexEnv for each layer... */
1120   if (G_LIKELY (vertend->add_layer (pipeline,
1121                                     layer,
1122                                     state->layer_differences[unit_index],
1123                                     state->framebuffer)))
1124     state->added_layer = TRUE;
1125   else
1126     {
1127       state->error_adding_layer = TRUE;
1128       return FALSE;
1129     }
1130 
1131   return TRUE;
1132 }
1133 
1134 static CoglBool
fragend_add_layer_cb(CoglPipelineLayer * layer,void * user_data)1135 fragend_add_layer_cb (CoglPipelineLayer *layer,
1136                       void *user_data)
1137 {
1138   CoglPipelineAddLayerState *state = user_data;
1139   const CoglPipelineFragend *fragend = state->fragend;
1140   CoglPipeline *pipeline = state->pipeline;
1141   int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
1142 
1143   /* Either generate per layer code snippets or setup the
1144    * fixed function glTexEnv for each layer... */
1145   if (G_LIKELY (fragend->add_layer (pipeline,
1146                                     layer,
1147                                     state->layer_differences[unit_index])))
1148     state->added_layer = TRUE;
1149   else
1150     {
1151       state->error_adding_layer = TRUE;
1152       return FALSE;
1153     }
1154 
1155   return TRUE;
1156 }
1157 
1158 /*
1159  * _cogl_pipeline_flush_gl_state:
1160  *
1161  * Details of override options:
1162  * ->fallback_mask: is a bitmask of the pipeline layers that need to be
1163  *    replaced with the default, fallback textures. The fallback textures are
1164  *    fully transparent textures so they hopefully wont contribute to the
1165  *    texture combining.
1166  *
1167  *    The intention of fallbacks is to try and preserve
1168  *    the number of layers the user is expecting so that texture coordinates
1169  *    they gave will mostly still correspond to the textures they intended, and
1170  *    have a fighting chance of looking close to their originally intended
1171  *    result.
1172  *
1173  * ->disable_mask: is a bitmask of the pipeline layers that will simply have
1174  *    texturing disabled. It's only really intended for disabling all layers
1175  *    > X; i.e. we'd expect to see a contiguous run of 0 starting from the LSB
1176  *    and at some point the remaining bits flip to 1. It might work to disable
1177  *    arbitrary layers; though I'm not sure a.t.m how OpenGL would take to
1178  *    that.
1179  *
1180  *    The intention of the disable_mask is for emitting geometry when the user
1181  *    hasn't supplied enough texture coordinates for all the layers and it's
1182  *    not possible to auto generate default texture coordinates for those
1183  *    layers.
1184  *
1185  * ->layer0_override_texture: forcibly tells us to bind this GL texture name for
1186  *    layer 0 instead of plucking the gl_texture from the CoglTexture of layer
1187  *    0.
1188  *
1189  *    The intention of this is for any primitives that supports sliced textures.
1190  *    The code will can iterate each of the slices and re-flush the pipeline
1191  *    forcing the GL texture of each slice in turn.
1192  *
1193  * ->wrap_mode_overrides: overrides the wrap modes set on each
1194  *    layer. This is used to implement the automatic wrap mode.
1195  *
1196  * XXX: It might also help if we could specify a texture matrix for code
1197  *    dealing with slicing that would be multiplied with the users own matrix.
1198  *
1199  *    Normaly texture coords in the range [0, 1] refer to the extents of the
1200  *    texture, but when your GL texture represents a slice of the real texture
1201  *    (from the users POV) then a texture matrix would be a neat way of
1202  *    transforming the mapping for each slice.
1203  *
1204  *    Currently for textured rectangles we manually calculate the texture
1205  *    coords for each slice based on the users given coords, but this solution
1206  *    isn't ideal, and can't be used with CoglVertexBuffers.
1207  */
1208 void
_cogl_pipeline_flush_gl_state(CoglContext * ctx,CoglPipeline * pipeline,CoglFramebuffer * framebuffer,CoglBool with_color_attrib,CoglBool unknown_color_alpha)1209 _cogl_pipeline_flush_gl_state (CoglContext *ctx,
1210                                CoglPipeline *pipeline,
1211                                CoglFramebuffer *framebuffer,
1212                                CoglBool with_color_attrib,
1213                                CoglBool unknown_color_alpha)
1214 {
1215   CoglPipeline *current_pipeline = ctx->current_pipeline;
1216   unsigned long pipelines_difference;
1217   int n_layers;
1218   unsigned long *layer_differences;
1219   int i;
1220   CoglTextureUnit *unit1;
1221   const CoglPipelineProgend *progend;
1222 
1223   COGL_STATIC_TIMER (pipeline_flush_timer,
1224                      "Mainloop", /* parent */
1225                      "Material Flush",
1226                      "The time spent flushing material state",
1227                      0 /* no application private data */);
1228 
1229   COGL_TIMER_START (_cogl_uprof_context, pipeline_flush_timer);
1230 
1231   /* Bail out asap if we've been asked to re-flush the already current
1232    * pipeline and we can see the pipeline hasn't changed */
1233   if (current_pipeline == pipeline &&
1234       ctx->current_pipeline_age == pipeline->age &&
1235       ctx->current_pipeline_with_color_attrib == with_color_attrib &&
1236       ctx->current_pipeline_unknown_color_alpha == unknown_color_alpha)
1237     goto done;
1238   else
1239     {
1240       /* Update derived state (currently just the 'real_blend_enable'
1241        * state) and determine a mask of state that differs between the
1242        * current pipeline and the one we are flushing.
1243        *
1244        * Note updating the derived state is done before doing any
1245        * pipeline comparisons so that we can correctly compare the
1246        * 'real_blend_enable' state itself.
1247        */
1248 
1249       if (current_pipeline == pipeline)
1250         {
1251           pipelines_difference = ctx->current_pipeline_changes_since_flush;
1252 
1253           if (pipelines_difference & COGL_PIPELINE_STATE_AFFECTS_BLENDING ||
1254               pipeline->unknown_color_alpha != unknown_color_alpha)
1255             {
1256               CoglBool save_real_blend_enable = pipeline->real_blend_enable;
1257 
1258               _cogl_pipeline_update_real_blend_enable (pipeline,
1259                                                        unknown_color_alpha);
1260 
1261               if (save_real_blend_enable != pipeline->real_blend_enable)
1262                 pipelines_difference |= COGL_PIPELINE_STATE_REAL_BLEND_ENABLE;
1263             }
1264         }
1265       else if (current_pipeline)
1266         {
1267           pipelines_difference = ctx->current_pipeline_changes_since_flush;
1268 
1269           _cogl_pipeline_update_real_blend_enable (pipeline,
1270                                                    unknown_color_alpha);
1271 
1272           pipelines_difference |=
1273             _cogl_pipeline_compare_differences (ctx->current_pipeline,
1274                                                 pipeline);
1275         }
1276       else
1277         {
1278           _cogl_pipeline_update_real_blend_enable (pipeline,
1279                                                    unknown_color_alpha);
1280 
1281           pipelines_difference = COGL_PIPELINE_STATE_ALL;
1282         }
1283     }
1284 
1285   /* Get a layer_differences mask for each layer to be flushed */
1286   n_layers = cogl_pipeline_get_n_layers (pipeline);
1287   if (n_layers)
1288     {
1289       CoglPipelineCompareLayersState state;
1290       layer_differences = g_alloca (sizeof (unsigned long) * n_layers);
1291       memset (layer_differences, 0, sizeof (unsigned long) * n_layers);
1292       state.i = 0;
1293       state.layer_differences = layer_differences;
1294       _cogl_pipeline_foreach_layer_internal (pipeline,
1295                                              compare_layer_differences_cb,
1296                                              &state);
1297     }
1298   else
1299     layer_differences = NULL;
1300 
1301   /* First flush everything that's the same regardless of which
1302    * pipeline backend is being used...
1303    *
1304    * 1) top level state:
1305    *  glColor (or skip if a vertex attribute is being used for color)
1306    *  blend state
1307    *  alpha test state (except for GLES 2.0)
1308    *
1309    * 2) then foreach layer:
1310    *  determine gl_target/gl_texture
1311    *  bind texture
1312    *
1313    *  Note: After _cogl_pipeline_flush_common_gl_state you can expect
1314    *  all state of the layers corresponding texture unit to be
1315    *  updated.
1316    */
1317   _cogl_pipeline_flush_common_gl_state (pipeline,
1318                                         pipelines_difference,
1319                                         layer_differences,
1320                                         with_color_attrib);
1321 
1322   /* Now flush the fragment, vertex and program state according to the
1323    * current progend backend.
1324    *
1325    * Note: Some backends may not support the current pipeline
1326    * configuration and in that case it will report and error and we
1327    * will look for a different backend.
1328    *
1329    * NB: if pipeline->progend != COGL_PIPELINE_PROGEND_UNDEFINED then
1330    * we have previously managed to successfully flush this pipeline
1331    * with the given progend so we will simply use that to avoid
1332    * fallback code paths.
1333    */
1334   if (pipeline->progend == COGL_PIPELINE_PROGEND_UNDEFINED)
1335     _cogl_pipeline_set_progend (pipeline, COGL_PIPELINE_PROGEND_DEFAULT);
1336 
1337   for (i = pipeline->progend;
1338        i < COGL_PIPELINE_N_PROGENDS;
1339        i++, _cogl_pipeline_set_progend (pipeline, i))
1340     {
1341       const CoglPipelineVertend *vertend;
1342       const CoglPipelineFragend *fragend;
1343       CoglPipelineAddLayerState state;
1344 
1345       progend = _cogl_pipeline_progends[i];
1346 
1347       if (G_UNLIKELY (!progend->start (pipeline)))
1348         continue;
1349 
1350       vertend = _cogl_pipeline_vertends[progend->vertend];
1351 
1352       vertend->start (pipeline,
1353                       n_layers,
1354                       pipelines_difference);
1355 
1356       state.framebuffer = framebuffer;
1357       state.vertend = vertend;
1358       state.pipeline = pipeline;
1359       state.layer_differences = layer_differences;
1360       state.error_adding_layer = FALSE;
1361       state.added_layer = FALSE;
1362 
1363       _cogl_pipeline_foreach_layer_internal (pipeline,
1364                                              vertend_add_layer_cb,
1365                                              &state);
1366 
1367       if (G_UNLIKELY (state.error_adding_layer))
1368         continue;
1369 
1370       if (G_UNLIKELY (!vertend->end (pipeline, pipelines_difference)))
1371         continue;
1372 
1373       /* Now prepare the fragment processing state (fragend)
1374        *
1375        * NB: We can't combine the setup of the vertend and fragend
1376        * since the backends that do code generation share
1377        * ctx->codegen_source_buffer as a scratch buffer.
1378        */
1379 
1380       fragend = _cogl_pipeline_fragends[progend->fragend];
1381       state.fragend = fragend;
1382 
1383       fragend->start (pipeline,
1384                       n_layers,
1385                       pipelines_difference);
1386 
1387       _cogl_pipeline_foreach_layer_internal (pipeline,
1388                                              fragend_add_layer_cb,
1389                                              &state);
1390 
1391       if (G_UNLIKELY (state.error_adding_layer))
1392         continue;
1393 
1394       if (!state.added_layer)
1395         {
1396           if (fragend->passthrough &&
1397               G_UNLIKELY (!fragend->passthrough (pipeline)))
1398             continue;
1399         }
1400 
1401       if (G_UNLIKELY (!fragend->end (pipeline, pipelines_difference)))
1402         continue;
1403 
1404       if (progend->end)
1405         progend->end (pipeline, pipelines_difference);
1406       break;
1407     }
1408 
1409   /* FIXME: This reference is actually resulting in lots of
1410    * copy-on-write reparenting because one-shot pipelines end up
1411    * living for longer than necessary and so any later modification of
1412    * the parent will cause a copy-on-write.
1413    *
1414    * XXX: The issue should largely go away when we switch to using
1415    * weak pipelines for overrides.
1416    */
1417   cogl_object_ref (pipeline);
1418   if (ctx->current_pipeline != NULL)
1419     cogl_object_unref (ctx->current_pipeline);
1420   ctx->current_pipeline = pipeline;
1421   ctx->current_pipeline_changes_since_flush = 0;
1422   ctx->current_pipeline_with_color_attrib = with_color_attrib;
1423   ctx->current_pipeline_unknown_color_alpha = unknown_color_alpha;
1424   ctx->current_pipeline_age = pipeline->age;
1425 
1426 done:
1427 
1428   progend = _cogl_pipeline_progends[pipeline->progend];
1429 
1430   /* We can't assume the color will be retained between flushes when
1431    * using the glsl progend because the generic attribute values are
1432    * not stored as part of the program object so they could be
1433    * overridden by any attribute changes in another program */
1434   if (pipeline->progend == COGL_PIPELINE_PROGEND_GLSL && !with_color_attrib)
1435     {
1436       int attribute;
1437       CoglPipeline *authority =
1438         _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR);
1439       int name_index = COGL_ATTRIBUTE_COLOR_NAME_INDEX;
1440 
1441       attribute =
1442         _cogl_pipeline_progend_glsl_get_attrib_location (pipeline, name_index);
1443       if (attribute != -1)
1444         GE (ctx,
1445             glVertexAttrib4f (attribute,
1446                               cogl_color_get_red_float (&authority->color),
1447                               cogl_color_get_green_float (&authority->color),
1448                               cogl_color_get_blue_float (&authority->color),
1449                               cogl_color_get_alpha_float (&authority->color)));
1450     }
1451 
1452   /* Give the progend a chance to update any uniforms that might not
1453    * depend on the material state. This is used on GLES2 to update the
1454    * matrices */
1455   if (progend->pre_paint)
1456     progend->pre_paint (pipeline, framebuffer);
1457 
1458   /* Handle the fact that OpenGL associates texture filter and wrap
1459    * modes with the texture objects not the texture units... */
1460   if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS))
1461     foreach_texture_unit_update_filter_and_wrap_modes ();
1462 
1463   /* If this pipeline has more than one layer then we always need
1464    * to make sure we rebind the texture for unit 1.
1465    *
1466    * NB: various components of Cogl may temporarily bind arbitrary
1467    * textures to texture unit 1 so they can query and modify texture
1468    * object parameters. cogl-pipeline.c (See
1469    * _cogl_bind_gl_texture_transient)
1470    */
1471   unit1 = _cogl_get_texture_unit (1);
1472   if (cogl_pipeline_get_n_layers (pipeline) > 1 && unit1->dirty_gl_texture)
1473     {
1474       _cogl_set_active_texture_unit (1);
1475       GE (ctx, glBindTexture (unit1->gl_target, unit1->gl_texture));
1476       unit1->dirty_gl_texture = FALSE;
1477     }
1478 
1479   COGL_TIMER_STOP (_cogl_uprof_context, pipeline_flush_timer);
1480 }
1481 
1482