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