1 /*
2  * Cogl
3  *
4  * A Low Level GPU Graphics and Utilities API
5  *
6  * Copyright (C) 2008,2009,2010 Intel Corporation.
7  *
8  * Permission is hereby granted, free of charge, to any person
9  * obtaining a copy of this software and associated documentation
10  * files (the "Software"), to deal in the Software without
11  * restriction, including without limitation the rights to use, copy,
12  * modify, merge, publish, distribute, sublicense, and/or sell copies
13  * of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be
17  * included in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26  * SOFTWARE.
27  *
28  *
29  *
30  * Authors:
31  *   Robert Bragg <robert@linux.intel.com>
32  */
33 
34 #include "cogl-config.h"
35 
36 #include "cogl-util.h"
37 #include "cogl-context-private.h"
38 #include "cogl-texture-private.h"
39 
40 #include "cogl-pipeline.h"
41 #include "cogl-pipeline-layer-private.h"
42 #include "cogl-pipeline-layer-state-private.h"
43 #include "cogl-pipeline-layer-state.h"
44 #include "cogl-node-private.h"
45 #include "cogl-context-private.h"
46 #include "cogl-texture-private.h"
47 
48 #include <string.h>
49 
50 static void
51 _cogl_pipeline_layer_free (CoglPipelineLayer *layer);
52 
53 /* This type was made deprecated before the cogl_is_pipeline_layer
54    function was ever exposed in the public headers so there's no need
55    to make the cogl_is_pipeline_layer function public. We use INTERNAL
56    so that the cogl_is_* function won't get defined */
57 COGL_OBJECT_INTERNAL_DEFINE (PipelineLayer, pipeline_layer);
58 
59 
60 CoglPipelineLayer *
_cogl_pipeline_layer_get_authority(CoglPipelineLayer * layer,unsigned long difference)61 _cogl_pipeline_layer_get_authority (CoglPipelineLayer *layer,
62                                     unsigned long difference)
63 {
64   CoglPipelineLayer *authority = layer;
65   while (!(authority->differences & difference))
66     authority = _cogl_pipeline_layer_get_parent (authority);
67   return authority;
68 }
69 
70 int
_cogl_pipeline_layer_get_unit_index(CoglPipelineLayer * layer)71 _cogl_pipeline_layer_get_unit_index (CoglPipelineLayer *layer)
72 {
73   CoglPipelineLayer *authority =
74     _cogl_pipeline_layer_get_authority (layer, COGL_PIPELINE_LAYER_STATE_UNIT);
75   return authority->unit_index;
76 }
77 
78 gboolean
_cogl_pipeline_layer_has_alpha(CoglPipelineLayer * layer)79 _cogl_pipeline_layer_has_alpha (CoglPipelineLayer *layer)
80 {
81   CoglPipelineLayer *combine_authority =
82     _cogl_pipeline_layer_get_authority (layer,
83                                         COGL_PIPELINE_LAYER_STATE_COMBINE);
84   CoglPipelineLayerBigState *big_state = combine_authority->big_state;
85   CoglPipelineLayer *tex_authority;
86   CoglPipelineLayer *snippets_authority;
87 
88   /* has_alpha maintains the alpha status for the GL_PREVIOUS layer */
89 
90   /* For anything but the default texture combine we currently just
91    * assume it may result in an alpha value < 1
92    *
93    * FIXME: we could do better than this. */
94   if (big_state->texture_combine_alpha_func !=
95       COGL_PIPELINE_COMBINE_FUNC_MODULATE ||
96       big_state->texture_combine_alpha_src[0] !=
97       COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS ||
98       big_state->texture_combine_alpha_op[0] !=
99       COGL_PIPELINE_COMBINE_OP_SRC_ALPHA ||
100       big_state->texture_combine_alpha_src[1] !=
101       COGL_PIPELINE_COMBINE_SOURCE_TEXTURE ||
102       big_state->texture_combine_alpha_op[1] !=
103       COGL_PIPELINE_COMBINE_OP_SRC_ALPHA)
104     {
105       return TRUE;
106     }
107 
108   /* NB: A layer may have a combine mode set on it but not yet
109    * have an associated texture which would mean we'd fallback
110    * to the default texture which doesn't have an alpha component
111    */
112   tex_authority =
113     _cogl_pipeline_layer_get_authority (layer,
114                                         COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA);
115   if (tex_authority->texture &&
116       _cogl_texture_get_format (tex_authority->texture) & COGL_A_BIT)
117     {
118       return TRUE;
119     }
120 
121   /* All bets are off if the layer contains any snippets */
122   snippets_authority = _cogl_pipeline_layer_get_authority
123     (layer, COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS);
124   if (snippets_authority->big_state->vertex_snippets.entries != NULL)
125     return TRUE;
126   snippets_authority = _cogl_pipeline_layer_get_authority
127     (layer, COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS);
128   if (snippets_authority->big_state->fragment_snippets.entries != NULL)
129     return TRUE;
130 
131   return FALSE;
132 }
133 
134 unsigned int
_cogl_get_n_args_for_combine_func(CoglPipelineCombineFunc func)135 _cogl_get_n_args_for_combine_func (CoglPipelineCombineFunc func)
136 {
137   switch (func)
138     {
139     case COGL_PIPELINE_COMBINE_FUNC_REPLACE:
140       return 1;
141     case COGL_PIPELINE_COMBINE_FUNC_MODULATE:
142     case COGL_PIPELINE_COMBINE_FUNC_ADD:
143     case COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED:
144     case COGL_PIPELINE_COMBINE_FUNC_SUBTRACT:
145     case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB:
146     case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA:
147       return 2;
148     case COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE:
149       return 3;
150     }
151   return 0;
152 }
153 
154 void
_cogl_pipeline_layer_copy_differences(CoglPipelineLayer * dest,CoglPipelineLayer * src,unsigned long differences)155 _cogl_pipeline_layer_copy_differences (CoglPipelineLayer *dest,
156                                        CoglPipelineLayer *src,
157                                        unsigned long differences)
158 {
159   CoglPipelineLayerBigState *big_dest, *big_src;
160 
161   if ((differences & COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE) &&
162       !dest->has_big_state)
163     {
164       dest->big_state = g_new0 (CoglPipelineLayerBigState, 1);
165       dest->has_big_state = TRUE;
166     }
167 
168   big_dest = dest->big_state;
169   big_src = src->big_state;
170 
171   dest->differences |= differences;
172 
173   while (differences)
174     {
175       int index = ffs (differences) - 1;
176 
177       differences &= ~(1 << index);
178 
179       /* This convoluted switch statement is just here so that we'll
180        * get a warning if a new state is added without handling it
181        * here */
182       switch (index)
183         {
184         case COGL_PIPELINE_LAYER_STATE_COUNT:
185         case COGL_PIPELINE_LAYER_STATE_UNIT_INDEX:
186           g_warn_if_reached ();
187           break;
188 
189         case COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX:
190           dest->texture = src->texture;
191           if (dest->texture)
192             cogl_object_ref (dest->texture);
193           break;
194 
195         case COGL_PIPELINE_LAYER_STATE_SAMPLER_INDEX:
196           dest->sampler_cache_entry = src->sampler_cache_entry;
197           break;
198 
199         case COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX:
200           {
201             CoglPipelineCombineFunc func;
202             int n_args, i;
203 
204             func = big_src->texture_combine_rgb_func;
205             big_dest->texture_combine_rgb_func = func;
206             n_args = _cogl_get_n_args_for_combine_func (func);
207             for (i = 0; i < n_args; i++)
208               {
209                 big_dest->texture_combine_rgb_src[i] =
210                   big_src->texture_combine_rgb_src[i];
211                 big_dest->texture_combine_rgb_op[i] =
212                   big_src->texture_combine_rgb_op[i];
213               }
214 
215             func = big_src->texture_combine_alpha_func;
216             big_dest->texture_combine_alpha_func = func;
217             n_args = _cogl_get_n_args_for_combine_func (func);
218             for (i = 0; i < n_args; i++)
219               {
220                 big_dest->texture_combine_alpha_src[i] =
221                   big_src->texture_combine_alpha_src[i];
222                 big_dest->texture_combine_alpha_op[i] =
223                   big_src->texture_combine_alpha_op[i];
224               }
225           }
226           break;
227 
228         case COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX:
229           memcpy (big_dest->texture_combine_constant,
230                   big_src->texture_combine_constant,
231                   sizeof (big_dest->texture_combine_constant));
232           break;
233 
234         case COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX:
235           big_dest->point_sprite_coords = big_src->point_sprite_coords;
236           break;
237 
238         case COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS_INDEX:
239           _cogl_pipeline_snippet_list_copy (&big_dest->vertex_snippets,
240                                             &big_src->vertex_snippets);
241           break;
242 
243         case COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS_INDEX:
244           _cogl_pipeline_snippet_list_copy (&big_dest->fragment_snippets,
245                                             &big_src->fragment_snippets);
246           break;
247         }
248     }
249 }
250 
251 static void
_cogl_pipeline_layer_init_multi_property_sparse_state(CoglPipelineLayer * layer,CoglPipelineLayerState change)252 _cogl_pipeline_layer_init_multi_property_sparse_state (
253                                                   CoglPipelineLayer *layer,
254                                                   CoglPipelineLayerState change)
255 {
256   CoglPipelineLayer *authority;
257 
258   /* Nothing to initialize in these cases since they are all comprised
259    * of one member which we expect to immediately be overwritten. */
260   if (!(change & COGL_PIPELINE_LAYER_STATE_MULTI_PROPERTY))
261     return;
262 
263   authority = _cogl_pipeline_layer_get_authority (layer, change);
264 
265   switch (change)
266     {
267     /* XXX: avoid using a default: label so we get a warning if we
268      * don't explicitly handle a newly defined state-group here. */
269     case COGL_PIPELINE_LAYER_STATE_UNIT:
270     case COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA:
271     case COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS:
272     case COGL_PIPELINE_LAYER_STATE_USER_MATRIX:
273     case COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT:
274     case COGL_PIPELINE_LAYER_STATE_SAMPLER:
275       g_return_if_reached ();
276 
277     /* XXX: technically we could probably even consider these as
278      * single property state-groups from the pov that currently the
279      * corresponding property setters always update all of the values
280      * at the same time. */
281     case COGL_PIPELINE_LAYER_STATE_COMBINE:
282       {
283         int n_args;
284         int i;
285         CoglPipelineLayerBigState *src_big_state = authority->big_state;
286         CoglPipelineLayerBigState *dest_big_state = layer->big_state;
287         GLint func = src_big_state->texture_combine_rgb_func;
288 
289         dest_big_state->texture_combine_rgb_func = func;
290         n_args = _cogl_get_n_args_for_combine_func (func);
291         for (i = 0; i < n_args; i++)
292           {
293             dest_big_state->texture_combine_rgb_src[i] =
294               src_big_state->texture_combine_rgb_src[i];
295             dest_big_state->texture_combine_rgb_op[i] =
296               src_big_state->texture_combine_rgb_op[i];
297           }
298 
299         func = src_big_state->texture_combine_alpha_func;
300         dest_big_state->texture_combine_alpha_func = func;
301         n_args = _cogl_get_n_args_for_combine_func (func);
302         for (i = 0; i < n_args; i++)
303           {
304             dest_big_state->texture_combine_alpha_src[i] =
305               src_big_state->texture_combine_alpha_src[i];
306             dest_big_state->texture_combine_alpha_op[i] =
307               src_big_state->texture_combine_alpha_op[i];
308           }
309         break;
310       }
311     case COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS:
312       _cogl_pipeline_snippet_list_copy (&layer->big_state->vertex_snippets,
313                                         &authority->big_state->
314                                         vertex_snippets);
315       break;
316     case COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS:
317       _cogl_pipeline_snippet_list_copy (&layer->big_state->fragment_snippets,
318                                         &authority->big_state->
319                                         fragment_snippets);
320       break;
321     }
322 }
323 
324 /* NB: If a layer has descendants we can't modify the layer
325  * NB: If the layer is owned and the owner has descendants we can't
326  *     modify the layer.
327  *
328  * This function will allocate a new derived layer if you are trying
329  * to change the state of a layer with dependants (as described above)
330  * so you must always check the return value.
331  *
332  * If a new layer is returned it will be owned by required_owner.
333  * (NB: a layer is always modified with respect to a pipeline - the
334  *  "required_owner")
335  *
336  * required_owner can only by NULL for new, currently unowned layers
337  * with no dependants.
338  */
339 CoglPipelineLayer *
_cogl_pipeline_layer_pre_change_notify(CoglPipeline * required_owner,CoglPipelineLayer * layer,CoglPipelineLayerState change)340 _cogl_pipeline_layer_pre_change_notify (CoglPipeline *required_owner,
341                                         CoglPipelineLayer *layer,
342                                         CoglPipelineLayerState change)
343 {
344   /* Identify the case where the layer is new with no owner or
345    * dependants and so we don't need to do anything. */
346   if (_cogl_list_empty (&COGL_NODE (layer)->children) &&
347       layer->owner == NULL)
348     goto init_layer_state;
349 
350   /* We only allow a NULL required_owner for new layers */
351   g_return_val_if_fail (required_owner != NULL, layer);
352 
353   /* Chain up:
354    * A modification of a layer is indirectly also a modification of
355    * its owner so first make sure to flush the journal of any
356    * references to the current owner state and if necessary perform
357    * a copy-on-write for the required_owner if it has dependants.
358    */
359   _cogl_pipeline_pre_change_notify (required_owner,
360                                     COGL_PIPELINE_STATE_LAYERS,
361                                     NULL,
362                                     TRUE);
363 
364   /* Unlike pipelines; layers are simply considered immutable once
365    * they have dependants - either direct children, or another
366    * pipeline as an owner.
367    */
368   if (!_cogl_list_empty (&COGL_NODE (layer)->children) ||
369       layer->owner != required_owner)
370     {
371       CoglPipelineLayer *new = _cogl_pipeline_layer_copy (layer);
372       if (layer->owner == required_owner)
373         _cogl_pipeline_remove_layer_difference (required_owner, layer, FALSE);
374       _cogl_pipeline_add_layer_difference (required_owner, new, FALSE);
375       cogl_object_unref (new);
376       layer = new;
377       goto init_layer_state;
378     }
379 
380   /* Note: At this point we know there is only one pipeline dependent on
381    * this layer (required_owner), and there are no other layers
382    * dependent on this layer so it's ok to modify it. */
383 
384   /* NB: Although layers can have private state associated with them
385    * by multiple backends we know that a layer can't be *changed* if
386    * it has multiple dependants so if we reach here we know we only
387    * have a single owner and can only be associated with a single
388    * backend that needs to be notified of the layer change...
389    */
390     {
391       const CoglPipelineProgend *progend = _cogl_pipeline_progend;
392       const CoglPipelineFragend *fragend = _cogl_pipeline_fragend;
393       const CoglPipelineVertend *vertend = _cogl_pipeline_vertend;
394 
395       if (fragend->layer_pre_change_notify)
396         fragend->layer_pre_change_notify (required_owner, layer, change);
397       if (vertend->layer_pre_change_notify)
398         vertend->layer_pre_change_notify (required_owner, layer, change);
399       if (progend->layer_pre_change_notify)
400         progend->layer_pre_change_notify (required_owner, layer, change);
401     }
402 
403 init_layer_state:
404 
405   if (required_owner)
406     required_owner->age++;
407 
408   if (change & COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE &&
409       !layer->has_big_state)
410     {
411       layer->big_state = g_new0 (CoglPipelineLayerBigState, 1);
412       layer->has_big_state = TRUE;
413     }
414 
415   /* Note: conceptually we have just been notified that a single
416    * property value is about to change, but since some state-groups
417    * contain multiple properties and 'layer' is about to take over
418    * being the authority for the property's corresponding state-group
419    * we need to maintain the integrity of the other property values
420    * too.
421    *
422    * To ensure this we handle multi-property state-groups by copying
423    * all the values from the old-authority to the new...
424    *
425    * We don't have to worry about non-sparse property groups since
426    * we never take over being an authority for such properties so
427    * they automatically maintain integrity.
428    */
429   if (change & COGL_PIPELINE_LAYER_STATE_ALL_SPARSE &&
430       !(layer->differences & change))
431     {
432       _cogl_pipeline_layer_init_multi_property_sparse_state (layer, change);
433       layer->differences |= change;
434     }
435 
436   return layer;
437 }
438 
439 static void
_cogl_pipeline_layer_unparent(CoglNode * layer)440 _cogl_pipeline_layer_unparent (CoglNode *layer)
441 {
442   /* Chain up */
443   _cogl_pipeline_node_unparent_real (layer);
444 }
445 
446 static void
_cogl_pipeline_layer_set_parent(CoglPipelineLayer * layer,CoglPipelineLayer * parent)447 _cogl_pipeline_layer_set_parent (CoglPipelineLayer *layer,
448                                  CoglPipelineLayer *parent)
449 {
450   /* Chain up */
451   _cogl_pipeline_node_set_parent_real (COGL_NODE (layer),
452                                        COGL_NODE (parent),
453                                        _cogl_pipeline_layer_unparent,
454                                        TRUE);
455 }
456 
457 CoglPipelineLayer *
_cogl_pipeline_layer_copy(CoglPipelineLayer * src)458 _cogl_pipeline_layer_copy (CoglPipelineLayer *src)
459 {
460   CoglPipelineLayer *layer = g_new0 (CoglPipelineLayer, 1);
461 
462   _cogl_pipeline_node_init (COGL_NODE (layer));
463 
464   layer->owner = NULL;
465   layer->index = src->index;
466   layer->differences = 0;
467   layer->has_big_state = FALSE;
468 
469   _cogl_pipeline_layer_set_parent (layer, src);
470 
471   return _cogl_pipeline_layer_object_new (layer);
472 }
473 
474 /* XXX: This is duplicated logic; the same as for
475  * _cogl_pipeline_prune_redundant_ancestry it would be nice to find a
476  * way to consolidate these functions! */
477 void
_cogl_pipeline_layer_prune_redundant_ancestry(CoglPipelineLayer * layer)478 _cogl_pipeline_layer_prune_redundant_ancestry (CoglPipelineLayer *layer)
479 {
480   CoglPipelineLayer *new_parent = _cogl_pipeline_layer_get_parent (layer);
481 
482   /* walk up past ancestors that are now redundant and potentially
483    * reparent the layer. */
484   while (_cogl_pipeline_layer_get_parent (new_parent) &&
485          (new_parent->differences | layer->differences) ==
486          layer->differences)
487     new_parent = _cogl_pipeline_layer_get_parent (new_parent);
488 
489   _cogl_pipeline_layer_set_parent (layer, new_parent);
490 }
491 
492 /* Determine the mask of differences between two layers.
493  *
494  * XXX: If layers and pipelines could both be cast to a common Tree
495  * type of some kind then we could have a unified
496  * compare_differences() function.
497  */
498 unsigned long
_cogl_pipeline_layer_compare_differences(CoglPipelineLayer * layer0,CoglPipelineLayer * layer1)499 _cogl_pipeline_layer_compare_differences (CoglPipelineLayer *layer0,
500                                           CoglPipelineLayer *layer1)
501 {
502   GSList *head0 = NULL;
503   GSList *head1 = NULL;
504   CoglPipelineLayer *node0;
505   CoglPipelineLayer *node1;
506   int len0 = 0;
507   int len1 = 0;
508   int count;
509   GSList *common_ancestor0;
510   GSList *common_ancestor1;
511   unsigned long layers_difference = 0;
512 
513   /* Algorithm:
514    *
515    * 1) Walk the ancestors of each layer to the root node, adding a
516    *    pointer to each ancester node to two linked lists
517    *
518    * 2) Compare the lists to find the nodes where they start to
519    *    differ marking the common_ancestor node for each list.
520    *
521    * 3) For each list now iterate starting after the common_ancestor
522    *    nodes ORing each nodes ->difference mask into the final
523    *    differences mask.
524    */
525 
526   for (node0 = layer0; node0; node0 = _cogl_pipeline_layer_get_parent (node0))
527     {
528       GSList *link = alloca (sizeof (GSList));
529       link->next = head0;
530       link->data = node0;
531       head0 = link;
532       len0++;
533     }
534   for (node1 = layer1; node1; node1 = _cogl_pipeline_layer_get_parent (node1))
535     {
536       GSList *link = alloca (sizeof (GSList));
537       link->next = head1;
538       link->data = node1;
539       head1 = link;
540       len1++;
541     }
542 
543   /* NB: There's no point looking at the head entries since we know both layers
544    * must have the same default layer as their root node. */
545   common_ancestor0 = head0;
546   common_ancestor1 = head1;
547   head0 = head0->next;
548   head1 = head1->next;
549   count = MIN (len0, len1) - 1;
550   while (count--)
551     {
552       if (head0->data != head1->data)
553         break;
554       common_ancestor0 = head0;
555       common_ancestor1 = head1;
556       head0 = head0->next;
557       head1 = head1->next;
558     }
559 
560   for (head0 = common_ancestor0->next; head0; head0 = head0->next)
561     {
562       node0 = head0->data;
563       layers_difference |= node0->differences;
564     }
565   for (head1 = common_ancestor1->next; head1; head1 = head1->next)
566     {
567       node1 = head1->data;
568       layers_difference |= node1->differences;
569     }
570 
571   return layers_difference;
572 }
573 
574 static gboolean
layer_state_equal(CoglPipelineLayerStateIndex state_index,CoglPipelineLayer ** authorities0,CoglPipelineLayer ** authorities1,CoglPipelineLayerStateComparator comparator)575 layer_state_equal (CoglPipelineLayerStateIndex state_index,
576                    CoglPipelineLayer **authorities0,
577                    CoglPipelineLayer **authorities1,
578                    CoglPipelineLayerStateComparator comparator)
579 {
580   return comparator (authorities0[state_index], authorities1[state_index]);
581 }
582 
583 void
_cogl_pipeline_layer_resolve_authorities(CoglPipelineLayer * layer,unsigned long differences,CoglPipelineLayer ** authorities)584 _cogl_pipeline_layer_resolve_authorities (CoglPipelineLayer *layer,
585                                           unsigned long differences,
586                                           CoglPipelineLayer **authorities)
587 {
588   unsigned long remaining = differences;
589   CoglPipelineLayer *authority = layer;
590 
591   do
592     {
593       unsigned long found = authority->differences & remaining;
594       int i;
595 
596       if (found == 0)
597         continue;
598 
599       for (i = 0; TRUE; i++)
600         {
601           unsigned long state = (1L<<i);
602 
603           if (state & found)
604             authorities[i] = authority;
605           else if (state > found)
606             break;
607         }
608 
609       remaining &= ~found;
610       if (remaining == 0)
611         return;
612     }
613   while ((authority = _cogl_pipeline_layer_get_parent (authority)));
614 
615   g_assert (remaining == 0);
616 }
617 
618 gboolean
_cogl_pipeline_layer_equal(CoglPipelineLayer * layer0,CoglPipelineLayer * layer1,unsigned long differences_mask,CoglPipelineEvalFlags flags)619 _cogl_pipeline_layer_equal (CoglPipelineLayer *layer0,
620                             CoglPipelineLayer *layer1,
621                             unsigned long differences_mask,
622                             CoglPipelineEvalFlags flags)
623 {
624   unsigned long layers_difference;
625   CoglPipelineLayer *authorities0[COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT];
626   CoglPipelineLayer *authorities1[COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT];
627 
628   if (layer0 == layer1)
629     return TRUE;
630 
631   layers_difference =
632     _cogl_pipeline_layer_compare_differences (layer0, layer1);
633 
634   /* Only compare the sparse state groups requested by the caller... */
635   layers_difference &= differences_mask;
636 
637   _cogl_pipeline_layer_resolve_authorities (layer0,
638                                             layers_difference,
639                                             authorities0);
640   _cogl_pipeline_layer_resolve_authorities (layer1,
641                                             layers_difference,
642                                             authorities1);
643 
644   if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA)
645     {
646       CoglPipelineLayerStateIndex state_index =
647         COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX;
648       if (!_cogl_pipeline_layer_texture_data_equal (authorities0[state_index],
649                                                     authorities1[state_index],
650                                                     flags))
651         return FALSE;
652     }
653 
654   if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE &&
655       !layer_state_equal (COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX,
656                           authorities0, authorities1,
657                           _cogl_pipeline_layer_combine_state_equal))
658     return FALSE;
659 
660   if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT &&
661       !layer_state_equal (COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX,
662                           authorities0, authorities1,
663                           _cogl_pipeline_layer_combine_constant_equal))
664     return FALSE;
665 
666   if (layers_difference & COGL_PIPELINE_LAYER_STATE_SAMPLER &&
667       !layer_state_equal (COGL_PIPELINE_LAYER_STATE_SAMPLER_INDEX,
668                           authorities0, authorities1,
669                           _cogl_pipeline_layer_sampler_equal))
670     return FALSE;
671 
672   if (layers_difference & COGL_PIPELINE_LAYER_STATE_USER_MATRIX &&
673       !layer_state_equal (COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX,
674                           authorities0, authorities1,
675                           _cogl_pipeline_layer_user_matrix_equal))
676     return FALSE;
677 
678   if (layers_difference & COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS &&
679       !layer_state_equal (COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX,
680                           authorities0, authorities1,
681                           _cogl_pipeline_layer_point_sprite_coords_equal))
682     return FALSE;
683 
684   if (layers_difference & COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS &&
685       !layer_state_equal (COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS_INDEX,
686                           authorities0, authorities1,
687                           _cogl_pipeline_layer_vertex_snippets_equal))
688     return FALSE;
689 
690   if (layers_difference & COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS &&
691       !layer_state_equal (COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS_INDEX,
692                           authorities0, authorities1,
693                           _cogl_pipeline_layer_fragment_snippets_equal))
694     return FALSE;
695 
696   return TRUE;
697 }
698 
699 static void
_cogl_pipeline_layer_free(CoglPipelineLayer * layer)700 _cogl_pipeline_layer_free (CoglPipelineLayer *layer)
701 {
702   _cogl_pipeline_layer_unparent (COGL_NODE (layer));
703 
704   if (layer->differences & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA &&
705       layer->texture != NULL)
706     cogl_object_unref (layer->texture);
707 
708   if (layer->differences & COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS)
709     _cogl_pipeline_snippet_list_free (&layer->big_state->vertex_snippets);
710 
711   if (layer->differences & COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS)
712     _cogl_pipeline_snippet_list_free (&layer->big_state->fragment_snippets);
713 
714   if (layer->differences & COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE)
715     g_free (layer->big_state);
716 
717   g_free (layer);
718 }
719 
720 void
_cogl_pipeline_init_default_layers(void)721 _cogl_pipeline_init_default_layers (void)
722 {
723   CoglPipelineLayer *layer = g_new0 (CoglPipelineLayer, 1);
724   CoglPipelineLayerBigState *big_state =
725     g_new0 (CoglPipelineLayerBigState, 1);
726   CoglPipelineLayer *new;
727 
728   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
729 
730   _cogl_pipeline_node_init (COGL_NODE (layer));
731 
732   layer->index = 0;
733 
734   layer->differences = COGL_PIPELINE_LAYER_STATE_ALL_SPARSE;
735 
736   layer->unit_index = 0;
737 
738   layer->texture = NULL;
739 
740   layer->sampler_cache_entry =
741     _cogl_sampler_cache_get_default_entry (ctx->sampler_cache);
742 
743   layer->big_state = big_state;
744   layer->has_big_state = TRUE;
745 
746   /* Choose the same default combine mode as OpenGL:
747    * RGBA = MODULATE(PREVIOUS[RGBA],TEXTURE[RGBA]) */
748   big_state->texture_combine_rgb_func =
749     COGL_PIPELINE_COMBINE_FUNC_MODULATE;
750   big_state->texture_combine_rgb_src[0] =
751     COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS;
752   big_state->texture_combine_rgb_src[1] =
753     COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
754   big_state->texture_combine_rgb_op[0] =
755     COGL_PIPELINE_COMBINE_OP_SRC_COLOR;
756   big_state->texture_combine_rgb_op[1] =
757     COGL_PIPELINE_COMBINE_OP_SRC_COLOR;
758   big_state->texture_combine_alpha_func =
759     COGL_PIPELINE_COMBINE_FUNC_MODULATE;
760   big_state->texture_combine_alpha_src[0] =
761     COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS;
762   big_state->texture_combine_alpha_src[1] =
763     COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
764   big_state->texture_combine_alpha_op[0] =
765     COGL_PIPELINE_COMBINE_OP_SRC_ALPHA;
766   big_state->texture_combine_alpha_op[1] =
767     COGL_PIPELINE_COMBINE_OP_SRC_ALPHA;
768 
769   big_state->point_sprite_coords = FALSE;
770 
771   graphene_matrix_init_identity (&big_state->matrix);
772 
773   ctx->default_layer_0 = _cogl_pipeline_layer_object_new (layer);
774 
775   /* TODO: we should make default_layer_n comprise of two
776    * descendants of default_layer_0:
777    * - the first descendant should change the texture combine
778    *   to what we expect is most commonly used for multitexturing
779    * - the second should revert the above change.
780    *
781    * why? the documentation for how a new layer is initialized
782    * doesn't say that layers > 0 have different defaults so unless
783    * we change the documentation we can't use different defaults,
784    * but if the user does what we expect and changes the
785    * texture combine then we can revert the authority to the
786    * first descendant which means we can maximize the number
787    * of layers with a common ancestor.
788    *
789    * The main problem will be that we'll need to disable the
790    * optimizations for flattening the ancestry when we make
791    * the second descendant which reverts the state.
792    */
793   ctx->default_layer_n = _cogl_pipeline_layer_copy (layer);
794   new = _cogl_pipeline_set_layer_unit (NULL, ctx->default_layer_n, 1);
795   g_assert (new == ctx->default_layer_n);
796   /* Since we passed a newly allocated layer we don't expect that
797    * _set_layer_unit() will have to allocate *another* layer. */
798 
799   /* Finally we create a dummy dependent for ->default_layer_n which
800    * effectively ensures that ->default_layer_n and ->default_layer_0
801    * remain immutable.
802    */
803   ctx->dummy_layer_dependant =
804     _cogl_pipeline_layer_copy (ctx->default_layer_n);
805 }
806 
807 void
_cogl_pipeline_layer_pre_paint(CoglPipelineLayer * layer)808 _cogl_pipeline_layer_pre_paint (CoglPipelineLayer *layer)
809 {
810   CoglPipelineLayer *texture_authority;
811 
812   texture_authority =
813     _cogl_pipeline_layer_get_authority (layer,
814                                         COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA);
815 
816   if (texture_authority->texture != NULL)
817     {
818       CoglTexturePrePaintFlags flags = 0;
819       CoglPipelineFilter min_filter;
820       CoglPipelineFilter mag_filter;
821 
822       _cogl_pipeline_layer_get_filters (layer, &min_filter, &mag_filter);
823 
824       if (min_filter == COGL_PIPELINE_FILTER_NEAREST_MIPMAP_NEAREST
825           || min_filter == COGL_PIPELINE_FILTER_LINEAR_MIPMAP_NEAREST
826           || min_filter == COGL_PIPELINE_FILTER_NEAREST_MIPMAP_LINEAR
827           || min_filter == COGL_PIPELINE_FILTER_LINEAR_MIPMAP_LINEAR)
828         flags |= COGL_TEXTURE_NEEDS_MIPMAP;
829 
830       _cogl_texture_pre_paint (texture_authority->texture, flags);
831     }
832 }
833 
834 /* Determines if we need to handle the RGB and A texture combining
835  * separately or is the same function used for both channel masks and
836  * with the same arguments...
837  */
838 gboolean
_cogl_pipeline_layer_needs_combine_separate(CoglPipelineLayer * combine_authority)839 _cogl_pipeline_layer_needs_combine_separate
840                                        (CoglPipelineLayer *combine_authority)
841 {
842   CoglPipelineLayerBigState *big_state = combine_authority->big_state;
843   int n_args;
844   int i;
845 
846   if (big_state->texture_combine_rgb_func !=
847       big_state->texture_combine_alpha_func)
848     return TRUE;
849 
850   n_args = _cogl_get_n_args_for_combine_func (big_state->texture_combine_rgb_func);
851 
852   for (i = 0; i < n_args; i++)
853     {
854       if (big_state->texture_combine_rgb_src[i] !=
855           big_state->texture_combine_alpha_src[i])
856         return TRUE;
857 
858       /*
859        * We can allow some variation of the source operands without
860        * needing a separation...
861        *
862        * "A = REPLACE (CONSTANT[A])" + either of the following...
863        * "RGB = REPLACE (CONSTANT[RGB])"
864        * "RGB = REPLACE (CONSTANT[A])"
865        *
866        * can be combined as:
867        * "RGBA = REPLACE (CONSTANT)" or
868        * "RGBA = REPLACE (CONSTANT[A])" or
869        *
870        * And "A = REPLACE (1-CONSTANT[A])" + either of the following...
871        * "RGB = REPLACE (1-CONSTANT)" or
872        * "RGB = REPLACE (1-CONSTANT[A])"
873        *
874        * can be combined as:
875        * "RGBA = REPLACE (1-CONSTANT)" or
876        * "RGBA = REPLACE (1-CONSTANT[A])"
877        */
878       switch (big_state->texture_combine_alpha_op[i])
879         {
880         case GL_SRC_ALPHA:
881           switch (big_state->texture_combine_rgb_op[i])
882             {
883             case GL_SRC_COLOR:
884             case GL_SRC_ALPHA:
885               break;
886             default:
887               return FALSE;
888             }
889           break;
890         case GL_ONE_MINUS_SRC_ALPHA:
891           switch (big_state->texture_combine_rgb_op[i])
892             {
893             case GL_ONE_MINUS_SRC_COLOR:
894             case GL_ONE_MINUS_SRC_ALPHA:
895               break;
896             default:
897               return FALSE;
898             }
899           break;
900         default:
901           return FALSE;	/* impossible */
902         }
903     }
904 
905   return FALSE;
906 }
907 
908 
909