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