1 /*
2  * Cogl
3  *
4  * A Low Level GPU Graphics and Utilities API
5  *
6  * Copyright (C) 2008,2009,2010,2013 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-context-private.h"
38 #include "cogl-object.h"
39 
40 #include "cogl-pipeline-private.h"
41 #include "cogl-pipeline-state-private.h"
42 #include "cogl-pipeline-layer-state-private.h"
43 #include "cogl-texture-private.h"
44 #include "cogl-blend-string.h"
45 #include "cogl-journal-private.h"
46 #include "cogl-color-private.h"
47 #include "cogl-util.h"
48 #include "cogl-profile.h"
49 #include "cogl-depth-state-private.h"
50 #include "cogl1-context.h"
51 #include "cogl-gtype-private.h"
52 
53 #include <glib.h>
54 #include <glib/gprintf.h>
55 #include <string.h>
56 
57 static void _cogl_pipeline_free (CoglPipeline *tex);
58 static void recursively_free_layer_caches (CoglPipeline *pipeline);
59 static gboolean _cogl_pipeline_is_weak (CoglPipeline *pipeline);
60 
61 const CoglPipelineFragend *_cogl_pipeline_fragend;
62 const CoglPipelineVertend *_cogl_pipeline_vertend;
63 const CoglPipelineProgend *_cogl_pipeline_progend;
64 
65 #include "driver/gl/cogl-pipeline-fragend-glsl-private.h"
66 #include "driver/gl/cogl-pipeline-vertend-glsl-private.h"
67 #include "driver/gl/cogl-pipeline-progend-glsl-private.h"
68 
69 COGL_OBJECT_DEFINE (Pipeline, pipeline);
70 COGL_GTYPE_DEFINE_CLASS (Pipeline, pipeline);
71 
72 /*
73  * This initializes the first pipeline owned by the Cogl context. All
74  * subsequently instantiated pipelines created via the cogl_pipeline_new()
75  * API will initially be a copy of this pipeline.
76  *
77  * The default pipeline is the topmost ancester for all pipelines.
78  */
79 void
_cogl_pipeline_init_default_pipeline(void)80 _cogl_pipeline_init_default_pipeline (void)
81 {
82   /* Create new - blank - pipeline */
83   CoglPipeline *pipeline = g_new0 (CoglPipeline, 1);
84   /* XXX: NB: It's important that we zero this to avoid polluting
85    * pipeline hash values with un-initialized data */
86   CoglPipelineBigState *big_state = g_new0 (CoglPipelineBigState, 1);
87   CoglPipelineAlphaFuncState *alpha_state = &big_state->alpha_state;
88   CoglPipelineBlendState *blend_state = &big_state->blend_state;
89   CoglPipelineCullFaceState *cull_face_state = &big_state->cull_face_state;
90   CoglPipelineUniformsState *uniforms_state = &big_state->uniforms_state;
91 
92   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
93 
94   /* Take this opportunity to setup the backends... */
95   _cogl_pipeline_fragend = &_cogl_pipeline_glsl_fragend;
96   _cogl_pipeline_progend = &_cogl_pipeline_glsl_progend;
97   _cogl_pipeline_vertend = &_cogl_pipeline_glsl_vertend;
98 
99   _cogl_pipeline_node_init (COGL_NODE (pipeline));
100 
101   pipeline->is_weak = FALSE;
102   pipeline->journal_ref_count = 0;
103   pipeline->differences = COGL_PIPELINE_STATE_ALL_SPARSE;
104 
105   pipeline->real_blend_enable = FALSE;
106 
107   pipeline->layer_differences = NULL;
108   pipeline->n_layers = 0;
109 
110   pipeline->big_state = big_state;
111   pipeline->has_big_state = TRUE;
112 
113   pipeline->static_breadcrumb = "default pipeline";
114   pipeline->has_static_breadcrumb = TRUE;
115 
116   pipeline->age = 0;
117 
118   /* Use the same defaults as the GL spec... */
119   cogl_color_init_from_4ub (&pipeline->color, 0xff, 0xff, 0xff, 0xff);
120 
121   /* Use the same defaults as the GL spec... */
122   alpha_state->alpha_func = COGL_PIPELINE_ALPHA_FUNC_ALWAYS;
123   alpha_state->alpha_func_reference = 0.0;
124 
125   /* Not the same as the GL default, but seems saner... */
126 #if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL)
127   blend_state->blend_equation_rgb = GL_FUNC_ADD;
128   blend_state->blend_equation_alpha = GL_FUNC_ADD;
129   blend_state->blend_src_factor_alpha = GL_ONE;
130   blend_state->blend_dst_factor_alpha = GL_ONE_MINUS_SRC_ALPHA;
131   cogl_color_init_from_4ub (&blend_state->blend_constant,
132                             0x00, 0x00, 0x00, 0x00);
133 #endif
134   blend_state->blend_src_factor_rgb = GL_ONE;
135   blend_state->blend_dst_factor_rgb = GL_ONE_MINUS_SRC_ALPHA;
136 
137   big_state->user_program = NULL;
138 
139   cogl_depth_state_init (&big_state->depth_state);
140 
141   big_state->point_size = 0.0f;
142 
143   cull_face_state->mode = COGL_PIPELINE_CULL_FACE_MODE_NONE;
144   cull_face_state->front_winding = COGL_WINDING_COUNTER_CLOCKWISE;
145 
146   _cogl_bitmask_init (&uniforms_state->override_mask);
147   _cogl_bitmask_init (&uniforms_state->changed_mask);
148   uniforms_state->override_values = NULL;
149 
150   ctx->default_pipeline = _cogl_pipeline_object_new (pipeline);
151 }
152 
153 static void
_cogl_pipeline_unparent(CoglNode * pipeline)154 _cogl_pipeline_unparent (CoglNode *pipeline)
155 {
156   /* Chain up */
157   _cogl_pipeline_node_unparent_real (pipeline);
158 }
159 
160 static gboolean
recursively_free_layer_caches_cb(CoglNode * node,void * user_data)161 recursively_free_layer_caches_cb (CoglNode *node,
162                                   void *user_data)
163 {
164   recursively_free_layer_caches (COGL_PIPELINE (node));
165   return TRUE;
166 }
167 
168 /* This recursively frees the layers_cache of a pipeline and all of
169  * its descendants.
170  *
171  * For instance if we change a pipelines ->layer_differences list
172  * then that pipeline and all of its descendants may now have
173  * incorrect layer caches. */
174 static void
recursively_free_layer_caches(CoglPipeline * pipeline)175 recursively_free_layer_caches (CoglPipeline *pipeline)
176 {
177   /* Note: we maintain the invariable that if a pipeline already has a
178    * dirty layers_cache then so do all of its descendants. */
179   if (pipeline->layers_cache_dirty)
180     return;
181 
182   if (G_UNLIKELY (pipeline->layers_cache != pipeline->short_layers_cache))
183     g_free (pipeline->layers_cache);
184   pipeline->layers_cache_dirty = TRUE;
185 
186   _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline),
187                                      recursively_free_layer_caches_cb,
188                                      NULL);
189 }
190 
191 static void
_cogl_pipeline_set_parent(CoglPipeline * pipeline,CoglPipeline * parent,gboolean take_strong_reference)192 _cogl_pipeline_set_parent (CoglPipeline *pipeline,
193                            CoglPipeline *parent,
194                            gboolean take_strong_reference)
195 {
196   /* Chain up */
197   _cogl_pipeline_node_set_parent_real (COGL_NODE (pipeline),
198                                        COGL_NODE (parent),
199                                        _cogl_pipeline_unparent,
200                                        take_strong_reference);
201 
202   /* Since we just changed the ancestry of the pipeline its cache of
203    * layers could now be invalid so free it... */
204   if (pipeline->differences & COGL_PIPELINE_STATE_LAYERS)
205     recursively_free_layer_caches (pipeline);
206 }
207 
208 static void
_cogl_pipeline_promote_weak_ancestors(CoglPipeline * strong)209 _cogl_pipeline_promote_weak_ancestors (CoglPipeline *strong)
210 {
211   CoglNode *n;
212 
213   g_return_if_fail (!strong->is_weak);
214 
215   /* If the parent of strong is weak, then we want to promote it by
216      taking a reference on strong's grandparent. We don't need to take
217      a reference on strong's direct parent */
218 
219   if (COGL_NODE (strong)->parent == NULL)
220     return;
221 
222   for (n = COGL_NODE (strong)->parent;
223        /* We can assume that all weak pipelines have a parent */
224        COGL_PIPELINE (n)->is_weak;
225        n = n->parent)
226     /* 'n' is weak so we take a reference on its parent */
227     cogl_object_ref (n->parent);
228 }
229 
230 static void
_cogl_pipeline_revert_weak_ancestors(CoglPipeline * strong)231 _cogl_pipeline_revert_weak_ancestors (CoglPipeline *strong)
232 {
233   CoglNode *n;
234 
235   g_return_if_fail (!strong->is_weak);
236 
237   /* This reverts the effect of calling
238      _cogl_pipeline_promote_weak_ancestors */
239 
240   if (COGL_NODE (strong)->parent == NULL)
241     return;
242 
243   for (n = COGL_NODE (strong)->parent;
244        /* We can assume that all weak pipelines have a parent */
245        COGL_PIPELINE (n)->is_weak;
246        n = n->parent)
247     /* 'n' is weak so we unref its parent */
248     cogl_object_unref (n->parent);
249 }
250 
251 /* XXX: Always have an eye out for opportunities to lower the cost of
252  * cogl_pipeline_copy. */
253 static CoglPipeline *
_cogl_pipeline_copy(CoglPipeline * src,gboolean is_weak)254 _cogl_pipeline_copy (CoglPipeline *src, gboolean is_weak)
255 {
256   CoglPipeline *pipeline = g_new0 (CoglPipeline, 1);
257 
258   _cogl_pipeline_node_init (COGL_NODE (pipeline));
259 
260   pipeline->is_weak = is_weak;
261 
262   pipeline->journal_ref_count = 0;
263 
264   pipeline->differences = 0;
265 
266   pipeline->has_big_state = FALSE;
267 
268   /* NB: real_blend_enable isn't a sparse property, it's valid for
269    * every pipeline node so we have fast access to it. */
270   pipeline->real_blend_enable = src->real_blend_enable;
271   pipeline->dirty_real_blend_enable = src->dirty_real_blend_enable;
272   pipeline->unknown_color_alpha = src->unknown_color_alpha;
273 
274   /* XXX:
275    * consider generalizing the idea of "cached" properties. These
276    * would still have an authority like other sparse properties but
277    * you wouldn't have to walk up the ancestry to find the authority
278    * because the value would be cached directly in each pipeline.
279    */
280 
281   pipeline->layers_cache_dirty = TRUE;
282 
283   pipeline->has_static_breadcrumb = FALSE;
284 
285   pipeline->age = 0;
286 
287   _cogl_pipeline_set_parent (pipeline, src, !is_weak);
288 
289   /* The semantics for copying a weak pipeline are that we promote all
290    * weak ancestors to temporarily become strong pipelines until the
291    * copy is freed. */
292   if (!is_weak)
293     _cogl_pipeline_promote_weak_ancestors (pipeline);
294 
295   return _cogl_pipeline_object_new (pipeline);
296 }
297 
298 CoglPipeline *
cogl_pipeline_copy(CoglPipeline * src)299 cogl_pipeline_copy (CoglPipeline *src)
300 {
301   return _cogl_pipeline_copy (src, FALSE);
302 }
303 
304 CoglPipeline *
_cogl_pipeline_weak_copy(CoglPipeline * pipeline,CoglPipelineDestroyCallback callback,void * user_data)305 _cogl_pipeline_weak_copy (CoglPipeline *pipeline,
306                           CoglPipelineDestroyCallback callback,
307                           void *user_data)
308 {
309   CoglPipeline *copy;
310   CoglPipeline *copy_pipeline;
311 
312   copy = _cogl_pipeline_copy (pipeline, TRUE);
313   copy_pipeline = COGL_PIPELINE (copy);
314   copy_pipeline->destroy_callback = callback;
315   copy_pipeline->destroy_data = user_data;
316 
317   return copy;
318 }
319 
320 CoglPipeline *
cogl_pipeline_new(CoglContext * context)321 cogl_pipeline_new (CoglContext *context)
322 {
323   CoglPipeline *new;
324 
325   new = cogl_pipeline_copy (context->default_pipeline);
326 #ifdef COGL_DEBUG_ENABLED
327   _cogl_pipeline_set_static_breadcrumb (new, "new");
328 #endif
329   return new;
330 }
331 
332 static gboolean
destroy_weak_children_cb(CoglNode * node,void * user_data)333 destroy_weak_children_cb (CoglNode *node,
334                           void *user_data)
335 {
336   CoglPipeline *pipeline = COGL_PIPELINE (node);
337 
338   if (_cogl_pipeline_is_weak (pipeline))
339     {
340       _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline),
341                                          destroy_weak_children_cb,
342                                          NULL);
343 
344       pipeline->destroy_callback (pipeline, pipeline->destroy_data);
345       _cogl_pipeline_unparent (COGL_NODE (pipeline));
346     }
347 
348   return TRUE;
349 }
350 
351 static void
_cogl_pipeline_free(CoglPipeline * pipeline)352 _cogl_pipeline_free (CoglPipeline *pipeline)
353 {
354   if (!pipeline->is_weak)
355     _cogl_pipeline_revert_weak_ancestors (pipeline);
356 
357   /* Weak pipelines don't take a reference on their parent */
358   _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline),
359                                      destroy_weak_children_cb,
360                                      NULL);
361 
362   g_assert (_cogl_list_empty (&COGL_NODE (pipeline)->children));
363 
364   _cogl_pipeline_unparent (COGL_NODE (pipeline));
365 
366   if (pipeline->differences & COGL_PIPELINE_STATE_USER_SHADER &&
367       pipeline->big_state->user_program)
368     cogl_object_unref (pipeline->big_state->user_program);
369 
370   if (pipeline->differences & COGL_PIPELINE_STATE_UNIFORMS)
371     {
372       CoglPipelineUniformsState *uniforms_state
373         = &pipeline->big_state->uniforms_state;
374       int n_overrides = _cogl_bitmask_popcount (&uniforms_state->override_mask);
375       int i;
376 
377       for (i = 0; i < n_overrides; i++)
378         _cogl_boxed_value_destroy (uniforms_state->override_values + i);
379       g_free (uniforms_state->override_values);
380 
381       _cogl_bitmask_destroy (&uniforms_state->override_mask);
382       _cogl_bitmask_destroy (&uniforms_state->changed_mask);
383     }
384 
385   if (pipeline->differences & COGL_PIPELINE_STATE_LAYERS)
386     g_list_free_full (pipeline->layer_differences, cogl_object_unref);
387 
388   if (pipeline->differences & COGL_PIPELINE_STATE_VERTEX_SNIPPETS)
389     _cogl_pipeline_snippet_list_free (&pipeline->big_state->vertex_snippets);
390 
391   if (pipeline->differences & COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS)
392     _cogl_pipeline_snippet_list_free (&pipeline->big_state->fragment_snippets);
393 
394   if (pipeline->differences & COGL_PIPELINE_STATE_NEEDS_BIG_STATE)
395     g_free (pipeline->big_state);
396 
397   recursively_free_layer_caches (pipeline);
398 
399   g_free (pipeline);
400 }
401 
402 gboolean
_cogl_pipeline_get_real_blend_enabled(CoglPipeline * pipeline)403 _cogl_pipeline_get_real_blend_enabled (CoglPipeline *pipeline)
404 {
405   g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
406 
407   return pipeline->real_blend_enable;
408 }
409 
410 static void
_cogl_pipeline_update_layers_cache(CoglPipeline * pipeline)411 _cogl_pipeline_update_layers_cache (CoglPipeline *pipeline)
412 {
413   /* Note: we assume this pipeline is a _LAYERS authority */
414   int n_layers;
415   CoglPipeline *current;
416   int layers_found;
417 
418   if (G_LIKELY (!pipeline->layers_cache_dirty) ||
419       pipeline->n_layers == 0)
420     return;
421 
422   pipeline->layers_cache_dirty = FALSE;
423 
424   n_layers = pipeline->n_layers;
425   if (G_LIKELY (n_layers < G_N_ELEMENTS (pipeline->short_layers_cache)))
426     {
427       pipeline->layers_cache = pipeline->short_layers_cache;
428       memset (pipeline->layers_cache, 0,
429               sizeof (CoglPipelineLayer *) *
430               G_N_ELEMENTS (pipeline->short_layers_cache));
431     }
432   else
433     {
434       pipeline->layers_cache =
435         g_malloc0 (sizeof (CoglPipelineLayer *) * n_layers);
436     }
437 
438   /* Notes:
439    *
440    * Each pipeline doesn't have to contain a complete list of the layers
441    * it depends on, some of them are indirectly referenced through the
442    * pipeline's ancestors.
443    *
444    * pipeline->layer_differences only contains a list of layers that
445    * have changed in relation to its parent.
446    *
447    * pipeline->layer_differences is not maintained sorted, but it
448    * won't contain multiple layers corresponding to a particular
449    * ->unit_index.
450    *
451    * Some of the ancestor pipelines may reference layers with
452    * ->unit_index values >= n_layers so we ignore them.
453    *
454    * As we ascend through the ancestors we are searching for any
455    * CoglPipelineLayers corresponding to the texture ->unit_index
456    * values in the range [0,n_layers-1]. As soon as a pointer is found
457    * we ignore layers of further ancestors with the same ->unit_index
458    * values.
459    */
460 
461   layers_found = 0;
462   for (current = pipeline;
463        _cogl_pipeline_get_parent (current);
464        current = _cogl_pipeline_get_parent (current))
465     {
466       GList *l;
467 
468       if (!(current->differences & COGL_PIPELINE_STATE_LAYERS))
469         continue;
470 
471       for (l = current->layer_differences; l; l = l->next)
472         {
473           CoglPipelineLayer *layer = l->data;
474           int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
475 
476           if (unit_index < n_layers && !pipeline->layers_cache[unit_index])
477             {
478               pipeline->layers_cache[unit_index] = layer;
479               layers_found++;
480               if (layers_found == n_layers)
481                 return;
482             }
483         }
484     }
485 
486   g_warn_if_reached ();
487 }
488 
489 /* XXX: Be careful when using this API that the callback given doesn't result
490  * in the layer cache being invalidated during the iteration! */
491 void
_cogl_pipeline_foreach_layer_internal(CoglPipeline * pipeline,CoglPipelineInternalLayerCallback callback,void * user_data)492 _cogl_pipeline_foreach_layer_internal (CoglPipeline *pipeline,
493                                        CoglPipelineInternalLayerCallback callback,
494                                        void *user_data)
495 {
496   CoglPipeline *authority =
497     _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LAYERS);
498   int n_layers;
499   int i;
500   gboolean cont;
501 
502   n_layers = authority->n_layers;
503   if (n_layers == 0)
504     return;
505 
506   _cogl_pipeline_update_layers_cache (authority);
507 
508   for (i = 0, cont = TRUE; i < n_layers && cont == TRUE; i++)
509     {
510       g_return_if_fail (authority->layers_cache_dirty == FALSE);
511       cont = callback (authority->layers_cache[i], user_data);
512     }
513 }
514 
515 gboolean
_cogl_pipeline_layer_numbers_equal(CoglPipeline * pipeline0,CoglPipeline * pipeline1)516 _cogl_pipeline_layer_numbers_equal (CoglPipeline *pipeline0,
517                                     CoglPipeline *pipeline1)
518 {
519   CoglPipeline *authority0 =
520     _cogl_pipeline_get_authority (pipeline0, COGL_PIPELINE_STATE_LAYERS);
521   CoglPipeline *authority1 =
522     _cogl_pipeline_get_authority (pipeline1, COGL_PIPELINE_STATE_LAYERS);
523   int n_layers = authority0->n_layers;
524   int i;
525 
526   if (authority1->n_layers != n_layers)
527     return FALSE;
528 
529   _cogl_pipeline_update_layers_cache (authority0);
530   _cogl_pipeline_update_layers_cache (authority1);
531 
532   for (i = 0; i < n_layers; i++)
533     {
534       CoglPipelineLayer *layer0 = authority0->layers_cache[i];
535       CoglPipelineLayer *layer1 = authority1->layers_cache[i];
536 
537       if (layer0->index != layer1->index)
538         return FALSE;
539     }
540 
541   return TRUE;
542 }
543 
544 gboolean
_cogl_pipeline_layer_and_unit_numbers_equal(CoglPipeline * pipeline0,CoglPipeline * pipeline1)545 _cogl_pipeline_layer_and_unit_numbers_equal (CoglPipeline *pipeline0,
546                                              CoglPipeline *pipeline1)
547 {
548   CoglPipeline *authority0 =
549     _cogl_pipeline_get_authority (pipeline0, COGL_PIPELINE_STATE_LAYERS);
550   CoglPipeline *authority1 =
551     _cogl_pipeline_get_authority (pipeline1, COGL_PIPELINE_STATE_LAYERS);
552   int n_layers = authority0->n_layers;
553   int i;
554 
555   if (authority1->n_layers != n_layers)
556     return FALSE;
557 
558   _cogl_pipeline_update_layers_cache (authority0);
559   _cogl_pipeline_update_layers_cache (authority1);
560 
561   for (i = 0; i < n_layers; i++)
562     {
563       CoglPipelineLayer *layer0 = authority0->layers_cache[i];
564       CoglPipelineLayer *layer1 = authority1->layers_cache[i];
565       int unit0, unit1;
566 
567       if (layer0->index != layer1->index)
568         return FALSE;
569 
570       unit0 = _cogl_pipeline_layer_get_unit_index (layer0);
571       unit1 = _cogl_pipeline_layer_get_unit_index (layer1);
572       if (unit0 != unit1)
573         return FALSE;
574     }
575 
576   return TRUE;
577 }
578 
579 typedef struct
580 {
581   int i;
582   int *indices;
583 } AppendLayerIndexState;
584 
585 static gboolean
append_layer_index_cb(CoglPipelineLayer * layer,void * user_data)586 append_layer_index_cb (CoglPipelineLayer *layer,
587                        void *user_data)
588 {
589   AppendLayerIndexState *state = user_data;
590   state->indices[state->i++] = layer->index;
591   return TRUE;
592 }
593 
594 void
cogl_pipeline_foreach_layer(CoglPipeline * pipeline,CoglPipelineLayerCallback callback,void * user_data)595 cogl_pipeline_foreach_layer (CoglPipeline *pipeline,
596                              CoglPipelineLayerCallback callback,
597                              void *user_data)
598 {
599   CoglPipeline *authority =
600     _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LAYERS);
601   AppendLayerIndexState state;
602   gboolean cont;
603   int i;
604 
605   /* XXX: We don't know what the user is going to want to do to the layers
606    * but any modification of layers can result in the layer graph changing
607    * which could confuse _cogl_pipeline_foreach_layer_internal(). We first
608    * get a list of layer indices which will remain valid so long as the
609    * user doesn't remove layers. */
610 
611   state.i = 0;
612   state.indices = g_alloca (authority->n_layers * sizeof (int));
613 
614   _cogl_pipeline_foreach_layer_internal (pipeline,
615                                          append_layer_index_cb,
616                                          &state);
617 
618   for (i = 0, cont = TRUE; i < authority->n_layers && cont; i++)
619     cont = callback (pipeline, state.indices[i], user_data);
620 }
621 
622 static gboolean
layer_has_alpha_cb(CoglPipelineLayer * layer,void * data)623 layer_has_alpha_cb (CoglPipelineLayer *layer, void *data)
624 {
625   gboolean *has_alpha = data;
626   *has_alpha = _cogl_pipeline_layer_has_alpha (layer);
627 
628   /* return FALSE to stop iterating layers if we find any layer
629    * has alpha ...
630    *
631    * FIXME: actually we should never be bailing out because it's
632    * always possible that a later layer could discard any previous
633    * alpha!
634    */
635 
636   return !(*has_alpha);
637 }
638 
639 /* NB: If this pipeline returns FALSE that doesn't mean that the
640  * pipeline is definitely opaque, it just means that that the
641  * given changes dont imply transparency.
642  *
643  * If you want to find out of the pipeline is opaque then assuming
644  * this returns FALSE for a set of changes then you can follow
645  * up
646  */
647 static gboolean
_cogl_pipeline_change_implies_transparency(CoglPipeline * pipeline,unsigned int changes,const CoglColor * override_color,gboolean unknown_color_alpha)648 _cogl_pipeline_change_implies_transparency (CoglPipeline *pipeline,
649                                             unsigned int changes,
650                                             const CoglColor *override_color,
651                                             gboolean unknown_color_alpha)
652 {
653   /* In the case of a layer state change we need to check everything
654    * else first since they contribute to the has_alpha status of the
655    * "PREVIOUS" layer. */
656   if (changes & COGL_PIPELINE_STATE_LAYERS)
657     changes = COGL_PIPELINE_STATE_AFFECTS_BLENDING;
658 
659   if (unknown_color_alpha)
660     return TRUE;
661 
662   if ((override_color && cogl_color_get_alpha_byte (override_color) != 0xff))
663     return TRUE;
664 
665   if (changes & COGL_PIPELINE_STATE_COLOR)
666     {
667       CoglColor tmp;
668       cogl_pipeline_get_color (pipeline, &tmp);
669       if (cogl_color_get_alpha_byte (&tmp) != 0xff)
670         return TRUE;
671     }
672 
673   if (changes & COGL_PIPELINE_STATE_USER_SHADER)
674     {
675       /* We can't make any assumptions about the alpha channel if the user
676        * is using an unknown fragment shader.
677        *
678        * TODO: check that it isn't just a vertex shader!
679        */
680       if (_cogl_pipeline_get_user_program (pipeline) != NULL)
681         return TRUE;
682     }
683 
684   if (changes & COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS)
685     {
686       if (_cogl_pipeline_has_non_layer_fragment_snippets (pipeline))
687         return TRUE;
688     }
689 
690   if (changes & COGL_PIPELINE_STATE_VERTEX_SNIPPETS)
691     {
692       if (_cogl_pipeline_has_non_layer_vertex_snippets (pipeline))
693         return TRUE;
694     }
695 
696   if (changes & COGL_PIPELINE_STATE_LAYERS)
697     {
698       /* has_alpha tracks the alpha status of the GL_PREVIOUS layer.
699        * To start with that's defined by the pipeline color which
700        * must be fully opaque if we got this far. */
701       gboolean has_alpha = FALSE;
702       _cogl_pipeline_foreach_layer_internal (pipeline,
703                                              layer_has_alpha_cb,
704                                              &has_alpha);
705       if (has_alpha)
706         return TRUE;
707     }
708 
709   return FALSE;
710 }
711 
712 static gboolean
_cogl_pipeline_needs_blending_enabled(CoglPipeline * pipeline,unsigned int changes,const CoglColor * override_color,gboolean unknown_color_alpha)713 _cogl_pipeline_needs_blending_enabled (CoglPipeline *pipeline,
714                                        unsigned int changes,
715                                        const CoglColor *override_color,
716                                        gboolean unknown_color_alpha)
717 {
718   CoglPipeline *blend_authority;
719   CoglPipelineBlendState *blend_state;
720 
721   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_BLENDING)))
722     return FALSE;
723 
724   blend_authority =
725     _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_BLEND);
726 
727   blend_state = &blend_authority->big_state->blend_state;
728 
729   /* We are trying to identify some cases that are equivalent to
730    * blending being disable, where the output is simply GL_SRC_COLOR.
731    *
732    * Note: we currently only consider a few cases that can be
733    * optimized but there could be opportunities to special case more
734    * blend functions later.
735    */
736 
737   /* As the most common way that we currently use to effectively
738    * disable blending is to use an equation of
739    * "RGBA=ADD(SRC_COLOR, 0)" that's the first thing we check
740    * for... */
741   if (blend_state->blend_equation_rgb == GL_FUNC_ADD &&
742       blend_state->blend_equation_alpha == GL_FUNC_ADD &&
743       blend_state->blend_src_factor_alpha == GL_ONE &&
744       blend_state->blend_dst_factor_alpha == GL_ZERO)
745     {
746       return FALSE;
747     }
748 
749   /* NB: The default blending equation for Cogl is
750    * "RGBA=ADD(SRC_COLOR, DST_COLOR * (1-SRC_COLOR[A]))"
751    *
752    * Next we check if the default blending equation is being used.  If
753    * so then we follow that by looking for cases where SRC_COLOR[A] ==
754    * 1 since that simplifies "DST_COLOR * (1-SRC_COLOR[A])" to 0 which
755    * also effectively requires no blending.
756    */
757 
758   if (blend_state->blend_equation_rgb != GL_FUNC_ADD ||
759       blend_state->blend_equation_alpha != GL_FUNC_ADD)
760     return TRUE;
761 
762   if (blend_state->blend_src_factor_alpha != GL_ONE ||
763       blend_state->blend_dst_factor_alpha != GL_ONE_MINUS_SRC_ALPHA)
764     return TRUE;
765 
766   if (blend_state->blend_src_factor_rgb != GL_ONE ||
767       blend_state->blend_dst_factor_rgb != GL_ONE_MINUS_SRC_ALPHA)
768     return TRUE;
769 
770   /* Given the above constraints, it's now a case of finding any
771    * SRC_ALPHA that != 1 */
772 
773   if (_cogl_pipeline_change_implies_transparency (pipeline, changes,
774                                                   override_color,
775                                                   unknown_color_alpha))
776     return TRUE;
777 
778   /* At this point, considering just the state that has changed it
779    * looks like blending isn't needed. If blending was previously
780    * enabled though it could be that some other state still requires
781    * that we have blending enabled because it implies transparency.
782    * In this case we still need to go and check the other state...
783    *
784    * XXX: We could explicitly keep track of the mask of state groups
785    * that are currently causing blending to be enabled so that we
786    * never have to resort to checking *all* the state and can instead
787    * always limit the check to those in the mask.
788    */
789   if (pipeline->real_blend_enable)
790     {
791       unsigned int other_state =
792         COGL_PIPELINE_STATE_AFFECTS_BLENDING & ~changes;
793       if (other_state &&
794           _cogl_pipeline_change_implies_transparency (pipeline, other_state, NULL, FALSE))
795         return TRUE;
796     }
797 
798   return FALSE;
799 }
800 
801 static void
_cogl_pipeline_copy_differences(CoglPipeline * dest,CoglPipeline * src,unsigned long differences)802 _cogl_pipeline_copy_differences (CoglPipeline *dest,
803                                  CoglPipeline *src,
804                                  unsigned long differences)
805 {
806   CoglPipelineBigState *big_state;
807 
808   if (differences & COGL_PIPELINE_STATE_COLOR)
809     dest->color = src->color;
810 
811   if (differences & COGL_PIPELINE_STATE_LAYERS)
812     {
813       GList *l;
814 
815       if (dest->differences & COGL_PIPELINE_STATE_LAYERS &&
816           dest->layer_differences)
817         g_list_free_full (dest->layer_differences, cogl_object_unref);
818 
819       for (l = src->layer_differences; l; l = l->next)
820         {
821           /* NB: a layer can't have more than one ->owner so we can't
822            * simply take a references on each of the original
823            * layer_differences, we have to derive new layers from the
824            * originals instead. */
825           CoglPipelineLayer *copy = _cogl_pipeline_layer_copy (l->data);
826           _cogl_pipeline_add_layer_difference (dest, copy, FALSE);
827           cogl_object_unref (copy);
828         }
829 
830       /* Note: we initialize n_layers after adding the layer differences
831        * since the act of adding the layers will initialize n_layers to 0
832        * because dest isn't initially a STATE_LAYERS authority. */
833       dest->n_layers = src->n_layers;
834     }
835 
836   if (differences & COGL_PIPELINE_STATE_NEEDS_BIG_STATE)
837     {
838       if (!dest->has_big_state)
839         {
840           dest->big_state = g_new0 (CoglPipelineBigState, 1);
841           dest->has_big_state = TRUE;
842         }
843       big_state = dest->big_state;
844     }
845   else
846     goto check_for_blending_change;
847 
848   if (differences & COGL_PIPELINE_STATE_ALPHA_FUNC)
849     big_state->alpha_state.alpha_func =
850       src->big_state->alpha_state.alpha_func;
851 
852   if (differences & COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE)
853     big_state->alpha_state.alpha_func_reference =
854       src->big_state->alpha_state.alpha_func_reference;
855 
856   if (differences & COGL_PIPELINE_STATE_BLEND)
857     {
858       memcpy (&big_state->blend_state,
859               &src->big_state->blend_state,
860               sizeof (CoglPipelineBlendState));
861     }
862 
863   if (differences & COGL_PIPELINE_STATE_USER_SHADER)
864     {
865       if (src->big_state->user_program)
866         big_state->user_program =
867           cogl_object_ref (src->big_state->user_program);
868       else
869         big_state->user_program = NULL;
870     }
871 
872   if (differences & COGL_PIPELINE_STATE_DEPTH)
873     {
874       memcpy (&big_state->depth_state,
875               &src->big_state->depth_state,
876               sizeof (CoglDepthState));
877     }
878 
879   if (differences & COGL_PIPELINE_STATE_NON_ZERO_POINT_SIZE)
880     big_state->non_zero_point_size = src->big_state->non_zero_point_size;
881 
882   if (differences & COGL_PIPELINE_STATE_POINT_SIZE)
883     big_state->point_size = src->big_state->point_size;
884 
885   if (differences & COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE)
886     big_state->per_vertex_point_size = src->big_state->per_vertex_point_size;
887 
888   if (differences & COGL_PIPELINE_STATE_CULL_FACE)
889     {
890       memcpy (&big_state->cull_face_state,
891               &src->big_state->cull_face_state,
892               sizeof (CoglPipelineCullFaceState));
893     }
894 
895   if (differences & COGL_PIPELINE_STATE_UNIFORMS)
896     {
897       int n_overrides =
898         _cogl_bitmask_popcount (&src->big_state->uniforms_state.override_mask);
899       int i;
900 
901       big_state->uniforms_state.override_values =
902         g_malloc (n_overrides * sizeof (CoglBoxedValue));
903 
904       for (i = 0; i < n_overrides; i++)
905         {
906           CoglBoxedValue *dst_bv =
907             big_state->uniforms_state.override_values + i;
908           const CoglBoxedValue *src_bv =
909             src->big_state->uniforms_state.override_values + i;
910 
911           _cogl_boxed_value_copy (dst_bv, src_bv);
912         }
913 
914       _cogl_bitmask_init (&big_state->uniforms_state.override_mask);
915       _cogl_bitmask_set_bits (&big_state->uniforms_state.override_mask,
916                               &src->big_state->uniforms_state.override_mask);
917 
918       _cogl_bitmask_init (&big_state->uniforms_state.changed_mask);
919     }
920 
921   if (differences & COGL_PIPELINE_STATE_VERTEX_SNIPPETS)
922     _cogl_pipeline_snippet_list_copy (&big_state->vertex_snippets,
923                                       &src->big_state->vertex_snippets);
924 
925   if (differences & COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS)
926     _cogl_pipeline_snippet_list_copy (&big_state->fragment_snippets,
927                                       &src->big_state->fragment_snippets);
928 
929   /* XXX: we shouldn't bother doing this in most cases since
930    * _copy_differences is typically used to initialize pipeline state
931    * by copying it from the current authority, so it's not actually
932    * *changing* anything.
933    */
934 check_for_blending_change:
935   if (differences & COGL_PIPELINE_STATE_AFFECTS_BLENDING)
936     dest->dirty_real_blend_enable = TRUE;
937 
938   dest->differences |= differences;
939 }
940 
941 static void
_cogl_pipeline_init_multi_property_sparse_state(CoglPipeline * pipeline,CoglPipelineState change)942 _cogl_pipeline_init_multi_property_sparse_state (CoglPipeline *pipeline,
943                                                  CoglPipelineState change)
944 {
945   CoglPipeline *authority;
946 
947   g_return_if_fail (change & COGL_PIPELINE_STATE_ALL_SPARSE);
948 
949   if (!(change & COGL_PIPELINE_STATE_MULTI_PROPERTY))
950     return;
951 
952   authority = _cogl_pipeline_get_authority (pipeline, change);
953 
954   switch (change)
955     {
956     /* XXX: avoid using a default: label so we get a warning if we
957      * don't explicitly handle a newly defined state-group here. */
958     case COGL_PIPELINE_STATE_COLOR:
959     case COGL_PIPELINE_STATE_ALPHA_FUNC:
960     case COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE:
961     case COGL_PIPELINE_STATE_NON_ZERO_POINT_SIZE:
962     case COGL_PIPELINE_STATE_POINT_SIZE:
963     case COGL_PIPELINE_STATE_USER_SHADER:
964     case COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE:
965     case COGL_PIPELINE_STATE_REAL_BLEND_ENABLE:
966       g_return_if_reached ();
967 
968     case COGL_PIPELINE_STATE_LAYERS:
969       pipeline->n_layers = authority->n_layers;
970       pipeline->layer_differences = NULL;
971       break;
972     case COGL_PIPELINE_STATE_BLEND:
973       {
974         memcpy (&pipeline->big_state->blend_state,
975                 &authority->big_state->blend_state,
976                 sizeof (CoglPipelineBlendState));
977         break;
978       }
979     case COGL_PIPELINE_STATE_DEPTH:
980       {
981         memcpy (&pipeline->big_state->depth_state,
982                 &authority->big_state->depth_state,
983                 sizeof (CoglDepthState));
984         break;
985       }
986     case COGL_PIPELINE_STATE_CULL_FACE:
987       {
988         memcpy (&pipeline->big_state->cull_face_state,
989                 &authority->big_state->cull_face_state,
990                 sizeof (CoglPipelineCullFaceState));
991         break;
992       }
993     case COGL_PIPELINE_STATE_UNIFORMS:
994       {
995         CoglPipelineUniformsState *uniforms_state =
996           &pipeline->big_state->uniforms_state;
997         _cogl_bitmask_init (&uniforms_state->override_mask);
998         _cogl_bitmask_init (&uniforms_state->changed_mask);
999         uniforms_state->override_values = NULL;
1000         break;
1001       }
1002     case COGL_PIPELINE_STATE_VERTEX_SNIPPETS:
1003       _cogl_pipeline_snippet_list_copy (&pipeline->big_state->vertex_snippets,
1004                                         &authority->big_state->vertex_snippets);
1005       break;
1006 
1007     case COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS:
1008       _cogl_pipeline_snippet_list_copy (&pipeline->big_state->fragment_snippets,
1009                                         &authority->big_state->
1010                                         fragment_snippets);
1011       break;
1012     }
1013 }
1014 
1015 static gboolean
check_if_strong_cb(CoglNode * node,void * user_data)1016 check_if_strong_cb (CoglNode *node, void *user_data)
1017 {
1018   CoglPipeline *pipeline = COGL_PIPELINE (node);
1019   gboolean *has_strong_child = user_data;
1020 
1021   if (!_cogl_pipeline_is_weak (pipeline))
1022     {
1023       *has_strong_child = TRUE;
1024       return FALSE;
1025     }
1026 
1027   return TRUE;
1028 }
1029 
1030 static gboolean
has_strong_children(CoglPipeline * pipeline)1031 has_strong_children (CoglPipeline *pipeline)
1032 {
1033   gboolean has_strong_child = FALSE;
1034   _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline),
1035                                      check_if_strong_cb,
1036                                      &has_strong_child);
1037   return has_strong_child;
1038 }
1039 
1040 static gboolean
_cogl_pipeline_is_weak(CoglPipeline * pipeline)1041 _cogl_pipeline_is_weak (CoglPipeline *pipeline)
1042 {
1043   if (pipeline->is_weak && !has_strong_children (pipeline))
1044     return TRUE;
1045   else
1046     return FALSE;
1047 }
1048 
1049 static gboolean
reparent_children_cb(CoglNode * node,void * user_data)1050 reparent_children_cb (CoglNode *node,
1051                       void *user_data)
1052 {
1053   CoglPipeline *pipeline = COGL_PIPELINE (node);
1054   CoglPipeline *parent = user_data;
1055 
1056   _cogl_pipeline_set_parent (pipeline, parent, TRUE);
1057 
1058   return TRUE;
1059 }
1060 
1061 void
_cogl_pipeline_pre_change_notify(CoglPipeline * pipeline,CoglPipelineState change,const CoglColor * new_color,gboolean from_layer_change)1062 _cogl_pipeline_pre_change_notify (CoglPipeline     *pipeline,
1063                                   CoglPipelineState change,
1064                                   const CoglColor  *new_color,
1065                                   gboolean          from_layer_change)
1066 {
1067   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1068 
1069   /* If primitives have been logged in the journal referencing the
1070    * current state of this pipeline we need to flush the journal
1071    * before we can modify it... */
1072   if (pipeline->journal_ref_count)
1073     {
1074       gboolean skip_journal_flush = FALSE;
1075 
1076       /* XXX: We don't usually need to flush the journal just due to
1077        * color changes since pipeline colors are logged in the
1078        * journal's vertex buffer. The exception is when the change in
1079        * color enables or disables the need for blending. */
1080       if (change == COGL_PIPELINE_STATE_COLOR)
1081         {
1082           gboolean will_need_blending =
1083             _cogl_pipeline_needs_blending_enabled (pipeline,
1084                                                    change,
1085                                                    new_color,
1086                                                    FALSE);
1087           gboolean blend_enable = pipeline->real_blend_enable ? TRUE : FALSE;
1088 
1089           if (will_need_blending == blend_enable)
1090             skip_journal_flush = TRUE;
1091         }
1092 
1093       if (!skip_journal_flush)
1094         {
1095           /* XXX: note we use cogl_flush() not _cogl_flush_journal() so
1096            * we will flush *all* known journals that might reference the
1097            * current pipeline. */
1098           cogl_flush ();
1099         }
1100     }
1101 
1102   /* XXX:
1103    * To simplify things for the vertex, fragment and program backends
1104    * we are careful about how we report STATE_LAYERS changes.
1105    *
1106    * All STATE_LAYERS change notifications with the exception of
1107    * ->n_layers will also result in layer_pre_change_notifications.
1108    *
1109    * For backends that perform code generation for fragment processing
1110    * they typically need to understand the details of how layers get
1111    * changed to determine if they need to repeat codegen.  It doesn't
1112    * help them to report a pipeline STATE_LAYERS change for all layer
1113    * changes since it's so broad, they really need to wait for the
1114    * specific layer change to be notified.  What does help though is
1115    * to report a STATE_LAYERS change for a change in ->n_layers
1116    * because they typically do need to repeat codegen in that case.
1117    *
1118    * Here we ensure that change notifications against a pipeline or
1119    * against a layer are mutually exclusive as far as fragment, vertex
1120    * and program backends are concerned.
1121    *
1122    * NB: A pipeline can potentially have private state from multiple
1123    * backends associated with it because descendants may cache state
1124    * with an ancestor to maximize the chance that it can later be
1125    * re-used by other descendants and a descendent can require a
1126    * different backend to an ancestor.
1127    */
1128   if (!from_layer_change)
1129     {
1130       const CoglPipelineProgend *progend = _cogl_pipeline_progend;
1131       const CoglPipelineVertend *vertend = _cogl_pipeline_vertend;
1132       const CoglPipelineFragend *fragend = _cogl_pipeline_fragend;
1133 
1134       if (vertend->pipeline_pre_change_notify)
1135         vertend->pipeline_pre_change_notify (pipeline, change, new_color);
1136 
1137       /* TODO: make the vertend and fragend implementation details
1138        * of the progend */
1139 
1140       if (fragend->pipeline_pre_change_notify)
1141         fragend->pipeline_pre_change_notify (pipeline, change, new_color);
1142 
1143       if (progend->pipeline_pre_change_notify)
1144         progend->pipeline_pre_change_notify (pipeline, change, new_color);
1145     }
1146 
1147   /* There may be an arbitrary tree of descendants of this pipeline;
1148    * any of which may indirectly depend on this pipeline as the
1149    * authority for some set of properties. (Meaning for example that
1150    * one of its descendants derives its color or blending state from
1151    * this pipeline.)
1152    *
1153    * We can't modify any property that this pipeline is the authority
1154    * for unless we create another pipeline to take its place first and
1155    * make sure descendants reference this new pipeline instead.
1156    */
1157 
1158   /* The simplest descendants to handle are weak pipelines; we simply
1159    * destroy them if we are modifying a pipeline they depend on. This
1160    * means weak pipelines never cause us to do a copy-on-write. */
1161   _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline),
1162                                      destroy_weak_children_cb,
1163                                      NULL);
1164 
1165   /* If there are still children remaining though we'll need to
1166    * perform a copy-on-write and reparent the dependants as children
1167    * of the copy. */
1168   if (!_cogl_list_empty (&COGL_NODE (pipeline)->children))
1169     {
1170       CoglPipeline *new_authority;
1171 
1172       COGL_STATIC_COUNTER (pipeline_copy_on_write_counter,
1173                            "pipeline copy on write counter",
1174                            "Increments each time a pipeline "
1175                            "must be copied to allow modification",
1176                            0 /* no application private data */);
1177 
1178       COGL_COUNTER_INC (_cogl_uprof_context, pipeline_copy_on_write_counter);
1179 
1180       new_authority =
1181         cogl_pipeline_copy (_cogl_pipeline_get_parent (pipeline));
1182 #ifdef COGL_DEBUG_ENABLED
1183       _cogl_pipeline_set_static_breadcrumb (new_authority,
1184                                             "pre_change_notify:copy-on-write");
1185 #endif
1186 
1187       /* We could explicitly walk the descendants, OR together the set
1188        * of differences that we determine this pipeline is the
1189        * authority on and only copy those differences copied across.
1190        *
1191        * Or, if we don't explicitly walk the descendants we at least
1192        * know that pipeline->differences represents the largest set of
1193        * differences that this pipeline could possibly be an authority
1194        * on.
1195        *
1196        * We do the later just because it's simplest, but we might need
1197        * to come back to this later...
1198        */
1199       _cogl_pipeline_copy_differences (new_authority, pipeline,
1200                                        pipeline->differences);
1201 
1202       /* Reparent the dependants of pipeline to be children of
1203        * new_authority instead... */
1204       _cogl_pipeline_node_foreach_child (COGL_NODE (pipeline),
1205                                          reparent_children_cb,
1206                                          new_authority);
1207 
1208       /* The children will keep the new authority alive so drop the
1209        * reference we got when copying... */
1210       cogl_object_unref (new_authority);
1211     }
1212 
1213   /* At this point we know we have a pipeline with no strong
1214    * dependants (though we may have some weak children) so we are now
1215    * free to modify the pipeline. */
1216 
1217   pipeline->age++;
1218 
1219   if (change & COGL_PIPELINE_STATE_NEEDS_BIG_STATE &&
1220       !pipeline->has_big_state)
1221     {
1222       pipeline->big_state = g_new0 (CoglPipelineBigState, 1);
1223       pipeline->has_big_state = TRUE;
1224     }
1225 
1226   /* Note: conceptually we have just been notified that a single
1227    * property value is about to change, but since some state-groups
1228    * contain multiple properties and 'pipeline' is about to take over
1229    * being the authority for the property's corresponding state-group
1230    * we need to maintain the integrity of the other property values
1231    * too.
1232    *
1233    * To ensure this we handle multi-property state-groups by copying
1234    * all the values from the old-authority to the new...
1235    *
1236    * We don't have to worry about non-sparse property groups since
1237    * we never take over being an authority for such properties so
1238    * they automatically maintain integrity.
1239    */
1240   if (change & COGL_PIPELINE_STATE_ALL_SPARSE &&
1241       !(pipeline->differences & change))
1242     {
1243       _cogl_pipeline_init_multi_property_sparse_state (pipeline, change);
1244       pipeline->differences |= change;
1245     }
1246 
1247   /* Each pipeline has a sorted cache of the layers it depends on
1248    * which will need updating via _cogl_pipeline_update_layers_cache
1249    * if a pipeline's layers are changed. */
1250   if (change == COGL_PIPELINE_STATE_LAYERS)
1251     recursively_free_layer_caches (pipeline);
1252 
1253   /* If the pipeline being changed is the same as the last pipeline we
1254    * flushed then we keep a track of the changes so we can try to
1255    * minimize redundant OpenGL calls if the same pipeline is flushed
1256    * again.
1257    */
1258   if (ctx->current_pipeline == pipeline)
1259     ctx->current_pipeline_changes_since_flush |= change;
1260 }
1261 
1262 
1263 void
_cogl_pipeline_add_layer_difference(CoglPipeline * pipeline,CoglPipelineLayer * layer,gboolean inc_n_layers)1264 _cogl_pipeline_add_layer_difference (CoglPipeline *pipeline,
1265                                      CoglPipelineLayer *layer,
1266                                      gboolean inc_n_layers)
1267 {
1268   g_return_if_fail (layer->owner == NULL);
1269 
1270   layer->owner = pipeline;
1271   cogl_object_ref (layer);
1272 
1273   /* - Flush journal primitives referencing the current state.
1274    * - Make sure the pipeline has no dependants so it may be modified.
1275    * - If the pipeline isn't currently an authority for the state being
1276    *   changed, then initialize that state from the current authority.
1277    */
1278   /* Note: the last argument to _cogl_pipeline_pre_change_notify is
1279    * needed to differentiate STATE_LAYER changes which don't affect
1280    * the number of layers from those that do. NB: Layer change
1281    * notifications that don't change the number of layers don't get
1282    * forwarded to the fragend. */
1283   _cogl_pipeline_pre_change_notify (pipeline,
1284                                     COGL_PIPELINE_STATE_LAYERS,
1285                                     NULL,
1286                                     !inc_n_layers);
1287 
1288   pipeline->differences |= COGL_PIPELINE_STATE_LAYERS;
1289 
1290   pipeline->layer_differences =
1291     g_list_prepend (pipeline->layer_differences, layer);
1292 
1293   if (inc_n_layers)
1294     pipeline->n_layers++;
1295 
1296   /* Adding a layer difference may mean this pipeline now overrides
1297    * all of the layers of its parent which might make the parent
1298    * redundant so we should try to prune the hierarchy */
1299   _cogl_pipeline_prune_redundant_ancestry (pipeline);
1300 }
1301 
1302 void
_cogl_pipeline_remove_layer_difference(CoglPipeline * pipeline,CoglPipelineLayer * layer,gboolean dec_n_layers)1303 _cogl_pipeline_remove_layer_difference (CoglPipeline *pipeline,
1304                                         CoglPipelineLayer *layer,
1305                                         gboolean dec_n_layers)
1306 {
1307   /* - Flush journal primitives referencing the current state.
1308    * - Make sure the pipeline has no dependants so it may be modified.
1309    * - If the pipeline isn't currently an authority for the state being
1310    *   changed, then initialize that state from the current authority.
1311    */
1312   /* Note: the last argument to _cogl_pipeline_pre_change_notify is
1313    * needed to differentiate STATE_LAYER changes which don't affect
1314    * the number of layers from those that do. NB: Layer change
1315    * notifications that don't change the number of layers don't get
1316    * forwarded to the fragend. */
1317   _cogl_pipeline_pre_change_notify (pipeline,
1318                                     COGL_PIPELINE_STATE_LAYERS,
1319                                     NULL,
1320                                     !dec_n_layers);
1321 
1322   /* We only need to remove the layer difference if the pipeline is
1323    * currently the owner. If it is not the owner then one of two
1324    * things will happen to make sure this layer is replaced. If it is
1325    * the last layer being removed then decrementing n_layers will
1326    * ensure that the last layer is skipped. If it is any other layer
1327    * then the subsequent layers will have been shifted down and cause
1328    * it be replaced */
1329   if (layer->owner == pipeline)
1330     {
1331       layer->owner = NULL;
1332       cogl_object_unref (layer);
1333 
1334       pipeline->layer_differences =
1335         g_list_remove (pipeline->layer_differences, layer);
1336     }
1337 
1338   pipeline->differences |= COGL_PIPELINE_STATE_LAYERS;
1339 
1340   if (dec_n_layers)
1341     pipeline->n_layers--;
1342 }
1343 
1344 static void
_cogl_pipeline_try_reverting_layers_authority(CoglPipeline * authority,CoglPipeline * old_authority)1345 _cogl_pipeline_try_reverting_layers_authority (CoglPipeline *authority,
1346                                                CoglPipeline *old_authority)
1347 {
1348   if (authority->layer_differences == NULL &&
1349       _cogl_pipeline_get_parent (authority))
1350     {
1351       /* If the previous _STATE_LAYERS authority has the same
1352        * ->n_layers then we can revert to that being the authority
1353        *  again. */
1354       if (!old_authority)
1355         {
1356           old_authority =
1357             _cogl_pipeline_get_authority (_cogl_pipeline_get_parent (authority),
1358                                           COGL_PIPELINE_STATE_LAYERS);
1359         }
1360 
1361       if (old_authority->n_layers == authority->n_layers)
1362         authority->differences &= ~COGL_PIPELINE_STATE_LAYERS;
1363     }
1364 }
1365 
1366 void
_cogl_pipeline_update_real_blend_enable(CoglPipeline * pipeline,gboolean unknown_color_alpha)1367 _cogl_pipeline_update_real_blend_enable (CoglPipeline *pipeline,
1368                                          gboolean unknown_color_alpha)
1369 {
1370   CoglPipeline *parent;
1371   unsigned int differences;
1372 
1373   if (pipeline->dirty_real_blend_enable == FALSE &&
1374       pipeline->unknown_color_alpha == unknown_color_alpha)
1375     return;
1376 
1377   if (pipeline->dirty_real_blend_enable)
1378     {
1379       differences = pipeline->differences;
1380 
1381       parent = _cogl_pipeline_get_parent (pipeline);
1382       while (parent->dirty_real_blend_enable)
1383         {
1384           differences |= parent->differences;
1385           parent = _cogl_pipeline_get_parent (parent);
1386         }
1387 
1388       /* We initialize the pipeline's real_blend_enable with a known
1389        * reference value from its nearest ancestor with clean state so
1390        * we can then potentially reduce the work involved in checking
1391        * if the pipeline really needs blending itself because we can
1392        * just look at the things that differ between the ancestor and
1393        * this pipeline.
1394        */
1395       pipeline->real_blend_enable = parent->real_blend_enable;
1396     }
1397   else /* pipeline->unknown_color_alpha != unknown_color_alpha */
1398     differences = 0;
1399 
1400   /* Note we don't call _cogl_pipeline_pre_change_notify() for this
1401    * state change because ->real_blend_enable is lazily derived from
1402    * other state while flushing the pipeline and we'd need to avoid
1403    * recursion problems in cases where _pre_change_notify() flushes
1404    * the journal if the pipeline is referenced by a journal.
1405    */
1406   pipeline->real_blend_enable =
1407     _cogl_pipeline_needs_blending_enabled (pipeline, differences,
1408                                            NULL, unknown_color_alpha);
1409   pipeline->dirty_real_blend_enable = FALSE;
1410   pipeline->unknown_color_alpha = unknown_color_alpha;
1411 }
1412 
1413 typedef struct
1414 {
1415   int keep_n;
1416   int current_pos;
1417   int first_index_to_prune;
1418 } CoglPipelinePruneLayersInfo;
1419 
1420 static gboolean
update_prune_layers_info_cb(CoglPipelineLayer * layer,void * user_data)1421 update_prune_layers_info_cb (CoglPipelineLayer *layer, void *user_data)
1422 {
1423   CoglPipelinePruneLayersInfo *state = user_data;
1424 
1425   if (state->current_pos == state->keep_n)
1426     {
1427       state->first_index_to_prune = layer->index;
1428       return FALSE;
1429     }
1430   state->current_pos++;
1431   return TRUE;
1432 }
1433 
1434 void
_cogl_pipeline_prune_to_n_layers(CoglPipeline * pipeline,int n)1435 _cogl_pipeline_prune_to_n_layers (CoglPipeline *pipeline, int n)
1436 {
1437   CoglPipeline *authority =
1438     _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LAYERS);
1439   CoglPipelinePruneLayersInfo state;
1440   GList *l;
1441   GList *next;
1442 
1443   if (authority->n_layers <= n)
1444     return;
1445 
1446   /* This call to foreach_layer_internal needs to be done before
1447    * calling pre_change_notify because it recreates the layer cache.
1448    * We are relying on pre_change_notify to clear the layer cache
1449    * before we change the number of layers */
1450   state.keep_n = n;
1451   state.current_pos = 0;
1452   _cogl_pipeline_foreach_layer_internal (pipeline,
1453                                          update_prune_layers_info_cb,
1454                                          &state);
1455 
1456   _cogl_pipeline_pre_change_notify (pipeline,
1457                                     COGL_PIPELINE_STATE_LAYERS,
1458                                     NULL,
1459                                     FALSE);
1460 
1461   pipeline->differences |= COGL_PIPELINE_STATE_LAYERS;
1462   pipeline->n_layers = n;
1463 
1464   /* It's possible that this pipeline owns some of the layers being
1465    * discarded, so we'll need to unlink them... */
1466   for (l = pipeline->layer_differences; l; l = next)
1467     {
1468       CoglPipelineLayer *layer = l->data;
1469       next = l->next; /* we're modifying the list we're iterating */
1470 
1471       if (layer->index >= state.first_index_to_prune)
1472         _cogl_pipeline_remove_layer_difference (pipeline, layer, FALSE);
1473     }
1474 
1475   pipeline->differences |= COGL_PIPELINE_STATE_LAYERS;
1476 }
1477 
1478 typedef struct
1479 {
1480   /* The layer we are trying to find */
1481   int                         layer_index;
1482 
1483   /* The layer we find or untouched if not found */
1484   CoglPipelineLayer          *layer;
1485 
1486   /* If the layer can't be found then a new layer should be
1487    * inserted after this texture unit index... */
1488   int                         insert_after;
1489 
1490   /* When adding a layer we need the list of layers to shift up
1491    * to a new texture unit. When removing we need the list of
1492    * layers to shift down.
1493    *
1494    * Note: the list isn't sorted */
1495   CoglPipelineLayer         **layers_to_shift;
1496   int                         n_layers_to_shift;
1497 
1498   /* When adding a layer we don't need a complete list of
1499    * layers_to_shift if we find a layer already corresponding to the
1500    * layer_index.  */
1501   gboolean                    ignore_shift_layers_if_found;
1502 
1503 } CoglPipelineLayerInfo;
1504 
1505 /* Returns TRUE once we know there is nothing more to update */
1506 static gboolean
update_layer_info(CoglPipelineLayer * layer,CoglPipelineLayerInfo * layer_info)1507 update_layer_info (CoglPipelineLayer *layer,
1508                    CoglPipelineLayerInfo *layer_info)
1509 {
1510   if (layer->index == layer_info->layer_index)
1511     {
1512       layer_info->layer = layer;
1513       if (layer_info->ignore_shift_layers_if_found)
1514         return TRUE;
1515     }
1516   else if (layer->index < layer_info->layer_index)
1517     {
1518       int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
1519       layer_info->insert_after = unit_index;
1520     }
1521   else
1522     layer_info->layers_to_shift[layer_info->n_layers_to_shift++] =
1523       layer;
1524 
1525   return FALSE;
1526 }
1527 
1528 /* Returns FALSE to break out of a _foreach_layer () iteration */
1529 static gboolean
update_layer_info_cb(CoglPipelineLayer * layer,void * user_data)1530 update_layer_info_cb (CoglPipelineLayer *layer,
1531                       void *user_data)
1532 {
1533   CoglPipelineLayerInfo *layer_info = user_data;
1534 
1535   if (update_layer_info (layer, layer_info))
1536     return FALSE; /* break */
1537   else
1538     return TRUE; /* continue */
1539 }
1540 
1541 static void
_cogl_pipeline_get_layer_info(CoglPipeline * pipeline,CoglPipelineLayerInfo * layer_info)1542 _cogl_pipeline_get_layer_info (CoglPipeline *pipeline,
1543                                CoglPipelineLayerInfo *layer_info)
1544 {
1545   /* Note: we are assuming this pipeline is a _STATE_LAYERS authority */
1546   int n_layers = pipeline->n_layers;
1547   int i;
1548 
1549   /* FIXME: _cogl_pipeline_foreach_layer_internal now calls
1550    * _cogl_pipeline_update_layers_cache anyway so this codepath is
1551    * pointless! */
1552   if (layer_info->ignore_shift_layers_if_found &&
1553       pipeline->layers_cache_dirty)
1554     {
1555       /* The expectation is that callers of
1556        * _cogl_pipeline_get_layer_info are likely to be modifying the
1557        * list of layers associated with a pipeline so in this case
1558        * where we don't have a cache of the layers and we don't
1559        * necessarily have to iterate all the layers of the pipeline we
1560        * use a foreach_layer callback instead of updating the cache
1561        * and iterating that as below. */
1562       _cogl_pipeline_foreach_layer_internal (pipeline,
1563                                              update_layer_info_cb,
1564                                              layer_info);
1565       return;
1566     }
1567 
1568   _cogl_pipeline_update_layers_cache (pipeline);
1569   for (i = 0; i < n_layers; i++)
1570     {
1571       CoglPipelineLayer *layer = pipeline->layers_cache[i];
1572 
1573       if (update_layer_info (layer, layer_info))
1574         return;
1575     }
1576 }
1577 
1578 CoglPipelineLayer *
_cogl_pipeline_get_layer_with_flags(CoglPipeline * pipeline,int layer_index,CoglPipelineGetLayerFlags flags)1579 _cogl_pipeline_get_layer_with_flags (CoglPipeline *pipeline,
1580                                      int layer_index,
1581                                      CoglPipelineGetLayerFlags flags)
1582 {
1583   CoglPipeline *authority =
1584     _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LAYERS);
1585   CoglPipelineLayerInfo layer_info;
1586   CoglPipelineLayer *layer;
1587   int unit_index;
1588   int i;
1589   CoglContext *ctx;
1590 
1591   /* The layer index of the layer we want info about */
1592   layer_info.layer_index = layer_index;
1593 
1594   /* If a layer already exists with the given index this will be
1595    * updated. */
1596   layer_info.layer = NULL;
1597 
1598   /* If a layer isn't found for the given index we'll need to know
1599    * where to insert a new layer. */
1600   layer_info.insert_after = -1;
1601 
1602   /* If a layer can't be found then we'll need to insert a new layer
1603    * and bump up the texture unit for all layers with an index
1604    * > layer_index. */
1605   layer_info.layers_to_shift =
1606     g_alloca (sizeof (CoglPipelineLayer *) * authority->n_layers);
1607   layer_info.n_layers_to_shift = 0;
1608 
1609   /* If an exact match is found though we don't need a complete
1610    * list of layers with indices > layer_index... */
1611   layer_info.ignore_shift_layers_if_found = TRUE;
1612 
1613   _cogl_pipeline_get_layer_info (authority, &layer_info);
1614 
1615   if (layer_info.layer || (flags & COGL_PIPELINE_GET_LAYER_NO_CREATE))
1616     return layer_info.layer;
1617 
1618   ctx = _cogl_context_get_default ();
1619 
1620   unit_index = layer_info.insert_after + 1;
1621   if (unit_index == 0)
1622     layer = _cogl_pipeline_layer_copy (ctx->default_layer_0);
1623   else
1624     {
1625       CoglPipelineLayer *new;
1626       layer = _cogl_pipeline_layer_copy (ctx->default_layer_n);
1627       new = _cogl_pipeline_set_layer_unit (NULL, layer, unit_index);
1628       /* Since we passed a newly allocated layer we wouldn't expect
1629        * _set_layer_unit() to have to allocate *another* layer. */
1630       g_assert (new == layer);
1631     }
1632   layer->index = layer_index;
1633 
1634   for (i = 0; i < layer_info.n_layers_to_shift; i++)
1635     {
1636       CoglPipelineLayer *shift_layer = layer_info.layers_to_shift[i];
1637 
1638       unit_index = _cogl_pipeline_layer_get_unit_index (shift_layer);
1639       _cogl_pipeline_set_layer_unit (pipeline, shift_layer, unit_index + 1);
1640       /* NB: shift_layer may not be writeable so _set_layer_unit()
1641        * will allocate a derived layer internally which will become
1642        * owned by pipeline. Check the return value if we need to do
1643        * anything else with this layer. */
1644     }
1645 
1646   _cogl_pipeline_add_layer_difference (pipeline, layer, TRUE);
1647 
1648   cogl_object_unref (layer);
1649 
1650   return layer;
1651 }
1652 
1653 void
_cogl_pipeline_prune_empty_layer_difference(CoglPipeline * layers_authority,CoglPipelineLayer * layer)1654 _cogl_pipeline_prune_empty_layer_difference (CoglPipeline *layers_authority,
1655                                              CoglPipelineLayer *layer)
1656 {
1657   /* Find the GList link that references the empty layer */
1658   GList *link = g_list_find (layers_authority->layer_differences, layer);
1659   /* No pipeline directly owns the root node layer so this is safe... */
1660   CoglPipelineLayer *layer_parent = _cogl_pipeline_layer_get_parent (layer);
1661   CoglPipelineLayerInfo layer_info;
1662   CoglPipeline *old_layers_authority;
1663 
1664   g_return_if_fail (link != NULL);
1665 
1666   /* If the layer's parent doesn't have an owner then we can simply
1667    * take ownership ourselves and drop our reference on the empty
1668    * layer. We don't want to take ownership of the root node layer so
1669    * we also need to verify that the parent has a parent
1670    */
1671   if (layer_parent->index == layer->index && layer_parent->owner == NULL &&
1672       _cogl_pipeline_layer_get_parent (layer_parent) != NULL)
1673     {
1674       cogl_object_ref (layer_parent);
1675       layer_parent->owner = layers_authority;
1676       link->data = layer_parent;
1677       cogl_object_unref (layer);
1678       recursively_free_layer_caches (layers_authority);
1679       return;
1680     }
1681 
1682   /* Now we want to find the layer that would become the authority for
1683    * layer->index if we were to remove layer from
1684    * layers_authority->layer_differences
1685    */
1686 
1687   /* The layer index of the layer we want info about */
1688   layer_info.layer_index = layer->index;
1689 
1690   /* If a layer already exists with the given index this will be
1691    * updated. */
1692   layer_info.layer = NULL;
1693 
1694   /* If a layer can't be found then we'll need to insert a new layer
1695    * and bump up the texture unit for all layers with an index
1696    * > layer_index. */
1697   layer_info.layers_to_shift =
1698     g_alloca (sizeof (CoglPipelineLayer *) * layers_authority->n_layers);
1699   layer_info.n_layers_to_shift = 0;
1700 
1701   /* If an exact match is found though we don't need a complete
1702    * list of layers with indices > layer_index... */
1703   layer_info.ignore_shift_layers_if_found = TRUE;
1704 
1705   /* We know the default/root pipeline isn't a LAYERS authority so it's
1706    * safe to use the result of _cogl_pipeline_get_parent (layers_authority)
1707    * without checking it.
1708    */
1709   old_layers_authority =
1710     _cogl_pipeline_get_authority (_cogl_pipeline_get_parent (layers_authority),
1711                                   COGL_PIPELINE_STATE_LAYERS);
1712 
1713   _cogl_pipeline_get_layer_info (old_layers_authority, &layer_info);
1714 
1715   /* If layer is the defining layer for the corresponding ->index then
1716    * we can't get rid of it. */
1717   if (!layer_info.layer)
1718     return;
1719 
1720   /* If the layer that would become the authority for layer->index is
1721    * _cogl_pipeline_layer_get_parent (layer) then we can simply remove the
1722    * layer difference. */
1723   if (layer_info.layer == _cogl_pipeline_layer_get_parent (layer))
1724     {
1725       _cogl_pipeline_remove_layer_difference (layers_authority, layer, FALSE);
1726       _cogl_pipeline_try_reverting_layers_authority (layers_authority,
1727                                                      old_layers_authority);
1728     }
1729 }
1730 
1731 typedef struct
1732 {
1733   int i;
1734   CoglPipeline *pipeline;
1735   unsigned long fallback_layers;
1736 } CoglPipelineFallbackState;
1737 
1738 static gboolean
fallback_layer_cb(CoglPipelineLayer * layer,void * user_data)1739 fallback_layer_cb (CoglPipelineLayer *layer, void *user_data)
1740 {
1741   CoglPipelineFallbackState *state = user_data;
1742   CoglPipeline *pipeline = state->pipeline;
1743   CoglTexture *texture = NULL;
1744   COGL_STATIC_COUNTER (layer_fallback_counter,
1745                        "layer fallback counter",
1746                        "Increments each time a layer's texture is "
1747                        "forced to a fallback texture",
1748                        0 /* no application private data */);
1749 
1750   _COGL_GET_CONTEXT (ctx, FALSE);
1751 
1752   if (!(state->fallback_layers & 1<<state->i))
1753     return TRUE;
1754 
1755   COGL_COUNTER_INC (_cogl_uprof_context, layer_fallback_counter);
1756 
1757   texture = COGL_TEXTURE (ctx->default_gl_texture_2d_tex);
1758 
1759   if (texture == NULL)
1760     {
1761       g_warning ("We don't have a fallback texture we can use to fill "
1762                  "in for an invalid pipeline layer, since it was "
1763                  "using an unsupported texture target ");
1764       /* might get away with this... */
1765       texture = COGL_TEXTURE (ctx->default_gl_texture_2d_tex);
1766     }
1767 
1768   cogl_pipeline_set_layer_texture (pipeline, layer->index, texture);
1769 
1770   state->i++;
1771 
1772   return TRUE;
1773 }
1774 
1775 typedef struct
1776 {
1777   CoglPipeline *pipeline;
1778   CoglTexture *texture;
1779 } CoglPipelineOverrideLayerState;
1780 
1781 static gboolean
override_layer_texture_cb(CoglPipelineLayer * layer,void * user_data)1782 override_layer_texture_cb (CoglPipelineLayer *layer, void *user_data)
1783 {
1784   CoglPipelineOverrideLayerState *state = user_data;
1785 
1786   cogl_pipeline_set_layer_texture (state->pipeline,
1787                                    layer->index,
1788                                    state->texture);
1789 
1790   return TRUE;
1791 }
1792 
1793 void
_cogl_pipeline_apply_overrides(CoglPipeline * pipeline,CoglPipelineFlushOptions * options)1794 _cogl_pipeline_apply_overrides (CoglPipeline *pipeline,
1795                                 CoglPipelineFlushOptions *options)
1796 {
1797   COGL_STATIC_COUNTER (apply_overrides_counter,
1798                        "pipeline overrides counter",
1799                        "Increments each time we have to apply "
1800                        "override options to a pipeline",
1801                        0 /* no application private data */);
1802 
1803   COGL_COUNTER_INC (_cogl_uprof_context, apply_overrides_counter);
1804 
1805   if (options->flags & COGL_PIPELINE_FLUSH_DISABLE_MASK)
1806     {
1807       int i;
1808 
1809       /* NB: we can assume that once we see one bit to disable
1810        * a layer, all subsequent layers are also disabled. */
1811       for (i = 0; i < 32 && options->disable_layers & (1<<i); i++)
1812         ;
1813 
1814       _cogl_pipeline_prune_to_n_layers (pipeline, i);
1815     }
1816 
1817   if (options->flags & COGL_PIPELINE_FLUSH_FALLBACK_MASK)
1818     {
1819       CoglPipelineFallbackState state;
1820 
1821       state.i = 0;
1822       state.pipeline = pipeline;
1823       state.fallback_layers = options->fallback_layers;
1824 
1825       _cogl_pipeline_foreach_layer_internal (pipeline,
1826                                              fallback_layer_cb,
1827                                              &state);
1828     }
1829 
1830   if (options->flags & COGL_PIPELINE_FLUSH_LAYER0_OVERRIDE)
1831     {
1832       CoglPipelineOverrideLayerState state;
1833 
1834       _cogl_pipeline_prune_to_n_layers (pipeline, 1);
1835 
1836       /* NB: we are overriding the first layer, but we don't know
1837        * the user's given layer_index, which is why we use
1838        * _cogl_pipeline_foreach_layer_internal() here even though we know
1839        * there's only one layer. */
1840       state.pipeline = pipeline;
1841       state.texture = options->layer0_override_texture;
1842       _cogl_pipeline_foreach_layer_internal (pipeline,
1843                                              override_layer_texture_cb,
1844                                              &state);
1845     }
1846 }
1847 
1848 static gboolean
_cogl_pipeline_layers_equal(CoglPipeline * authority0,CoglPipeline * authority1,unsigned long differences,CoglPipelineEvalFlags flags)1849 _cogl_pipeline_layers_equal (CoglPipeline *authority0,
1850                              CoglPipeline *authority1,
1851                              unsigned long differences,
1852                              CoglPipelineEvalFlags flags)
1853 {
1854   int i;
1855 
1856   if (authority0->n_layers != authority1->n_layers)
1857     return FALSE;
1858 
1859   _cogl_pipeline_update_layers_cache (authority0);
1860   _cogl_pipeline_update_layers_cache (authority1);
1861 
1862   for (i = 0; i < authority0->n_layers; i++)
1863     {
1864       if (!_cogl_pipeline_layer_equal (authority0->layers_cache[i],
1865                                        authority1->layers_cache[i],
1866                                        differences,
1867                                        flags))
1868         return FALSE;
1869     }
1870   return TRUE;
1871 }
1872 
1873 /* Determine the mask of differences between two pipelines */
1874 unsigned long
_cogl_pipeline_compare_differences(CoglPipeline * pipeline0,CoglPipeline * pipeline1)1875 _cogl_pipeline_compare_differences (CoglPipeline *pipeline0,
1876                                     CoglPipeline *pipeline1)
1877 {
1878   GSList *head0 = NULL;
1879   GSList *head1 = NULL;
1880   CoglPipeline *node0;
1881   CoglPipeline *node1;
1882   int len0 = 0;
1883   int len1 = 0;
1884   int count;
1885   GSList *common_ancestor0;
1886   GSList *common_ancestor1;
1887   unsigned long pipelines_difference = 0;
1888 
1889   /* Algorithm:
1890    *
1891    * 1) Walk the ancestors of each pipeline to the root node, adding a
1892    *    pointer to each ancester node to two linked lists
1893    *
1894    * 2) Compare the lists to find the nodes where they start to
1895    *    differ marking the common_ancestor node for each list.
1896    *
1897    * 3) For each list now iterate starting after the common_ancestor
1898    *    nodes ORing each nodes ->difference mask into the final
1899    *    differences mask.
1900    */
1901 
1902   for (node0 = pipeline0; node0; node0 = _cogl_pipeline_get_parent (node0))
1903     {
1904       GSList *link = alloca (sizeof (GSList));
1905       link->next = head0;
1906       link->data = node0;
1907       head0 = link;
1908       len0++;
1909     }
1910   for (node1 = pipeline1; node1; node1 = _cogl_pipeline_get_parent (node1))
1911     {
1912       GSList *link = alloca (sizeof (GSList));
1913       link->next = head1;
1914       link->data = node1;
1915       head1 = link;
1916       len1++;
1917     }
1918 
1919   /* NB: There's no point looking at the head entries since we know both
1920    * pipelines must have the same default pipeline as their root node. */
1921   common_ancestor0 = head0;
1922   common_ancestor1 = head1;
1923   head0 = head0->next;
1924   head1 = head1->next;
1925   count = MIN (len0, len1) - 1;
1926   while (count--)
1927     {
1928       if (head0->data != head1->data)
1929         break;
1930       common_ancestor0 = head0;
1931       common_ancestor1 = head1;
1932       head0 = head0->next;
1933       head1 = head1->next;
1934     }
1935 
1936   for (head0 = common_ancestor0->next; head0; head0 = head0->next)
1937     {
1938       node0 = head0->data;
1939       pipelines_difference |= node0->differences;
1940     }
1941   for (head1 = common_ancestor1->next; head1; head1 = head1->next)
1942     {
1943       node1 = head1->data;
1944       pipelines_difference |= node1->differences;
1945     }
1946 
1947   return pipelines_difference;
1948 }
1949 
1950 static void
_cogl_pipeline_resolve_authorities(CoglPipeline * pipeline,unsigned long differences,CoglPipeline ** authorities)1951 _cogl_pipeline_resolve_authorities (CoglPipeline *pipeline,
1952                                     unsigned long differences,
1953                                     CoglPipeline **authorities)
1954 {
1955   unsigned long remaining = differences;
1956   CoglPipeline *authority = pipeline;
1957 
1958   do
1959     {
1960       unsigned long found = authority->differences & remaining;
1961       int i;
1962 
1963       if (found == 0)
1964         continue;
1965 
1966       for (i = 0; TRUE; i++)
1967         {
1968           unsigned long state = (1L<<i);
1969 
1970           if (state & found)
1971             authorities[i] = authority;
1972           else if (state > found)
1973             break;
1974         }
1975 
1976       remaining &= ~found;
1977       if (remaining == 0)
1978         return;
1979     }
1980   while ((authority = _cogl_pipeline_get_parent (authority)));
1981 
1982   g_assert (remaining == 0);
1983 }
1984 
1985 /* Comparison of two arbitrary pipelines is done by:
1986  * 1) walking up the parents of each pipeline until a common
1987  *    ancestor is found, and at each step ORing together the
1988  *    difference masks.
1989  *
1990  * 2) using the final difference mask to determine which state
1991  *    groups to compare.
1992  *
1993  * This is used, for example, by the Cogl journal to compare pipelines so that
1994  * it can split up geometry that needs different OpenGL state.
1995  *
1996  * XXX: When comparing texture layers, _cogl_pipeline_equal will actually
1997  * compare the underlying GL texture handle that the Cogl texture uses so that
1998  * atlas textures and sub textures will be considered equal if they point to
1999  * the same texture. This is useful for comparing pipelines in the journal but
2000  * it means that _cogl_pipeline_equal doesn't strictly compare whether the
2001  * pipelines are the same. If we needed those semantics we could perhaps add
2002  * another function or some flags to control the behaviour.
2003  *
2004  * XXX: Similarly when comparing the wrap modes,
2005  * COGL_PIPELINE_WRAP_MODE_AUTOMATIC is considered to be the same as
2006  * COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE because once they get to the
2007  * journal stage they act exactly the same.
2008  */
2009 gboolean
_cogl_pipeline_equal(CoglPipeline * pipeline0,CoglPipeline * pipeline1,unsigned int differences,unsigned long layer_differences,CoglPipelineEvalFlags flags)2010 _cogl_pipeline_equal (CoglPipeline *pipeline0,
2011                       CoglPipeline *pipeline1,
2012                       unsigned int differences,
2013                       unsigned long layer_differences,
2014                       CoglPipelineEvalFlags flags)
2015 {
2016   unsigned long pipelines_difference;
2017   CoglPipeline *authorities0[COGL_PIPELINE_STATE_SPARSE_COUNT];
2018   CoglPipeline *authorities1[COGL_PIPELINE_STATE_SPARSE_COUNT];
2019   int bit;
2020   gboolean ret;
2021 
2022   COGL_STATIC_TIMER (pipeline_equal_timer,
2023                      "Mainloop", /* parent */
2024                      "_cogl_pipeline_equal",
2025                      "The time spent comparing cogl pipelines",
2026                      0 /* no application private data */);
2027 
2028   COGL_TIMER_START (_cogl_uprof_context, pipeline_equal_timer);
2029 
2030   if (pipeline0 == pipeline1)
2031     {
2032       ret = TRUE;
2033       goto done;
2034     }
2035 
2036   ret = FALSE;
2037 
2038   _cogl_pipeline_update_real_blend_enable (pipeline0, FALSE);
2039   _cogl_pipeline_update_real_blend_enable (pipeline1, FALSE);
2040 
2041   /* First check non-sparse properties */
2042 
2043   if (differences & COGL_PIPELINE_STATE_REAL_BLEND_ENABLE &&
2044       pipeline0->real_blend_enable != pipeline1->real_blend_enable)
2045     goto done;
2046 
2047   /* Then check sparse properties */
2048 
2049   pipelines_difference =
2050     _cogl_pipeline_compare_differences (pipeline0, pipeline1);
2051 
2052   /* Only compare the sparse state groups requested by the caller... */
2053   pipelines_difference &= differences;
2054 
2055   _cogl_pipeline_resolve_authorities (pipeline0,
2056                                       pipelines_difference,
2057                                       authorities0);
2058   _cogl_pipeline_resolve_authorities (pipeline1,
2059                                       pipelines_difference,
2060                                       authorities1);
2061 
2062   COGL_FLAGS_FOREACH_START (&pipelines_difference, 1, bit)
2063     {
2064       /* XXX: We considered having an array of callbacks for each state index
2065        * that we'd call here but decided that this way the compiler is more
2066        * likely going to be able to in-line the comparison functions and use
2067        * the index to jump straight to the required code. */
2068       switch ((CoglPipelineStateIndex)bit)
2069         {
2070         case COGL_PIPELINE_STATE_COLOR_INDEX:
2071           if (!cogl_color_equal (&authorities0[bit]->color,
2072                                  &authorities1[bit]->color))
2073             goto done;
2074           break;
2075         case COGL_PIPELINE_STATE_ALPHA_FUNC_INDEX:
2076           if (!_cogl_pipeline_alpha_func_state_equal (authorities0[bit],
2077                                                       authorities1[bit]))
2078             goto done;
2079           break;
2080         case COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE_INDEX:
2081           if (!_cogl_pipeline_alpha_func_reference_state_equal (
2082                                                             authorities0[bit],
2083                                                             authorities1[bit]))
2084             goto done;
2085           break;
2086         case COGL_PIPELINE_STATE_BLEND_INDEX:
2087           /* We don't need to compare the detailed blending state if we know
2088            * blending is disabled for both pipelines. */
2089           if (pipeline0->real_blend_enable)
2090             {
2091               if (!_cogl_pipeline_blend_state_equal (authorities0[bit],
2092                                                      authorities1[bit]))
2093                 goto done;
2094             }
2095           break;
2096         case COGL_PIPELINE_STATE_DEPTH_INDEX:
2097           if (!_cogl_pipeline_depth_state_equal (authorities0[bit],
2098                                                  authorities1[bit]))
2099             goto done;
2100           break;
2101         case COGL_PIPELINE_STATE_CULL_FACE_INDEX:
2102           if (!_cogl_pipeline_cull_face_state_equal (authorities0[bit],
2103                                                      authorities1[bit]))
2104             goto done;
2105           break;
2106         case COGL_PIPELINE_STATE_NON_ZERO_POINT_SIZE_INDEX:
2107           if (!_cogl_pipeline_non_zero_point_size_equal (authorities0[bit],
2108                                                          authorities1[bit]))
2109             goto done;
2110           break;
2111         case COGL_PIPELINE_STATE_POINT_SIZE_INDEX:
2112           if (!_cogl_pipeline_point_size_equal (authorities0[bit],
2113                                                 authorities1[bit]))
2114             goto done;
2115           break;
2116         case COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE_INDEX:
2117           if (!_cogl_pipeline_per_vertex_point_size_equal (authorities0[bit],
2118                                                            authorities1[bit]))
2119             goto done;
2120           break;
2121         case COGL_PIPELINE_STATE_USER_SHADER_INDEX:
2122           if (!_cogl_pipeline_user_shader_equal (authorities0[bit],
2123                                                  authorities1[bit]))
2124             goto done;
2125           break;
2126         case COGL_PIPELINE_STATE_UNIFORMS_INDEX:
2127           if (!_cogl_pipeline_uniforms_state_equal (authorities0[bit],
2128                                                     authorities1[bit]))
2129             goto done;
2130           break;
2131         case COGL_PIPELINE_STATE_VERTEX_SNIPPETS_INDEX:
2132           if (!_cogl_pipeline_vertex_snippets_state_equal (authorities0[bit],
2133                                                            authorities1[bit]))
2134             goto done;
2135           break;
2136         case COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS_INDEX:
2137           if (!_cogl_pipeline_fragment_snippets_state_equal (authorities0[bit],
2138                                                              authorities1[bit]))
2139             goto done;
2140           break;
2141         case COGL_PIPELINE_STATE_LAYERS_INDEX:
2142           {
2143             if (!_cogl_pipeline_layers_equal (authorities0[bit],
2144                                               authorities1[bit],
2145                                               layer_differences,
2146                                               flags))
2147               goto done;
2148             break;
2149           }
2150 
2151         case COGL_PIPELINE_STATE_REAL_BLEND_ENABLE_INDEX:
2152         case COGL_PIPELINE_STATE_COUNT:
2153           g_warn_if_reached ();
2154         }
2155     }
2156   COGL_FLAGS_FOREACH_END;
2157 
2158   ret = TRUE;
2159 done:
2160   COGL_TIMER_STOP (_cogl_uprof_context, pipeline_equal_timer);
2161   return ret;
2162 }
2163 
2164 void
_cogl_pipeline_prune_redundant_ancestry(CoglPipeline * pipeline)2165 _cogl_pipeline_prune_redundant_ancestry (CoglPipeline *pipeline)
2166 {
2167   CoglPipeline *new_parent = _cogl_pipeline_get_parent (pipeline);
2168 
2169   /* Before considering pruning redundant ancestry we check if this
2170    * pipeline is an authority for layer state and if so only consider
2171    * reparenting if it *owns* all the layers it depends on. NB: A
2172    * pipeline can be be a STATE_LAYERS authority but it may still
2173    * defer to its ancestors to define the state for some of its
2174    * layers.
2175    *
2176    * For example a pipeline that derives from a parent with 5 layers
2177    * can become a STATE_LAYERS authority by simply changing it's
2178    * ->n_layers count to 4 and in that case it can still defer to its
2179    * ancestors to define the state of those 4 layers.
2180    *
2181    * If a pipeline depends on any ancestors for layer state then we
2182    * immediately bail out.
2183    */
2184   if (pipeline->differences & COGL_PIPELINE_STATE_LAYERS)
2185     {
2186       if (pipeline->n_layers != g_list_length (pipeline->layer_differences))
2187         return;
2188     }
2189 
2190   /* walk up past ancestors that are now redundant and potentially
2191    * reparent the pipeline. */
2192   while (_cogl_pipeline_get_parent (new_parent) &&
2193          (new_parent->differences | pipeline->differences) ==
2194           pipeline->differences)
2195     new_parent = _cogl_pipeline_get_parent (new_parent);
2196 
2197   if (new_parent != _cogl_pipeline_get_parent (pipeline))
2198     {
2199       gboolean is_weak = _cogl_pipeline_is_weak (pipeline);
2200       _cogl_pipeline_set_parent (pipeline, new_parent, is_weak ? FALSE : TRUE);
2201     }
2202 }
2203 
2204 void
_cogl_pipeline_update_authority(CoglPipeline * pipeline,CoglPipeline * authority,CoglPipelineState state,CoglPipelineStateComparator comparator)2205 _cogl_pipeline_update_authority (CoglPipeline *pipeline,
2206                                  CoglPipeline *authority,
2207                                  CoglPipelineState state,
2208                                  CoglPipelineStateComparator comparator)
2209 {
2210   /* If we are the current authority see if we can revert to one of
2211    * our ancestors being the authority */
2212   if (pipeline == authority &&
2213       _cogl_pipeline_get_parent (authority) != NULL)
2214     {
2215       CoglPipeline *parent = _cogl_pipeline_get_parent (authority);
2216       CoglPipeline *old_authority =
2217         _cogl_pipeline_get_authority (parent, state);
2218 
2219       if (comparator (authority, old_authority))
2220         pipeline->differences &= ~state;
2221     }
2222   else if (pipeline != authority)
2223     {
2224       /* If we weren't previously the authority on this state then we
2225        * need to extended our differences mask and so it's possible
2226        * that some of our ancestry will now become redundant, so we
2227        * aim to reparent ourselves if that's true... */
2228       pipeline->differences |= state;
2229       _cogl_pipeline_prune_redundant_ancestry (pipeline);
2230     }
2231 }
2232 
2233 unsigned long
_cogl_pipeline_get_age(CoglPipeline * pipeline)2234 _cogl_pipeline_get_age (CoglPipeline *pipeline)
2235 {
2236   g_return_val_if_fail (cogl_is_pipeline (pipeline), 0);
2237 
2238   return pipeline->age;
2239 }
2240 
2241 void
cogl_pipeline_remove_layer(CoglPipeline * pipeline,int layer_index)2242 cogl_pipeline_remove_layer (CoglPipeline *pipeline, int layer_index)
2243 {
2244   CoglPipeline         *authority;
2245   CoglPipelineLayerInfo layer_info;
2246   int                   i;
2247 
2248   g_return_if_fail (cogl_is_pipeline (pipeline));
2249 
2250   authority =
2251     _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LAYERS);
2252 
2253   /* The layer index of the layer we want info about */
2254   layer_info.layer_index = layer_index;
2255 
2256   /* This will be updated with a reference to the layer being removed
2257    * if it can be found. */
2258   layer_info.layer = NULL;
2259 
2260   /* This will be filled in with a list of layers that need to be
2261    * dropped down to a lower texture unit to fill the gap of the
2262    * removed layer. */
2263   layer_info.layers_to_shift =
2264     g_alloca (sizeof (CoglPipelineLayer *) * authority->n_layers);
2265   layer_info.n_layers_to_shift = 0;
2266 
2267   /* Unlike when we query layer info when adding a layer we must
2268    * always have a complete layers_to_shift list... */
2269   layer_info.ignore_shift_layers_if_found = FALSE;
2270 
2271   _cogl_pipeline_get_layer_info (authority, &layer_info);
2272 
2273   if (layer_info.layer == NULL)
2274     return;
2275 
2276   for (i = 0; i < layer_info.n_layers_to_shift; i++)
2277     {
2278       CoglPipelineLayer *shift_layer = layer_info.layers_to_shift[i];
2279       int unit_index = _cogl_pipeline_layer_get_unit_index (shift_layer);
2280       _cogl_pipeline_set_layer_unit (pipeline, shift_layer, unit_index - 1);
2281       /* NB: shift_layer may not be writeable so _set_layer_unit()
2282        * will allocate a derived layer internally which will become
2283        * owned by pipeline. Check the return value if we need to do
2284        * anything else with this layer. */
2285     }
2286 
2287   _cogl_pipeline_remove_layer_difference (pipeline, layer_info.layer, TRUE);
2288   _cogl_pipeline_try_reverting_layers_authority (pipeline, NULL);
2289 
2290   pipeline->dirty_real_blend_enable = TRUE;
2291 }
2292 
2293 int
cogl_pipeline_get_n_layers(CoglPipeline * pipeline)2294 cogl_pipeline_get_n_layers (CoglPipeline *pipeline)
2295 {
2296   CoglPipeline *authority;
2297 
2298   g_return_val_if_fail (cogl_is_pipeline (pipeline), 0);
2299 
2300   authority =
2301     _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LAYERS);
2302 
2303   return authority->n_layers;
2304 }
2305 
2306 void
_cogl_pipeline_pre_paint_for_layer(CoglPipeline * pipeline,int layer_id)2307 _cogl_pipeline_pre_paint_for_layer (CoglPipeline *pipeline,
2308                                     int layer_id)
2309 {
2310   CoglPipelineLayer *layer = _cogl_pipeline_get_layer (pipeline, layer_id);
2311   _cogl_pipeline_layer_pre_paint (layer);
2312 }
2313 
2314 /* While a pipeline is referenced by the Cogl journal we can not allow
2315  * modifications, so this gives us a mechanism to track journal
2316  * references separately */
2317 CoglPipeline *
_cogl_pipeline_journal_ref(CoglPipeline * pipeline)2318 _cogl_pipeline_journal_ref (CoglPipeline *pipeline)
2319 {
2320   pipeline->journal_ref_count++;
2321   return cogl_object_ref (pipeline);
2322 }
2323 
2324 void
_cogl_pipeline_journal_unref(CoglPipeline * pipeline)2325 _cogl_pipeline_journal_unref (CoglPipeline *pipeline)
2326 {
2327   pipeline->journal_ref_count--;
2328   cogl_object_unref (pipeline);
2329 }
2330 
2331 #ifdef COGL_DEBUG_ENABLED
2332 void
_cogl_pipeline_set_static_breadcrumb(CoglPipeline * pipeline,const char * breadcrumb)2333 _cogl_pipeline_set_static_breadcrumb (CoglPipeline *pipeline,
2334                                       const char *breadcrumb)
2335 {
2336   pipeline->has_static_breadcrumb = TRUE;
2337   pipeline->static_breadcrumb = breadcrumb;
2338 }
2339 #endif
2340 
2341 typedef void (*LayerStateHashFunction) (CoglPipelineLayer *authority,
2342                                         CoglPipelineLayer **authorities,
2343                                         CoglPipelineHashState *state);
2344 
2345 static LayerStateHashFunction
2346 layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT];
2347 
2348 /* XXX: We don't statically initialize the array of hash functions, so
2349  * we won't get caught out by later re-indexing the groups for some
2350  * reason. */
2351 void
_cogl_pipeline_init_layer_state_hash_functions(void)2352 _cogl_pipeline_init_layer_state_hash_functions (void)
2353 {
2354   CoglPipelineLayerStateIndex _index;
2355   layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_UNIT_INDEX] =
2356     _cogl_pipeline_layer_hash_unit_state;
2357   layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX] =
2358     _cogl_pipeline_layer_hash_texture_data_state;
2359   layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_SAMPLER_INDEX] =
2360     _cogl_pipeline_layer_hash_sampler_state;
2361   layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX] =
2362     _cogl_pipeline_layer_hash_combine_state;
2363   layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX] =
2364     _cogl_pipeline_layer_hash_combine_constant_state;
2365   layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX] =
2366     _cogl_pipeline_layer_hash_user_matrix_state;
2367   _index = COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX;
2368   layer_state_hash_functions[_index] =
2369     _cogl_pipeline_layer_hash_point_sprite_state;
2370   _index = COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS_INDEX;
2371   layer_state_hash_functions[_index] =
2372     _cogl_pipeline_layer_hash_point_sprite_state;
2373   _index = COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS_INDEX;
2374   layer_state_hash_functions[_index] =
2375     _cogl_pipeline_layer_hash_fragment_snippets_state;
2376 
2377   {
2378   /* So we get a big error if we forget to update this code! */
2379   _COGL_STATIC_ASSERT (COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT == 9,
2380                        "Don't forget to install a hash function for new "
2381                        "pipeline state and update assert at end of "
2382                        "_cogl_pipeline_init_state_hash_functions");
2383   }
2384 }
2385 
2386 static gboolean
_cogl_pipeline_hash_layer_cb(CoglPipelineLayer * layer,void * user_data)2387 _cogl_pipeline_hash_layer_cb (CoglPipelineLayer *layer,
2388                               void *user_data)
2389 {
2390   CoglPipelineHashState *state = user_data;
2391   unsigned long differences = state->layer_differences;
2392   CoglPipelineLayer *authorities[COGL_PIPELINE_LAYER_STATE_COUNT];
2393   unsigned long mask;
2394   int i;
2395 
2396   /* Theoretically we would hash non-sparse layer state here but
2397    * currently layers don't have any. */
2398 
2399   /* XXX: we resolve all the authorities here - not just those
2400    * corresponding to hash_state->layer_differences - because
2401    * the hashing of some state groups actually depends on the values
2402    * in other groups. For example we don't hash layer combine
2403    * constants if they are aren't referenced by the current layer
2404    * combine function.
2405    */
2406   mask = COGL_PIPELINE_LAYER_STATE_ALL_SPARSE;
2407   _cogl_pipeline_layer_resolve_authorities (layer,
2408                                             mask,
2409                                             authorities);
2410 
2411   /* So we go right ahead and hash the sparse state... */
2412   for (i = 0; i < COGL_PIPELINE_LAYER_STATE_COUNT; i++)
2413     {
2414       unsigned long current_state = (1L<<i);
2415 
2416       /* XXX: we are hashing the un-mixed hash values of all the
2417        * individual state groups; we should provide a means to test
2418        * the quality of the final hash values we are getting with this
2419        * approach... */
2420       if (differences & current_state)
2421         {
2422           CoglPipelineLayer *authority = authorities[i];
2423           layer_state_hash_functions[i] (authority, authorities, state);
2424         }
2425 
2426       if (current_state > differences)
2427         break;
2428     }
2429 
2430   return TRUE;
2431 }
2432 
2433 void
_cogl_pipeline_hash_layers_state(CoglPipeline * authority,CoglPipelineHashState * state)2434 _cogl_pipeline_hash_layers_state (CoglPipeline *authority,
2435                                   CoglPipelineHashState *state)
2436 {
2437   state->hash =
2438     _cogl_util_one_at_a_time_hash (state->hash, &authority->n_layers,
2439                                    sizeof (authority->n_layers));
2440   _cogl_pipeline_foreach_layer_internal (authority,
2441                                          _cogl_pipeline_hash_layer_cb,
2442                                          state);
2443 }
2444 
2445 typedef void (*StateHashFunction) (CoglPipeline *authority, CoglPipelineHashState *state);
2446 
2447 static StateHashFunction
2448 state_hash_functions[COGL_PIPELINE_STATE_SPARSE_COUNT];
2449 
2450 /* We don't statically initialize the array of hash functions
2451  * so we won't get caught out by later re-indexing the groups for
2452  * some reason. */
2453 void
_cogl_pipeline_init_state_hash_functions(void)2454 _cogl_pipeline_init_state_hash_functions (void)
2455 {
2456   state_hash_functions[COGL_PIPELINE_STATE_COLOR_INDEX] =
2457     _cogl_pipeline_hash_color_state;
2458   state_hash_functions[COGL_PIPELINE_STATE_LAYERS_INDEX] =
2459     _cogl_pipeline_hash_layers_state;
2460   state_hash_functions[COGL_PIPELINE_STATE_ALPHA_FUNC_INDEX] =
2461     _cogl_pipeline_hash_alpha_func_state;
2462   state_hash_functions[COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE_INDEX] =
2463     _cogl_pipeline_hash_alpha_func_reference_state;
2464   state_hash_functions[COGL_PIPELINE_STATE_BLEND_INDEX] =
2465     _cogl_pipeline_hash_blend_state;
2466   state_hash_functions[COGL_PIPELINE_STATE_USER_SHADER_INDEX] =
2467     _cogl_pipeline_hash_user_shader_state;
2468   state_hash_functions[COGL_PIPELINE_STATE_DEPTH_INDEX] =
2469     _cogl_pipeline_hash_depth_state;
2470   state_hash_functions[COGL_PIPELINE_STATE_CULL_FACE_INDEX] =
2471     _cogl_pipeline_hash_cull_face_state;
2472   state_hash_functions[COGL_PIPELINE_STATE_NON_ZERO_POINT_SIZE_INDEX] =
2473     _cogl_pipeline_hash_non_zero_point_size_state;
2474   state_hash_functions[COGL_PIPELINE_STATE_POINT_SIZE_INDEX] =
2475     _cogl_pipeline_hash_point_size_state;
2476   state_hash_functions[COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE_INDEX] =
2477     _cogl_pipeline_hash_per_vertex_point_size_state;
2478   state_hash_functions[COGL_PIPELINE_STATE_UNIFORMS_INDEX] =
2479     _cogl_pipeline_hash_uniforms_state;
2480   state_hash_functions[COGL_PIPELINE_STATE_VERTEX_SNIPPETS_INDEX] =
2481     _cogl_pipeline_hash_vertex_snippets_state;
2482   state_hash_functions[COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS_INDEX] =
2483     _cogl_pipeline_hash_fragment_snippets_state;
2484 
2485   {
2486   /* So we get a big error if we forget to update this code! */
2487   _COGL_STATIC_ASSERT (COGL_PIPELINE_STATE_SPARSE_COUNT == 14,
2488                        "Make sure to install a hash function for "
2489                        "newly added pipeline state and update assert "
2490                        "in _cogl_pipeline_init_state_hash_functions");
2491   }
2492 }
2493 
2494 unsigned int
_cogl_pipeline_hash(CoglPipeline * pipeline,unsigned int differences,unsigned long layer_differences,CoglPipelineEvalFlags flags)2495 _cogl_pipeline_hash (CoglPipeline *pipeline,
2496                      unsigned int differences,
2497                      unsigned long layer_differences,
2498                      CoglPipelineEvalFlags flags)
2499 {
2500   CoglPipeline *authorities[COGL_PIPELINE_STATE_SPARSE_COUNT];
2501   unsigned int mask;
2502   int i;
2503   CoglPipelineHashState state;
2504   unsigned int final_hash = 0;
2505 
2506   state.hash = 0;
2507   state.layer_differences = layer_differences;
2508   state.flags = flags;
2509 
2510   _cogl_pipeline_update_real_blend_enable (pipeline, FALSE);
2511 
2512   /* hash non-sparse state */
2513 
2514   if (differences & COGL_PIPELINE_STATE_REAL_BLEND_ENABLE)
2515     {
2516       gboolean enable = pipeline->real_blend_enable;
2517       state.hash =
2518         _cogl_util_one_at_a_time_hash (state.hash, &enable, sizeof (enable));
2519     }
2520 
2521   /* hash sparse state */
2522 
2523   mask = differences & COGL_PIPELINE_STATE_ALL_SPARSE;
2524   _cogl_pipeline_resolve_authorities (pipeline, mask, authorities);
2525 
2526   for (i = 0; i < COGL_PIPELINE_STATE_SPARSE_COUNT; i++)
2527     {
2528       unsigned int current_state = (1<<i);
2529 
2530       /* XXX: we are hashing the un-mixed hash values of all the
2531        * individual state groups; we should provide a means to test
2532        * the quality of the final hash values we are getting with this
2533        * approach... */
2534       if (differences & current_state)
2535         {
2536           CoglPipeline *authority = authorities[i];
2537           state_hash_functions[i] (authority, &state);
2538           final_hash = _cogl_util_one_at_a_time_hash (final_hash, &state.hash,
2539                                                       sizeof (state.hash));
2540         }
2541 
2542       if (current_state > differences)
2543         break;
2544     }
2545 
2546   return _cogl_util_one_at_a_time_mix (final_hash);
2547 }
2548 
2549 typedef struct
2550 {
2551   CoglContext *context;
2552   CoglPipeline *src_pipeline;
2553   CoglPipeline *dst_pipeline;
2554   unsigned int layer_differences;
2555 } DeepCopyData;
2556 
2557 static gboolean
deep_copy_layer_cb(CoglPipelineLayer * src_layer,void * user_data)2558 deep_copy_layer_cb (CoglPipelineLayer *src_layer,
2559                     void *user_data)
2560 {
2561   DeepCopyData *data = user_data;
2562   CoglPipelineLayer *dst_layer;
2563   unsigned int differences = data->layer_differences;
2564 
2565   dst_layer = _cogl_pipeline_get_layer (data->dst_pipeline, src_layer->index);
2566 
2567   while (src_layer != data->context->default_layer_n &&
2568          src_layer != data->context->default_layer_0 &&
2569          differences)
2570     {
2571       unsigned long to_copy = differences & src_layer->differences;
2572 
2573       if (to_copy)
2574         {
2575           _cogl_pipeline_layer_copy_differences (dst_layer, src_layer, to_copy);
2576           differences ^= to_copy;
2577         }
2578 
2579       src_layer = COGL_PIPELINE_LAYER (COGL_NODE (src_layer)->parent);
2580     }
2581 
2582   return TRUE;
2583 }
2584 
2585 CoglPipeline *
_cogl_pipeline_deep_copy(CoglPipeline * pipeline,unsigned long differences,unsigned long layer_differences)2586 _cogl_pipeline_deep_copy (CoglPipeline *pipeline,
2587                           unsigned long differences,
2588                           unsigned long layer_differences)
2589 {
2590   CoglPipeline *new, *authority;
2591   gboolean copy_layer_state;
2592 
2593   _COGL_GET_CONTEXT (ctx, NULL);
2594 
2595   if ((differences & COGL_PIPELINE_STATE_LAYERS))
2596     {
2597       copy_layer_state = TRUE;
2598       differences &= ~COGL_PIPELINE_STATE_LAYERS;
2599     }
2600   else
2601     copy_layer_state = FALSE;
2602 
2603   new = cogl_pipeline_new (ctx);
2604 
2605   for (authority = pipeline;
2606        authority != ctx->default_pipeline && differences;
2607        authority = COGL_PIPELINE (COGL_NODE (authority)->parent))
2608     {
2609       unsigned long to_copy = differences & authority->differences;
2610 
2611       if (to_copy)
2612         {
2613           _cogl_pipeline_copy_differences (new, authority, to_copy);
2614           differences ^= to_copy;
2615         }
2616     }
2617 
2618   if (copy_layer_state)
2619     {
2620       DeepCopyData data;
2621 
2622       /* The unit index doesn't need to be copied because it should
2623        * end up with the same values anyway because the new pipeline
2624        * will have the same indices as the source pipeline */
2625       layer_differences &= ~COGL_PIPELINE_LAYER_STATE_UNIT;
2626 
2627       data.context = ctx;
2628       data.src_pipeline = pipeline;
2629       data.dst_pipeline = new;
2630       data.layer_differences = layer_differences;
2631 
2632       _cogl_pipeline_foreach_layer_internal (pipeline,
2633                                              deep_copy_layer_cb,
2634                                              &data);
2635     }
2636 
2637   return new;
2638 }
2639 
2640 typedef struct
2641 {
2642   int i;
2643   CoglPipelineLayer **layers;
2644 } AddLayersToArrayState;
2645 
2646 static gboolean
add_layer_to_array_cb(CoglPipelineLayer * layer,void * user_data)2647 add_layer_to_array_cb (CoglPipelineLayer *layer,
2648                        void *user_data)
2649 {
2650   AddLayersToArrayState *state = user_data;
2651   state->layers[state->i++] = layer;
2652   return TRUE;
2653 }
2654 
2655 /* This tries to find the oldest ancestor whose pipeline and layer
2656    state matches the given flags. This is mostly used to detect code
2657    gen authorities so that we can reduce the number of programs
2658    generated */
2659 CoglPipeline *
_cogl_pipeline_find_equivalent_parent(CoglPipeline * pipeline,CoglPipelineState pipeline_state,CoglPipelineLayerState layer_state)2660 _cogl_pipeline_find_equivalent_parent (CoglPipeline *pipeline,
2661                                        CoglPipelineState pipeline_state,
2662                                        CoglPipelineLayerState layer_state)
2663 {
2664   CoglPipeline *authority0;
2665   CoglPipeline *authority1;
2666   int n_layers;
2667   CoglPipelineLayer **authority0_layers;
2668   CoglPipelineLayer **authority1_layers;
2669 
2670   /* Find the first pipeline that modifies state that affects the
2671    * state or any layer state... */
2672   authority0 = _cogl_pipeline_get_authority (pipeline,
2673                                              pipeline_state |
2674                                              COGL_PIPELINE_STATE_LAYERS);
2675 
2676   /* Find the next ancestor after that, that also modifies the
2677    * state... */
2678   if (_cogl_pipeline_get_parent (authority0))
2679     {
2680       authority1 =
2681         _cogl_pipeline_get_authority (_cogl_pipeline_get_parent (authority0),
2682                                       pipeline_state |
2683                                       COGL_PIPELINE_STATE_LAYERS);
2684     }
2685   else
2686     return authority0;
2687 
2688   n_layers = cogl_pipeline_get_n_layers (authority0);
2689 
2690   for (;;)
2691     {
2692       AddLayersToArrayState state;
2693       int i;
2694 
2695       if (n_layers != cogl_pipeline_get_n_layers (authority1))
2696         return authority0;
2697 
2698       /* If the programs differ by anything that isn't part of the
2699          layer state then we can't continue */
2700       if (pipeline_state &&
2701           (_cogl_pipeline_compare_differences (authority0, authority1) &
2702            pipeline_state))
2703         return authority0;
2704 
2705       authority0_layers =
2706         g_alloca (sizeof (CoglPipelineLayer *) * n_layers);
2707       state.i = 0;
2708       state.layers = authority0_layers;
2709       _cogl_pipeline_foreach_layer_internal (authority0,
2710                                              add_layer_to_array_cb,
2711                                              &state);
2712 
2713       authority1_layers =
2714         g_alloca (sizeof (CoglPipelineLayer *) * n_layers);
2715       state.i = 0;
2716       state.layers = authority1_layers;
2717       _cogl_pipeline_foreach_layer_internal (authority1,
2718                                              add_layer_to_array_cb,
2719                                              &state);
2720 
2721       for (i = 0; i < n_layers; i++)
2722         {
2723           unsigned long layer_differences;
2724 
2725           if (authority0_layers[i] == authority1_layers[i])
2726             continue;
2727 
2728           layer_differences =
2729             _cogl_pipeline_layer_compare_differences (authority0_layers[i],
2730                                                       authority1_layers[i]);
2731 
2732           if (layer_differences & layer_state)
2733             return authority0;
2734         }
2735 
2736       /* Find the next ancestor after that, that also modifies state
2737        * affecting codegen... */
2738 
2739       if (!_cogl_pipeline_get_parent (authority1))
2740         break;
2741 
2742       authority0 = authority1;
2743       authority1 =
2744         _cogl_pipeline_get_authority (_cogl_pipeline_get_parent (authority1),
2745                                       pipeline_state |
2746                                       COGL_PIPELINE_STATE_LAYERS);
2747       if (authority1 == authority0)
2748         break;
2749     }
2750 
2751   return authority1;
2752 }
2753 
2754 CoglPipelineState
_cogl_pipeline_get_state_for_vertex_codegen(CoglContext * context)2755 _cogl_pipeline_get_state_for_vertex_codegen (CoglContext *context)
2756 {
2757   CoglPipelineState state = (COGL_PIPELINE_STATE_LAYERS |
2758                              COGL_PIPELINE_STATE_USER_SHADER |
2759                              COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE |
2760                              COGL_PIPELINE_STATE_VERTEX_SNIPPETS);
2761   state |= COGL_PIPELINE_STATE_NON_ZERO_POINT_SIZE;
2762 
2763   return state;
2764 }
2765 
2766 CoglPipelineLayerState
_cogl_pipeline_get_layer_state_for_fragment_codegen(CoglContext * context)2767 _cogl_pipeline_get_layer_state_for_fragment_codegen (CoglContext *context)
2768 {
2769   CoglPipelineLayerState state =
2770     (COGL_PIPELINE_LAYER_STATE_COMBINE |
2771      COGL_PIPELINE_LAYER_STATE_UNIT |
2772      COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS);
2773 
2774   /* Since the driver supports GLSL then we might be using gl_PointCoord
2775    * to implement the sprite coords. In that case the generated code
2776    * depends on the point sprite state */
2777   state |= COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS;
2778 
2779   return state;
2780 }
2781 
2782 CoglPipelineState
_cogl_pipeline_get_state_for_fragment_codegen(CoglContext * context)2783 _cogl_pipeline_get_state_for_fragment_codegen (CoglContext *context)
2784 {
2785   CoglPipelineState state = (COGL_PIPELINE_STATE_LAYERS |
2786                              COGL_PIPELINE_STATE_USER_SHADER |
2787                              COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS |
2788                              COGL_PIPELINE_STATE_ALPHA_FUNC);
2789 
2790   return state;
2791 }
2792 
2793 int
cogl_pipeline_get_uniform_location(CoglPipeline * pipeline,const char * uniform_name)2794 cogl_pipeline_get_uniform_location (CoglPipeline *pipeline,
2795                                     const char *uniform_name)
2796 {
2797   void *location_ptr;
2798   char *uniform_name_copy;
2799 
2800   _COGL_GET_CONTEXT (ctx, -1);
2801 
2802   /* This API is designed as if the uniform locations are specific to
2803      a pipeline but they are actually unique across a whole
2804      CoglContext. Potentially this could just be
2805      cogl_context_get_uniform_location but it seems to make sense to
2806      keep the API this way so that we can change the internals if need
2807      be. */
2808 
2809   /* Look for an existing uniform with this name */
2810   if (g_hash_table_lookup_extended (ctx->uniform_name_hash,
2811                                     uniform_name,
2812                                     NULL,
2813                                     &location_ptr))
2814     return GPOINTER_TO_INT (location_ptr);
2815 
2816   uniform_name_copy = g_strdup (uniform_name);
2817   g_ptr_array_add (ctx->uniform_names, uniform_name_copy);
2818   g_hash_table_insert (ctx->uniform_name_hash,
2819                        uniform_name_copy,
2820                        GINT_TO_POINTER (ctx->n_uniform_names));
2821 
2822   return ctx->n_uniform_names++;
2823 }
2824