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 #ifdef HAVE_CONFIG_H
35 #include "cogl-config.h"
36 #endif
37 
38 #include "cogl-context-private.h"
39 #include "cogl-pipeline-private.h"
40 #include "cogl-blend-string.h"
41 #include "cogl-util.h"
42 #include "cogl-matrix.h"
43 #include "cogl-snippet-private.h"
44 #include "cogl-texture-private.h"
45 #include "cogl-pipeline-layer-state-private.h"
46 #include "cogl-error-private.h"
47 
48 #include "string.h"
49 #if 0
50 #include "cogl-context-private.h"
51 #include "cogl-color-private.h"
52 
53 #endif
54 
55 /*
56  * XXX: consider special casing layer->unit_index so it's not a sparse
57  * property so instead we can assume it's valid for all layer
58  * instances.
59  * - We would need to initialize ->unit_index in
60  *   _cogl_pipeline_layer_copy ().
61  *
62  * XXX: If you use this API you should consider that the given layer
63  * might not be writeable and so a new derived layer will be allocated
64  * and modified instead. The layer modified will be returned so you
65  * can identify when this happens.
66  */
67 CoglPipelineLayer *
_cogl_pipeline_set_layer_unit(CoglPipeline * required_owner,CoglPipelineLayer * layer,int unit_index)68 _cogl_pipeline_set_layer_unit (CoglPipeline *required_owner,
69                                CoglPipelineLayer *layer,
70                                int unit_index)
71 {
72   CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_UNIT;
73   CoglPipelineLayer *authority =
74     _cogl_pipeline_layer_get_authority (layer, change);
75   CoglPipelineLayer *new;
76 
77   if (authority->unit_index == unit_index)
78     return layer;
79 
80   new =
81     _cogl_pipeline_layer_pre_change_notify (required_owner,
82                                             layer,
83                                             change);
84   if (new != layer)
85     layer = new;
86   else
87     {
88       /* If the layer we found is currently the authority on the state
89        * we are changing see if we can revert to one of our ancestors
90        * being the authority. */
91       if (layer == authority &&
92           _cogl_pipeline_layer_get_parent (authority) != NULL)
93         {
94           CoglPipelineLayer *parent =
95             _cogl_pipeline_layer_get_parent (authority);
96           CoglPipelineLayer *old_authority =
97             _cogl_pipeline_layer_get_authority (parent, change);
98 
99           if (old_authority->unit_index == unit_index)
100             {
101               layer->differences &= ~change;
102               return layer;
103             }
104         }
105     }
106 
107   layer->unit_index = unit_index;
108 
109   /* If we weren't previously the authority on this state then we need
110    * to extended our differences mask and so it's possible that some
111    * of our ancestry will now become redundant, so we aim to reparent
112    * ourselves if that's true... */
113   if (layer != authority)
114     {
115       layer->differences |= change;
116       _cogl_pipeline_layer_prune_redundant_ancestry (layer);
117     }
118 
119   return layer;
120 }
121 
122 CoglTexture *
_cogl_pipeline_layer_get_texture_real(CoglPipelineLayer * layer)123 _cogl_pipeline_layer_get_texture_real (CoglPipelineLayer *layer)
124 {
125   CoglPipelineLayer *authority =
126     _cogl_pipeline_layer_get_authority (layer,
127                                         COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA);
128 
129   return authority->texture;
130 }
131 
132 CoglTexture *
cogl_pipeline_get_layer_texture(CoglPipeline * pipeline,int layer_index)133 cogl_pipeline_get_layer_texture (CoglPipeline *pipeline,
134                                  int layer_index)
135 {
136   CoglPipelineLayer *layer =
137     _cogl_pipeline_get_layer (pipeline, layer_index);
138   return _cogl_pipeline_layer_get_texture (layer);
139 }
140 
141 CoglTextureType
_cogl_pipeline_layer_get_texture_type(CoglPipelineLayer * layer)142 _cogl_pipeline_layer_get_texture_type (CoglPipelineLayer *layer)
143 {
144   CoglPipelineLayer *authority =
145     _cogl_pipeline_layer_get_authority (layer,
146                                         COGL_PIPELINE_LAYER_STATE_TEXTURE_TYPE);
147 
148   return authority->texture_type;
149 }
150 
151 static void
_cogl_pipeline_set_layer_texture_type(CoglPipeline * pipeline,int layer_index,CoglTextureType texture_type)152 _cogl_pipeline_set_layer_texture_type (CoglPipeline *pipeline,
153                                        int layer_index,
154                                        CoglTextureType texture_type)
155 {
156   CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE_TYPE;
157   CoglPipelineLayer *layer;
158   CoglPipelineLayer *authority;
159   CoglPipelineLayer *new;
160 
161   /* Note: this will ensure that the layer exists, creating one if it
162    * doesn't already.
163    *
164    * Note: If the layer already existed it's possibly owned by another
165    * pipeline. If the layer is created then it will be owned by
166    * pipeline. */
167   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
168 
169   /* Now find the ancestor of the layer that is the authority for the
170    * state we want to change */
171   authority = _cogl_pipeline_layer_get_authority (layer, change);
172 
173   if (texture_type == authority->texture_type)
174     return;
175 
176   new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
177   if (new != layer)
178     layer = new;
179   else
180     {
181       /* If the original layer we found is currently the authority on
182        * the state we are changing see if we can revert to one of our
183        * ancestors being the authority. */
184       if (layer == authority &&
185           _cogl_pipeline_layer_get_parent (authority) != NULL)
186         {
187           CoglPipelineLayer *parent =
188             _cogl_pipeline_layer_get_parent (authority);
189           CoglPipelineLayer *old_authority =
190             _cogl_pipeline_layer_get_authority (parent, change);
191 
192           if (old_authority->texture_type == texture_type)
193             {
194               layer->differences &= ~change;
195 
196               g_assert (layer->owner == pipeline);
197               if (layer->differences == 0)
198                 _cogl_pipeline_prune_empty_layer_difference (pipeline,
199                                                              layer);
200               goto changed;
201             }
202         }
203     }
204 
205   layer->texture_type = texture_type;
206 
207   /* If we weren't previously the authority on this state then we need
208    * to extended our differences mask and so it's possible that some
209    * of our ancestry will now become redundant, so we aim to reparent
210    * ourselves if that's true... */
211   if (layer != authority)
212     {
213       layer->differences |= change;
214       _cogl_pipeline_layer_prune_redundant_ancestry (layer);
215     }
216 
217 changed:
218 
219   pipeline->dirty_real_blend_enable = TRUE;
220 }
221 
222 static void
_cogl_pipeline_set_layer_texture_data(CoglPipeline * pipeline,int layer_index,CoglTexture * texture)223 _cogl_pipeline_set_layer_texture_data (CoglPipeline *pipeline,
224                                        int layer_index,
225                                        CoglTexture *texture)
226 {
227   CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA;
228   CoglPipelineLayer *layer;
229   CoglPipelineLayer *authority;
230   CoglPipelineLayer *new;
231 
232   /* Note: this will ensure that the layer exists, creating one if it
233    * doesn't already.
234    *
235    * Note: If the layer already existed it's possibly owned by another
236    * pipeline. If the layer is created then it will be owned by
237    * pipeline. */
238   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
239 
240   /* Now find the ancestor of the layer that is the authority for the
241    * state we want to change */
242   authority = _cogl_pipeline_layer_get_authority (layer, change);
243 
244   if (authority->texture == texture)
245     return;
246 
247   new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
248   if (new != layer)
249     layer = new;
250   else
251     {
252       /* If the original layer we found is currently the authority on
253        * the state we are changing see if we can revert to one of our
254        * ancestors being the authority. */
255       if (layer == authority &&
256           _cogl_pipeline_layer_get_parent (authority) != NULL)
257         {
258           CoglPipelineLayer *parent =
259             _cogl_pipeline_layer_get_parent (authority);
260           CoglPipelineLayer *old_authority =
261             _cogl_pipeline_layer_get_authority (parent, change);
262 
263           if (old_authority->texture == texture)
264             {
265               layer->differences &= ~change;
266 
267               if (layer->texture != NULL)
268                 cogl_object_unref (layer->texture);
269 
270               g_assert (layer->owner == pipeline);
271               if (layer->differences == 0)
272                 _cogl_pipeline_prune_empty_layer_difference (pipeline,
273                                                              layer);
274               goto changed;
275             }
276         }
277     }
278 
279   if (texture != NULL)
280     cogl_object_ref (texture);
281   if (layer == authority &&
282       layer->texture != NULL)
283     cogl_object_unref (layer->texture);
284   layer->texture = texture;
285 
286   /* If we weren't previously the authority on this state then we need
287    * to extended our differences mask and so it's possible that some
288    * of our ancestry will now become redundant, so we aim to reparent
289    * ourselves if that's true... */
290   if (layer != authority)
291     {
292       layer->differences |= change;
293       _cogl_pipeline_layer_prune_redundant_ancestry (layer);
294     }
295 
296 changed:
297 
298   pipeline->dirty_real_blend_enable = TRUE;
299 }
300 
301 void
cogl_pipeline_set_layer_texture(CoglPipeline * pipeline,int layer_index,CoglTexture * texture)302 cogl_pipeline_set_layer_texture (CoglPipeline *pipeline,
303                                  int layer_index,
304                                  CoglTexture *texture)
305 {
306   /* For the convenience of fragend code we separate texture state
307    * into the "type" and the "data", and setting a layer texture
308    * updates both of these properties.
309    *
310    * One example for why this is helpful is that the fragends may
311    * cache programs they generate and want to re-use those programs
312    * with all pipelines having equivalent fragment processing state.
313    * For the sake of determining if pipelines have equivalent fragment
314    * processing state we don't need to compare that the same
315    * underlying texture objects are referenced by the pipelines but we
316    * do need to see if they use the same texture types. Making this
317    * distinction is much simpler if they are in different state
318    * groups.
319    *
320    * Note: if a NULL texture is set then we leave the type unchanged
321    * so we can avoid needlessly invalidating any associated fragment
322    * program.
323    */
324   if (texture)
325     {
326       CoglTextureType texture_type =
327         _cogl_texture_get_type (texture);
328       _cogl_pipeline_set_layer_texture_type (pipeline,
329                                              layer_index,
330                                              texture_type);
331     }
332   _cogl_pipeline_set_layer_texture_data (pipeline, layer_index, texture);
333 }
334 
335 void
cogl_pipeline_set_layer_null_texture(CoglPipeline * pipeline,int layer_index,CoglTextureType texture_type)336 cogl_pipeline_set_layer_null_texture (CoglPipeline *pipeline,
337                                       int layer_index,
338                                       CoglTextureType texture_type)
339 {
340   CoglContext *ctx = _cogl_context_get_default ();
341 
342   /* Disallow setting texture types that aren't supported */
343   switch (texture_type)
344     {
345     case COGL_TEXTURE_TYPE_2D:
346       break;
347 
348     case COGL_TEXTURE_TYPE_3D:
349       if (ctx->default_gl_texture_3d_tex == NULL)
350         {
351           g_warning ("The default 3D texture was set on a pipeline but "
352                      "3D textures are not supported");
353           texture_type = COGL_TEXTURE_TYPE_2D;
354           return;
355         }
356       break;
357 
358     case COGL_TEXTURE_TYPE_RECTANGLE:
359       if (ctx->default_gl_texture_rect_tex == NULL)
360         {
361           g_warning ("The default rectangle texture was set on a pipeline but "
362                      "rectangle textures are not supported");
363           texture_type = COGL_TEXTURE_TYPE_2D;
364         }
365       break;
366     }
367 
368   _cogl_pipeline_set_layer_texture_type (pipeline, layer_index, texture_type);
369   _cogl_pipeline_set_layer_texture_data (pipeline, layer_index, NULL);
370 }
371 
372 static void
_cogl_pipeline_set_layer_sampler_state(CoglPipeline * pipeline,CoglPipelineLayer * layer,CoglPipelineLayer * authority,const CoglSamplerCacheEntry * state)373 _cogl_pipeline_set_layer_sampler_state (CoglPipeline *pipeline,
374                                         CoglPipelineLayer *layer,
375                                         CoglPipelineLayer *authority,
376                                         const CoglSamplerCacheEntry *state)
377 {
378   CoglPipelineLayer *new;
379   CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_SAMPLER;
380 
381   if (authority->sampler_cache_entry == state)
382     return;
383 
384   new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
385   if (new != layer)
386     layer = new;
387   else
388     {
389       /* If the original layer we found is currently the authority on
390        * the state we are changing see if we can revert to one of our
391        * ancestors being the authority. */
392       if (layer == authority &&
393           _cogl_pipeline_layer_get_parent (authority) != NULL)
394         {
395           CoglPipelineLayer *parent =
396             _cogl_pipeline_layer_get_parent (authority);
397           CoglPipelineLayer *old_authority =
398             _cogl_pipeline_layer_get_authority (parent, change);
399 
400           if (old_authority->sampler_cache_entry == state)
401             {
402               layer->differences &= ~change;
403 
404               g_assert (layer->owner == pipeline);
405               if (layer->differences == 0)
406                 _cogl_pipeline_prune_empty_layer_difference (pipeline,
407                                                              layer);
408               return;
409             }
410         }
411     }
412 
413   layer->sampler_cache_entry = state;
414 
415   /* If we weren't previously the authority on this state then we need
416    * to extended our differences mask and so it's possible that some
417    * of our ancestry will now become redundant, so we aim to reparent
418    * ourselves if that's true... */
419   if (layer != authority)
420     {
421       layer->differences |= change;
422       _cogl_pipeline_layer_prune_redundant_ancestry (layer);
423     }
424 }
425 
426 static CoglSamplerCacheWrapMode
public_to_internal_wrap_mode(CoglPipelineWrapMode mode)427 public_to_internal_wrap_mode (CoglPipelineWrapMode mode)
428 {
429   return (CoglSamplerCacheWrapMode)mode;
430 }
431 
432 static CoglPipelineWrapMode
internal_to_public_wrap_mode(CoglSamplerCacheWrapMode internal_mode)433 internal_to_public_wrap_mode (CoglSamplerCacheWrapMode internal_mode)
434 {
435   _COGL_RETURN_VAL_IF_FAIL (internal_mode !=
436                         COGL_SAMPLER_CACHE_WRAP_MODE_CLAMP_TO_BORDER,
437                         COGL_PIPELINE_WRAP_MODE_AUTOMATIC);
438   return (CoglPipelineWrapMode)internal_mode;
439 }
440 
441 void
cogl_pipeline_set_layer_wrap_mode_s(CoglPipeline * pipeline,int layer_index,CoglPipelineWrapMode mode)442 cogl_pipeline_set_layer_wrap_mode_s (CoglPipeline *pipeline,
443                                      int layer_index,
444                                      CoglPipelineWrapMode mode)
445 {
446   CoglPipelineLayerState       change = COGL_PIPELINE_LAYER_STATE_SAMPLER;
447   CoglPipelineLayer           *layer;
448   CoglPipelineLayer           *authority;
449   CoglSamplerCacheWrapMode     internal_mode =
450     public_to_internal_wrap_mode (mode);
451   const CoglSamplerCacheEntry *sampler_state;
452 
453   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
454 
455   _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
456 
457   /* Note: this will ensure that the layer exists, creating one if it
458    * doesn't already.
459    *
460    * Note: If the layer already existed it's possibly owned by another
461    * pipeline. If the layer is created then it will be owned by
462    * pipeline. */
463   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
464 
465   /* Now find the ancestor of the layer that is the authority for the
466    * state we want to change */
467   authority = _cogl_pipeline_layer_get_authority (layer, change);
468 
469   sampler_state =
470     _cogl_sampler_cache_update_wrap_modes (ctx->sampler_cache,
471                                            authority->sampler_cache_entry,
472                                            internal_mode,
473                                            authority->sampler_cache_entry->
474                                            wrap_mode_t,
475                                            authority->sampler_cache_entry->
476                                            wrap_mode_p);
477   _cogl_pipeline_set_layer_sampler_state (pipeline,
478                                           layer,
479                                           authority,
480                                           sampler_state);
481 }
482 
483 void
cogl_pipeline_set_layer_wrap_mode_t(CoglPipeline * pipeline,int layer_index,CoglPipelineWrapMode mode)484 cogl_pipeline_set_layer_wrap_mode_t (CoglPipeline *pipeline,
485                                      int layer_index,
486                                      CoglPipelineWrapMode mode)
487 {
488   CoglPipelineLayerState       change = COGL_PIPELINE_LAYER_STATE_SAMPLER;
489   CoglPipelineLayer           *layer;
490   CoglPipelineLayer           *authority;
491   CoglSamplerCacheWrapMode     internal_mode =
492     public_to_internal_wrap_mode (mode);
493   const CoglSamplerCacheEntry *sampler_state;
494 
495   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
496 
497   _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
498 
499   /* Note: this will ensure that the layer exists, creating one if it
500    * doesn't already.
501    *
502    * Note: If the layer already existed it's possibly owned by another
503    * pipeline. If the layer is created then it will be owned by
504    * pipeline. */
505   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
506 
507   /* Now find the ancestor of the layer that is the authority for the
508    * state we want to change */
509   authority = _cogl_pipeline_layer_get_authority (layer, change);
510 
511   sampler_state =
512     _cogl_sampler_cache_update_wrap_modes (ctx->sampler_cache,
513                                            authority->sampler_cache_entry,
514                                            authority->sampler_cache_entry->
515                                            wrap_mode_s,
516                                            internal_mode,
517                                            authority->sampler_cache_entry->
518                                            wrap_mode_p);
519   _cogl_pipeline_set_layer_sampler_state (pipeline,
520                                           layer,
521                                           authority,
522                                           sampler_state);
523 }
524 
525 /* The rationale for naming the third texture coordinate 'p' instead
526    of OpenGL's usual 'r' is that 'r' conflicts with the usual naming
527    of the 'red' component when treating a vector as a color. Under
528    GLSL this is awkward because the texture swizzling for a vector
529    uses a single letter for each component and the names for colors,
530    textures and positions are synonymous. GLSL works around this by
531    naming the components of the texture s, t, p and q. Cogl already
532    effectively already exposes this naming because it exposes GLSL so
533    it makes sense to use that naming consistently. Another alternative
534    could be u, v and w. This is what Blender and Direct3D use. However
535    the w component conflicts with the w component of a position
536    vertex.  */
537 void
cogl_pipeline_set_layer_wrap_mode_p(CoglPipeline * pipeline,int layer_index,CoglPipelineWrapMode mode)538 cogl_pipeline_set_layer_wrap_mode_p (CoglPipeline *pipeline,
539                                      int layer_index,
540                                      CoglPipelineWrapMode mode)
541 {
542   CoglPipelineLayerState       change = COGL_PIPELINE_LAYER_STATE_SAMPLER;
543   CoglPipelineLayer           *layer;
544   CoglPipelineLayer           *authority;
545   CoglSamplerCacheWrapMode     internal_mode =
546     public_to_internal_wrap_mode (mode);
547   const CoglSamplerCacheEntry *sampler_state;
548 
549   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
550 
551   _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
552 
553   /* Note: this will ensure that the layer exists, creating one if it
554    * doesn't already.
555    *
556    * Note: If the layer already existed it's possibly owned by another
557    * pipeline. If the layer is created then it will be owned by
558    * pipeline. */
559   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
560 
561   /* Now find the ancestor of the layer that is the authority for the
562    * state we want to change */
563   authority = _cogl_pipeline_layer_get_authority (layer, change);
564 
565   sampler_state =
566     _cogl_sampler_cache_update_wrap_modes (ctx->sampler_cache,
567                                            authority->sampler_cache_entry,
568                                            authority->sampler_cache_entry->
569                                            wrap_mode_s,
570                                            authority->sampler_cache_entry->
571                                            wrap_mode_t,
572                                            internal_mode);
573   _cogl_pipeline_set_layer_sampler_state (pipeline,
574                                           layer,
575                                           authority,
576                                           sampler_state);
577 }
578 
579 void
cogl_pipeline_set_layer_wrap_mode(CoglPipeline * pipeline,int layer_index,CoglPipelineWrapMode mode)580 cogl_pipeline_set_layer_wrap_mode (CoglPipeline *pipeline,
581                                    int layer_index,
582                                    CoglPipelineWrapMode mode)
583 {
584   CoglPipelineLayerState       change = COGL_PIPELINE_LAYER_STATE_SAMPLER;
585   CoglPipelineLayer           *layer;
586   CoglPipelineLayer           *authority;
587   CoglSamplerCacheWrapMode     internal_mode =
588     public_to_internal_wrap_mode (mode);
589   const CoglSamplerCacheEntry *sampler_state;
590 
591   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
592 
593   _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
594 
595   /* Note: this will ensure that the layer exists, creating one if it
596    * doesn't already.
597    *
598    * Note: If the layer already existed it's possibly owned by another
599    * pipeline. If the layer is created then it will be owned by
600    * pipeline. */
601   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
602 
603   /* Now find the ancestor of the layer that is the authority for the
604    * state we want to change */
605   authority = _cogl_pipeline_layer_get_authority (layer, change);
606 
607   sampler_state =
608     _cogl_sampler_cache_update_wrap_modes (ctx->sampler_cache,
609                                            authority->sampler_cache_entry,
610                                            internal_mode,
611                                            internal_mode,
612                                            internal_mode);
613   _cogl_pipeline_set_layer_sampler_state (pipeline,
614                                           layer,
615                                           authority,
616                                           sampler_state);
617   /* XXX: I wonder if we should really be duplicating the mode into
618    * the 'p' wrap mode too? */
619 }
620 
621 /* FIXME: deprecate this API */
622 CoglPipelineWrapMode
_cogl_pipeline_layer_get_wrap_mode_s(CoglPipelineLayer * layer)623 _cogl_pipeline_layer_get_wrap_mode_s (CoglPipelineLayer *layer)
624 {
625   CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_SAMPLER;
626   CoglPipelineLayer     *authority;
627   const CoglSamplerCacheEntry *sampler_state;
628 
629   _COGL_RETURN_VAL_IF_FAIL (_cogl_is_pipeline_layer (layer), FALSE);
630 
631   /* Now find the ancestor of the layer that is the authority for the
632    * state we want to change */
633   authority = _cogl_pipeline_layer_get_authority (layer, change);
634 
635   sampler_state = authority->sampler_cache_entry;
636   return internal_to_public_wrap_mode (sampler_state->wrap_mode_s);
637 }
638 
639 CoglPipelineWrapMode
cogl_pipeline_get_layer_wrap_mode_s(CoglPipeline * pipeline,int layer_index)640 cogl_pipeline_get_layer_wrap_mode_s (CoglPipeline *pipeline, int layer_index)
641 {
642   CoglPipelineLayer *layer;
643 
644   _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE);
645 
646   /* Note: this will ensure that the layer exists, creating one if it
647    * doesn't already.
648    *
649    * Note: If the layer already existed it's possibly owned by another
650    * pipeline. If the layer is created then it will be owned by
651    * pipeline. */
652   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
653   /* FIXME: we shouldn't ever construct a layer in a getter function */
654 
655   return _cogl_pipeline_layer_get_wrap_mode_s (layer);
656 }
657 
658 /* FIXME: deprecate this API */
659 CoglPipelineWrapMode
_cogl_pipeline_layer_get_wrap_mode_t(CoglPipelineLayer * layer)660 _cogl_pipeline_layer_get_wrap_mode_t (CoglPipelineLayer *layer)
661 {
662   CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_SAMPLER;
663   CoglPipelineLayer     *authority;
664   const CoglSamplerCacheEntry *sampler_state;
665 
666   _COGL_RETURN_VAL_IF_FAIL (_cogl_is_pipeline_layer (layer), FALSE);
667 
668   /* Now find the ancestor of the layer that is the authority for the
669    * state we want to change */
670   authority = _cogl_pipeline_layer_get_authority (layer, change);
671 
672   sampler_state = authority->sampler_cache_entry;
673   return internal_to_public_wrap_mode (sampler_state->wrap_mode_t);
674 }
675 
676 CoglPipelineWrapMode
cogl_pipeline_get_layer_wrap_mode_t(CoglPipeline * pipeline,int layer_index)677 cogl_pipeline_get_layer_wrap_mode_t (CoglPipeline *pipeline, int layer_index)
678 {
679   CoglPipelineLayer *layer;
680 
681   _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE);
682 
683   /* Note: this will ensure that the layer exists, creating one if it
684    * doesn't already.
685    *
686    * Note: If the layer already existed it's possibly owned by another
687    * pipeline. If the layer is created then it will be owned by
688    * pipeline. */
689   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
690   /* FIXME: we shouldn't ever construct a layer in a getter function */
691 
692   return _cogl_pipeline_layer_get_wrap_mode_t (layer);
693 }
694 
695 CoglPipelineWrapMode
_cogl_pipeline_layer_get_wrap_mode_p(CoglPipelineLayer * layer)696 _cogl_pipeline_layer_get_wrap_mode_p (CoglPipelineLayer *layer)
697 {
698   CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_SAMPLER;
699   CoglPipelineLayer     *authority =
700     _cogl_pipeline_layer_get_authority (layer, change);
701   const CoglSamplerCacheEntry *sampler_state;
702 
703   sampler_state = authority->sampler_cache_entry;
704   return internal_to_public_wrap_mode (sampler_state->wrap_mode_p);
705 }
706 
707 CoglPipelineWrapMode
cogl_pipeline_get_layer_wrap_mode_p(CoglPipeline * pipeline,int layer_index)708 cogl_pipeline_get_layer_wrap_mode_p (CoglPipeline *pipeline, int layer_index)
709 {
710   CoglPipelineLayer *layer;
711 
712   _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE);
713 
714   /* Note: this will ensure that the layer exists, creating one if it
715    * doesn't already.
716    *
717    * Note: If the layer already existed it's possibly owned by another
718    * pipeline. If the layer is created then it will be owned by
719    * pipeline. */
720   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
721 
722   return _cogl_pipeline_layer_get_wrap_mode_p (layer);
723 }
724 
725 void
_cogl_pipeline_layer_get_wrap_modes(CoglPipelineLayer * layer,CoglSamplerCacheWrapMode * wrap_mode_s,CoglSamplerCacheWrapMode * wrap_mode_t,CoglSamplerCacheWrapMode * wrap_mode_p)726 _cogl_pipeline_layer_get_wrap_modes (CoglPipelineLayer *layer,
727                                      CoglSamplerCacheWrapMode *wrap_mode_s,
728                                      CoglSamplerCacheWrapMode *wrap_mode_t,
729                                      CoglSamplerCacheWrapMode *wrap_mode_p)
730 {
731   CoglPipelineLayer *authority =
732     _cogl_pipeline_layer_get_authority (layer,
733                                         COGL_PIPELINE_LAYER_STATE_SAMPLER);
734 
735   *wrap_mode_s = authority->sampler_cache_entry->wrap_mode_s;
736   *wrap_mode_t = authority->sampler_cache_entry->wrap_mode_t;
737   *wrap_mode_p = authority->sampler_cache_entry->wrap_mode_p;
738 }
739 
740 CoglBool
cogl_pipeline_set_layer_point_sprite_coords_enabled(CoglPipeline * pipeline,int layer_index,CoglBool enable,CoglError ** error)741 cogl_pipeline_set_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
742                                                      int layer_index,
743                                                      CoglBool enable,
744                                                      CoglError **error)
745 {
746   CoglPipelineLayerState       change =
747     COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS;
748   CoglPipelineLayer           *layer;
749   CoglPipelineLayer           *new;
750   CoglPipelineLayer           *authority;
751 
752   _COGL_GET_CONTEXT (ctx, FALSE);
753 
754   _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE);
755 
756   /* Don't allow point sprite coordinates to be enabled if the driver
757      doesn't support it */
758   if (enable && !cogl_has_feature (ctx, COGL_FEATURE_ID_POINT_SPRITE))
759     {
760       if (error)
761         {
762           _cogl_set_error (error,
763                            COGL_SYSTEM_ERROR,
764                            COGL_SYSTEM_ERROR_UNSUPPORTED,
765                            "Point sprite texture coordinates are enabled for "
766                            "a layer but the GL driver does not support it.");
767         }
768       else
769         {
770           static CoglBool warning_seen = FALSE;
771           if (!warning_seen)
772             g_warning ("Point sprite texture coordinates are enabled "
773                        "for a layer but the GL driver does not support it.");
774           warning_seen = TRUE;
775         }
776 
777       return FALSE;
778     }
779 
780   /* Note: this will ensure that the layer exists, creating one if it
781    * doesn't already.
782    *
783    * Note: If the layer already existed it's possibly owned by another
784    * pipeline. If the layer is created then it will be owned by
785    * pipeline. */
786   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
787 
788   /* Now find the ancestor of the layer that is the authority for the
789    * state we want to change */
790   authority = _cogl_pipeline_layer_get_authority (layer, change);
791 
792   if (authority->big_state->point_sprite_coords == enable)
793     return TRUE;
794 
795   new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
796   if (new != layer)
797     layer = new;
798   else
799     {
800       /* If the original layer we found is currently the authority on
801        * the state we are changing see if we can revert to one of our
802        * ancestors being the authority. */
803       if (layer == authority &&
804           _cogl_pipeline_layer_get_parent (authority) != NULL)
805         {
806           CoglPipelineLayer *parent =
807             _cogl_pipeline_layer_get_parent (authority);
808           CoglPipelineLayer *old_authority =
809             _cogl_pipeline_layer_get_authority (parent, change);
810 
811           if (old_authority->big_state->point_sprite_coords == enable)
812             {
813               layer->differences &= ~change;
814 
815               g_assert (layer->owner == pipeline);
816               if (layer->differences == 0)
817                 _cogl_pipeline_prune_empty_layer_difference (pipeline,
818                                                              layer);
819               return TRUE;
820             }
821         }
822     }
823 
824   layer->big_state->point_sprite_coords = enable;
825 
826   /* If we weren't previously the authority on this state then we need
827    * to extended our differences mask and so it's possible that some
828    * of our ancestry will now become redundant, so we aim to reparent
829    * ourselves if that's true... */
830   if (layer != authority)
831     {
832       layer->differences |= change;
833       _cogl_pipeline_layer_prune_redundant_ancestry (layer);
834     }
835 
836   return TRUE;
837 }
838 
839 CoglBool
cogl_pipeline_get_layer_point_sprite_coords_enabled(CoglPipeline * pipeline,int layer_index)840 cogl_pipeline_get_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
841                                                      int layer_index)
842 {
843   CoglPipelineLayerState       change =
844     COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS;
845   CoglPipelineLayer *layer;
846   CoglPipelineLayer *authority;
847 
848   _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE);
849 
850   /* Note: this will ensure that the layer exists, creating one if it
851    * doesn't already.
852    *
853    * Note: If the layer already existed it's possibly owned by another
854    * pipeline. If the layer is created then it will be owned by
855    * pipeline. */
856   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
857   /* FIXME: we shouldn't ever construct a layer in a getter function */
858 
859   authority = _cogl_pipeline_layer_get_authority (layer, change);
860 
861   return authority->big_state->point_sprite_coords;
862 }
863 
864 static void
_cogl_pipeline_layer_add_vertex_snippet(CoglPipeline * pipeline,int layer_index,CoglSnippet * snippet)865 _cogl_pipeline_layer_add_vertex_snippet (CoglPipeline *pipeline,
866                                          int layer_index,
867                                          CoglSnippet *snippet)
868 {
869   CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS;
870   CoglPipelineLayer *layer, *authority;
871 
872   /* Note: this will ensure that the layer exists, creating one if it
873    * doesn't already.
874    *
875    * Note: If the layer already existed it's possibly owned by another
876    * pipeline. If the layer is created then it will be owned by
877    * pipeline. */
878   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
879 
880   /* Now find the ancestor of the layer that is the authority for the
881    * state we want to change */
882   authority = _cogl_pipeline_layer_get_authority (layer, change);
883 
884   layer = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
885 
886   _cogl_pipeline_snippet_list_add (&layer->big_state->vertex_snippets,
887                                    snippet);
888 
889   /* If we weren't previously the authority on this state then we need
890    * to extended our differences mask and so it's possible that some
891    * of our ancestry will now become redundant, so we aim to reparent
892    * ourselves if that's true... */
893   if (layer != authority)
894     {
895       layer->differences |= change;
896       _cogl_pipeline_layer_prune_redundant_ancestry (layer);
897     }
898 }
899 
900 static void
_cogl_pipeline_layer_add_fragment_snippet(CoglPipeline * pipeline,int layer_index,CoglSnippet * snippet)901 _cogl_pipeline_layer_add_fragment_snippet (CoglPipeline *pipeline,
902                                            int layer_index,
903                                            CoglSnippet *snippet)
904 {
905   CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS;
906   CoglPipelineLayer *layer, *authority;
907 
908   /* Note: this will ensure that the layer exists, creating one if it
909    * doesn't already.
910    *
911    * Note: If the layer already existed it's possibly owned by another
912    * pipeline. If the layer is created then it will be owned by
913    * pipeline. */
914   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
915 
916   /* Now find the ancestor of the layer that is the authority for the
917    * state we want to change */
918   authority = _cogl_pipeline_layer_get_authority (layer, change);
919 
920   layer = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
921 
922   _cogl_pipeline_snippet_list_add (&layer->big_state->fragment_snippets,
923                                    snippet);
924 
925   /* If we weren't previously the authority on this state then we need
926    * to extended our differences mask and so it's possible that some
927    * of our ancestry will now become redundant, so we aim to reparent
928    * ourselves if that's true... */
929   if (layer != authority)
930     {
931       layer->differences |= change;
932       _cogl_pipeline_layer_prune_redundant_ancestry (layer);
933     }
934 }
935 
936 void
cogl_pipeline_add_layer_snippet(CoglPipeline * pipeline,int layer_index,CoglSnippet * snippet)937 cogl_pipeline_add_layer_snippet (CoglPipeline *pipeline,
938                                  int layer_index,
939                                  CoglSnippet *snippet)
940 {
941   _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
942   _COGL_RETURN_IF_FAIL (cogl_is_snippet (snippet));
943   _COGL_RETURN_IF_FAIL (snippet->hook >= COGL_SNIPPET_FIRST_LAYER_HOOK);
944 
945   if (snippet->hook < COGL_SNIPPET_FIRST_LAYER_FRAGMENT_HOOK)
946     _cogl_pipeline_layer_add_vertex_snippet (pipeline,
947                                              layer_index,
948                                              snippet);
949   else
950     _cogl_pipeline_layer_add_fragment_snippet (pipeline,
951                                                layer_index,
952                                                snippet);
953 }
954 
955 CoglBool
_cogl_pipeline_layer_texture_type_equal(CoglPipelineLayer * authority0,CoglPipelineLayer * authority1,CoglPipelineEvalFlags flags)956 _cogl_pipeline_layer_texture_type_equal (CoglPipelineLayer *authority0,
957                                          CoglPipelineLayer *authority1,
958                                          CoglPipelineEvalFlags flags)
959 {
960   return authority0->texture_type == authority1->texture_type;
961 }
962 
963 CoglBool
_cogl_pipeline_layer_texture_data_equal(CoglPipelineLayer * authority0,CoglPipelineLayer * authority1,CoglPipelineEvalFlags flags)964 _cogl_pipeline_layer_texture_data_equal (CoglPipelineLayer *authority0,
965                                          CoglPipelineLayer *authority1,
966                                          CoglPipelineEvalFlags flags)
967 {
968   if (authority0->texture == NULL)
969     {
970       if (authority1->texture == NULL)
971         return (_cogl_pipeline_layer_get_texture_type (authority0) ==
972                 _cogl_pipeline_layer_get_texture_type (authority1));
973       else
974         return FALSE;
975     }
976   else if (authority1->texture == NULL)
977     return FALSE;
978   else
979     {
980       GLuint gl_handle0, gl_handle1;
981 
982       cogl_texture_get_gl_texture (authority0->texture, &gl_handle0, NULL);
983       cogl_texture_get_gl_texture (authority1->texture, &gl_handle1, NULL);
984 
985       return gl_handle0 == gl_handle1;
986     }
987 }
988 
989 CoglBool
_cogl_pipeline_layer_combine_state_equal(CoglPipelineLayer * authority0,CoglPipelineLayer * authority1)990 _cogl_pipeline_layer_combine_state_equal (CoglPipelineLayer *authority0,
991                                           CoglPipelineLayer *authority1)
992 {
993   CoglPipelineLayerBigState *big_state0 = authority0->big_state;
994   CoglPipelineLayerBigState *big_state1 = authority1->big_state;
995   int n_args;
996   int i;
997 
998   if (big_state0->texture_combine_rgb_func !=
999       big_state1->texture_combine_rgb_func)
1000     return FALSE;
1001 
1002   if (big_state0->texture_combine_alpha_func !=
1003       big_state1->texture_combine_alpha_func)
1004     return FALSE;
1005 
1006   n_args =
1007     _cogl_get_n_args_for_combine_func (big_state0->texture_combine_rgb_func);
1008   for (i = 0; i < n_args; i++)
1009     {
1010       if ((big_state0->texture_combine_rgb_src[i] !=
1011            big_state1->texture_combine_rgb_src[i]) ||
1012           (big_state0->texture_combine_rgb_op[i] !=
1013            big_state1->texture_combine_rgb_op[i]))
1014         return FALSE;
1015     }
1016 
1017   n_args =
1018     _cogl_get_n_args_for_combine_func (big_state0->texture_combine_alpha_func);
1019   for (i = 0; i < n_args; i++)
1020     {
1021       if ((big_state0->texture_combine_alpha_src[i] !=
1022            big_state1->texture_combine_alpha_src[i]) ||
1023           (big_state0->texture_combine_alpha_op[i] !=
1024            big_state1->texture_combine_alpha_op[i]))
1025         return FALSE;
1026     }
1027 
1028   return TRUE;
1029 }
1030 
1031 CoglBool
_cogl_pipeline_layer_combine_constant_equal(CoglPipelineLayer * authority0,CoglPipelineLayer * authority1)1032 _cogl_pipeline_layer_combine_constant_equal (CoglPipelineLayer *authority0,
1033                                              CoglPipelineLayer *authority1)
1034 {
1035   return memcmp (authority0->big_state->texture_combine_constant,
1036                  authority1->big_state->texture_combine_constant,
1037                  sizeof (float) * 4) == 0 ? TRUE : FALSE;
1038 }
1039 
1040 CoglBool
_cogl_pipeline_layer_sampler_equal(CoglPipelineLayer * authority0,CoglPipelineLayer * authority1)1041 _cogl_pipeline_layer_sampler_equal (CoglPipelineLayer *authority0,
1042                                     CoglPipelineLayer *authority1)
1043 {
1044   /* We compare the actual sampler objects rather than just the entry
1045      pointers because two states with different values can lead to the
1046      same state in GL terms when AUTOMATIC is used as a wrap mode */
1047   return (authority0->sampler_cache_entry->sampler_object ==
1048           authority1->sampler_cache_entry->sampler_object);
1049 }
1050 
1051 CoglBool
_cogl_pipeline_layer_user_matrix_equal(CoglPipelineLayer * authority0,CoglPipelineLayer * authority1)1052 _cogl_pipeline_layer_user_matrix_equal (CoglPipelineLayer *authority0,
1053                                         CoglPipelineLayer *authority1)
1054 {
1055   CoglPipelineLayerBigState *big_state0 = authority0->big_state;
1056   CoglPipelineLayerBigState *big_state1 = authority1->big_state;
1057 
1058   if (!cogl_matrix_equal (&big_state0->matrix, &big_state1->matrix))
1059     return FALSE;
1060 
1061   return TRUE;
1062 }
1063 
1064 CoglBool
_cogl_pipeline_layer_point_sprite_coords_equal(CoglPipelineLayer * authority0,CoglPipelineLayer * authority1)1065 _cogl_pipeline_layer_point_sprite_coords_equal (CoglPipelineLayer *authority0,
1066                                                 CoglPipelineLayer *authority1)
1067 {
1068   CoglPipelineLayerBigState *big_state0 = authority0->big_state;
1069   CoglPipelineLayerBigState *big_state1 = authority1->big_state;
1070 
1071   return big_state0->point_sprite_coords == big_state1->point_sprite_coords;
1072 }
1073 
1074 CoglBool
_cogl_pipeline_layer_vertex_snippets_equal(CoglPipelineLayer * authority0,CoglPipelineLayer * authority1)1075 _cogl_pipeline_layer_vertex_snippets_equal (CoglPipelineLayer *authority0,
1076                                             CoglPipelineLayer *authority1)
1077 {
1078   return _cogl_pipeline_snippet_list_equal (&authority0->big_state->
1079                                             vertex_snippets,
1080                                             &authority1->big_state->
1081                                             vertex_snippets);
1082 }
1083 
1084 CoglBool
_cogl_pipeline_layer_fragment_snippets_equal(CoglPipelineLayer * authority0,CoglPipelineLayer * authority1)1085 _cogl_pipeline_layer_fragment_snippets_equal (CoglPipelineLayer *authority0,
1086                                               CoglPipelineLayer *authority1)
1087 {
1088   return _cogl_pipeline_snippet_list_equal (&authority0->big_state->
1089                                             fragment_snippets,
1090                                             &authority1->big_state->
1091                                             fragment_snippets);
1092 }
1093 
1094 static void
setup_texture_combine_state(CoglBlendStringStatement * statement,CoglPipelineCombineFunc * texture_combine_func,CoglPipelineCombineSource * texture_combine_src,CoglPipelineCombineOp * texture_combine_op)1095 setup_texture_combine_state (CoglBlendStringStatement *statement,
1096                              CoglPipelineCombineFunc *texture_combine_func,
1097                              CoglPipelineCombineSource *texture_combine_src,
1098                              CoglPipelineCombineOp *texture_combine_op)
1099 {
1100   int i;
1101 
1102   switch (statement->function->type)
1103     {
1104     case COGL_BLEND_STRING_FUNCTION_REPLACE:
1105       *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_REPLACE;
1106       break;
1107     case COGL_BLEND_STRING_FUNCTION_MODULATE:
1108       *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_MODULATE;
1109       break;
1110     case COGL_BLEND_STRING_FUNCTION_ADD:
1111       *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_ADD;
1112       break;
1113     case COGL_BLEND_STRING_FUNCTION_ADD_SIGNED:
1114       *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED;
1115       break;
1116     case COGL_BLEND_STRING_FUNCTION_INTERPOLATE:
1117       *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE;
1118       break;
1119     case COGL_BLEND_STRING_FUNCTION_SUBTRACT:
1120       *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_SUBTRACT;
1121       break;
1122     case COGL_BLEND_STRING_FUNCTION_DOT3_RGB:
1123       *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB;
1124       break;
1125     case COGL_BLEND_STRING_FUNCTION_DOT3_RGBA:
1126       *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA;
1127       break;
1128     }
1129 
1130   for (i = 0; i < statement->function->argc; i++)
1131     {
1132       CoglBlendStringArgument *arg = &statement->args[i];
1133 
1134       switch (arg->source.info->type)
1135         {
1136         case COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT:
1137           texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_CONSTANT;
1138           break;
1139         case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE:
1140           texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
1141           break;
1142         case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N:
1143           texture_combine_src[i] =
1144             COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0 + arg->source.texture;
1145           break;
1146         case COGL_BLEND_STRING_COLOR_SOURCE_PRIMARY:
1147           texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR;
1148           break;
1149         case COGL_BLEND_STRING_COLOR_SOURCE_PREVIOUS:
1150           texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS;
1151           break;
1152         default:
1153           g_warning ("Unexpected texture combine source");
1154           texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
1155         }
1156 
1157       if (arg->source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB)
1158         {
1159           if (statement->args[i].source.one_minus)
1160             texture_combine_op[i] =
1161               COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_COLOR;
1162           else
1163             texture_combine_op[i] = COGL_PIPELINE_COMBINE_OP_SRC_COLOR;
1164         }
1165       else
1166         {
1167           if (statement->args[i].source.one_minus)
1168             texture_combine_op[i] =
1169               COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA;
1170           else
1171             texture_combine_op[i] = COGL_PIPELINE_COMBINE_OP_SRC_ALPHA;
1172         }
1173     }
1174 }
1175 
1176 CoglBool
cogl_pipeline_set_layer_combine(CoglPipeline * pipeline,int layer_index,const char * combine_description,CoglError ** error)1177 cogl_pipeline_set_layer_combine (CoglPipeline *pipeline,
1178 				 int layer_index,
1179 				 const char *combine_description,
1180                                  CoglError **error)
1181 {
1182   CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_COMBINE;
1183   CoglPipelineLayer *authority;
1184   CoglPipelineLayer *layer;
1185   CoglBlendStringStatement statements[2];
1186   CoglBlendStringStatement split[2];
1187   CoglBlendStringStatement *rgb;
1188   CoglBlendStringStatement *a;
1189   int count;
1190 
1191   _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE);
1192 
1193   /* Note: this will ensure that the layer exists, creating one if it
1194    * doesn't already.
1195    *
1196    * Note: If the layer already existed it's possibly owned by another
1197    * pipeline. If the layer is created then it will be owned by
1198    * pipeline. */
1199   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
1200 
1201   /* Now find the ancestor of the layer that is the authority for the
1202    * state we want to change */
1203   authority = _cogl_pipeline_layer_get_authority (layer, state);
1204 
1205   count =
1206     _cogl_blend_string_compile (combine_description,
1207                                 COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE,
1208                                 statements,
1209                                 error);
1210   if (!count)
1211     return FALSE;
1212 
1213   if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA)
1214     {
1215       _cogl_blend_string_split_rgba_statement (statements,
1216                                                &split[0], &split[1]);
1217       rgb = &split[0];
1218       a = &split[1];
1219     }
1220   else
1221     {
1222       rgb = &statements[0];
1223       a = &statements[1];
1224     }
1225 
1226   /* FIXME: compare the new state with the current state! */
1227 
1228   /* possibly flush primitives referencing the current state... */
1229   layer = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state);
1230 
1231   setup_texture_combine_state (rgb,
1232                                &layer->big_state->texture_combine_rgb_func,
1233                                layer->big_state->texture_combine_rgb_src,
1234                                layer->big_state->texture_combine_rgb_op);
1235 
1236   setup_texture_combine_state (a,
1237                                &layer->big_state->texture_combine_alpha_func,
1238                                layer->big_state->texture_combine_alpha_src,
1239                                layer->big_state->texture_combine_alpha_op);
1240 
1241   /* If the original layer we found is currently the authority on
1242    * the state we are changing see if we can revert to one of our
1243    * ancestors being the authority. */
1244   if (layer == authority &&
1245       _cogl_pipeline_layer_get_parent (authority) != NULL)
1246     {
1247       CoglPipelineLayer *parent = _cogl_pipeline_layer_get_parent (authority);
1248       CoglPipelineLayer *old_authority =
1249         _cogl_pipeline_layer_get_authority (parent, state);
1250 
1251       if (_cogl_pipeline_layer_combine_state_equal (authority,
1252                                                     old_authority))
1253         {
1254           layer->differences &= ~state;
1255 
1256           g_assert (layer->owner == pipeline);
1257           if (layer->differences == 0)
1258             _cogl_pipeline_prune_empty_layer_difference (pipeline,
1259                                                          layer);
1260           goto changed;
1261         }
1262     }
1263 
1264   /* If we weren't previously the authority on this state then we need
1265    * to extended our differences mask and so it's possible that some
1266    * of our ancestry will now become redundant, so we aim to reparent
1267    * ourselves if that's true... */
1268   if (layer != authority)
1269     {
1270       layer->differences |= state;
1271       _cogl_pipeline_layer_prune_redundant_ancestry (layer);
1272     }
1273 
1274 changed:
1275 
1276   pipeline->dirty_real_blend_enable = TRUE;
1277   return TRUE;
1278 }
1279 
1280 void
cogl_pipeline_set_layer_combine_constant(CoglPipeline * pipeline,int layer_index,const CoglColor * constant_color)1281 cogl_pipeline_set_layer_combine_constant (CoglPipeline *pipeline,
1282 				          int layer_index,
1283                                           const CoglColor *constant_color)
1284 {
1285   CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT;
1286   CoglPipelineLayer     *layer;
1287   CoglPipelineLayer     *authority;
1288   CoglPipelineLayer     *new;
1289   float                  color_as_floats[4];
1290 
1291   _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
1292 
1293   /* Note: this will ensure that the layer exists, creating one if it
1294    * doesn't already.
1295    *
1296    * Note: If the layer already existed it's possibly owned by another
1297    * pipeline. If the layer is created then it will be owned by
1298    * pipeline. */
1299   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
1300 
1301   /* Now find the ancestor of the layer that is the authority for the
1302    * state we want to change */
1303   authority = _cogl_pipeline_layer_get_authority (layer, state);
1304 
1305   color_as_floats[0] = cogl_color_get_red_float (constant_color);
1306   color_as_floats[1] = cogl_color_get_green_float (constant_color);
1307   color_as_floats[2] = cogl_color_get_blue_float (constant_color);
1308   color_as_floats[3] = cogl_color_get_alpha_float (constant_color);
1309 
1310   if (memcmp (authority->big_state->texture_combine_constant,
1311               color_as_floats, sizeof (float) * 4) == 0)
1312     return;
1313 
1314   new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state);
1315   if (new != layer)
1316     layer = new;
1317   else
1318     {
1319       /* If the original layer we found is currently the authority on
1320        * the state we are changing see if we can revert to one of our
1321        * ancestors being the authority. */
1322       if (layer == authority &&
1323           _cogl_pipeline_layer_get_parent (authority) != NULL)
1324         {
1325           CoglPipelineLayer *parent =
1326             _cogl_pipeline_layer_get_parent (authority);
1327           CoglPipelineLayer *old_authority =
1328             _cogl_pipeline_layer_get_authority (parent, state);
1329           CoglPipelineLayerBigState *old_big_state = old_authority->big_state;
1330 
1331           if (memcmp (old_big_state->texture_combine_constant,
1332                       color_as_floats, sizeof (float) * 4) == 0)
1333             {
1334               layer->differences &= ~state;
1335 
1336               g_assert (layer->owner == pipeline);
1337               if (layer->differences == 0)
1338                 _cogl_pipeline_prune_empty_layer_difference (pipeline,
1339                                                              layer);
1340               goto changed;
1341             }
1342         }
1343     }
1344 
1345   memcpy (layer->big_state->texture_combine_constant,
1346           color_as_floats,
1347           sizeof (color_as_floats));
1348 
1349   /* If we weren't previously the authority on this state then we need
1350    * to extended our differences mask and so it's possible that some
1351    * of our ancestry will now become redundant, so we aim to reparent
1352    * ourselves if that's true... */
1353   if (layer != authority)
1354     {
1355       layer->differences |= state;
1356       _cogl_pipeline_layer_prune_redundant_ancestry (layer);
1357     }
1358 
1359 changed:
1360 
1361   pipeline->dirty_real_blend_enable = TRUE;
1362 }
1363 
1364 void
_cogl_pipeline_get_layer_combine_constant(CoglPipeline * pipeline,int layer_index,float * constant)1365 _cogl_pipeline_get_layer_combine_constant (CoglPipeline *pipeline,
1366                                            int layer_index,
1367                                            float *constant)
1368 {
1369   CoglPipelineLayerState       change =
1370     COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT;
1371   CoglPipelineLayer *layer;
1372   CoglPipelineLayer *authority;
1373 
1374   _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
1375 
1376   /* Note: this will ensure that the layer exists, creating one if it
1377    * doesn't already.
1378    *
1379    * Note: If the layer already existed it's possibly owned by another
1380    * pipeline. If the layer is created then it will be owned by
1381    * pipeline. */
1382   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
1383   /* FIXME: we shouldn't ever construct a layer in a getter function */
1384 
1385   authority = _cogl_pipeline_layer_get_authority (layer, change);
1386   memcpy (constant, authority->big_state->texture_combine_constant,
1387           sizeof (float) * 4);
1388 }
1389 
1390 /* We should probably make a public API version of this that has a
1391    matrix out-param. For an internal API it's good to be able to avoid
1392    copying the matrix */
1393 const CoglMatrix *
_cogl_pipeline_get_layer_matrix(CoglPipeline * pipeline,int layer_index)1394 _cogl_pipeline_get_layer_matrix (CoglPipeline *pipeline, int layer_index)
1395 {
1396   CoglPipelineLayerState       change =
1397     COGL_PIPELINE_LAYER_STATE_USER_MATRIX;
1398   CoglPipelineLayer *layer;
1399   CoglPipelineLayer *authority;
1400 
1401   _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), NULL);
1402 
1403   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
1404 
1405   authority = _cogl_pipeline_layer_get_authority (layer, change);
1406   return &authority->big_state->matrix;
1407 }
1408 
1409 void
cogl_pipeline_set_layer_matrix(CoglPipeline * pipeline,int layer_index,const CoglMatrix * matrix)1410 cogl_pipeline_set_layer_matrix (CoglPipeline *pipeline,
1411 				int layer_index,
1412                                 const CoglMatrix *matrix)
1413 {
1414   CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_USER_MATRIX;
1415   CoglPipelineLayer     *layer;
1416   CoglPipelineLayer     *authority;
1417   CoglPipelineLayer     *new;
1418 
1419   _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
1420 
1421   /* Note: this will ensure that the layer exists, creating one if it
1422    * doesn't already.
1423    *
1424    * Note: If the layer already existed it's possibly owned by another
1425    * pipeline. If the layer is created then it will be owned by
1426    * pipeline. */
1427   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
1428 
1429   /* Now find the ancestor of the layer that is the authority for the
1430    * state we want to change */
1431   authority = _cogl_pipeline_layer_get_authority (layer, state);
1432 
1433   if (cogl_matrix_equal (matrix, &authority->big_state->matrix))
1434     return;
1435 
1436   new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state);
1437   if (new != layer)
1438     layer = new;
1439   else
1440     {
1441       /* If the original layer we found is currently the authority on
1442        * the state we are changing see if we can revert to one of our
1443        * ancestors being the authority. */
1444       if (layer == authority &&
1445           _cogl_pipeline_layer_get_parent (authority) != NULL)
1446         {
1447           CoglPipelineLayer *parent =
1448             _cogl_pipeline_layer_get_parent (authority);
1449           CoglPipelineLayer *old_authority =
1450             _cogl_pipeline_layer_get_authority (parent, state);
1451 
1452           if (cogl_matrix_equal (matrix, &old_authority->big_state->matrix))
1453             {
1454               layer->differences &= ~state;
1455 
1456               g_assert (layer->owner == pipeline);
1457               if (layer->differences == 0)
1458                 _cogl_pipeline_prune_empty_layer_difference (pipeline,
1459                                                              layer);
1460               return;
1461             }
1462         }
1463     }
1464 
1465   layer->big_state->matrix = *matrix;
1466 
1467   /* If we weren't previously the authority on this state then we need
1468    * to extended our differences mask and so it's possible that some
1469    * of our ancestry will now become redundant, so we aim to reparent
1470    * ourselves if that's true... */
1471   if (layer != authority)
1472     {
1473       layer->differences |= state;
1474       _cogl_pipeline_layer_prune_redundant_ancestry (layer);
1475     }
1476 }
1477 
1478 CoglTexture *
_cogl_pipeline_layer_get_texture(CoglPipelineLayer * layer)1479 _cogl_pipeline_layer_get_texture (CoglPipelineLayer *layer)
1480 {
1481   _COGL_RETURN_VAL_IF_FAIL (_cogl_is_pipeline_layer (layer), NULL);
1482 
1483   return _cogl_pipeline_layer_get_texture_real (layer);
1484 }
1485 
1486 CoglBool
_cogl_pipeline_layer_has_user_matrix(CoglPipeline * pipeline,int layer_index)1487 _cogl_pipeline_layer_has_user_matrix (CoglPipeline *pipeline,
1488                                       int layer_index)
1489 {
1490   CoglPipelineLayer *layer;
1491   CoglPipelineLayer *authority;
1492 
1493   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
1494 
1495   authority =
1496     _cogl_pipeline_layer_get_authority (layer,
1497                                         COGL_PIPELINE_LAYER_STATE_USER_MATRIX);
1498 
1499   /* If the authority is the default pipeline then no, otherwise yes */
1500   return _cogl_pipeline_layer_get_parent (authority) ? TRUE : FALSE;
1501 }
1502 
1503 void
_cogl_pipeline_layer_get_filters(CoglPipelineLayer * layer,CoglPipelineFilter * min_filter,CoglPipelineFilter * mag_filter)1504 _cogl_pipeline_layer_get_filters (CoglPipelineLayer *layer,
1505                                   CoglPipelineFilter *min_filter,
1506                                   CoglPipelineFilter *mag_filter)
1507 {
1508   CoglPipelineLayer *authority =
1509     _cogl_pipeline_layer_get_authority (layer,
1510                                         COGL_PIPELINE_LAYER_STATE_SAMPLER);
1511 
1512   *min_filter = authority->sampler_cache_entry->min_filter;
1513   *mag_filter = authority->sampler_cache_entry->mag_filter;
1514 }
1515 
1516 void
_cogl_pipeline_get_layer_filters(CoglPipeline * pipeline,int layer_index,CoglPipelineFilter * min_filter,CoglPipelineFilter * mag_filter)1517 _cogl_pipeline_get_layer_filters (CoglPipeline *pipeline,
1518                                   int layer_index,
1519                                   CoglPipelineFilter *min_filter,
1520                                   CoglPipelineFilter *mag_filter)
1521 {
1522   CoglPipelineLayer *layer;
1523   CoglPipelineLayer *authority;
1524 
1525   _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
1526 
1527   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
1528 
1529   authority =
1530     _cogl_pipeline_layer_get_authority (layer,
1531                                         COGL_PIPELINE_LAYER_STATE_SAMPLER);
1532 
1533   *min_filter = authority->sampler_cache_entry->min_filter;
1534   *mag_filter = authority->sampler_cache_entry->mag_filter;
1535 }
1536 
1537 CoglPipelineFilter
cogl_pipeline_get_layer_min_filter(CoglPipeline * pipeline,int layer_index)1538 cogl_pipeline_get_layer_min_filter (CoglPipeline *pipeline,
1539                                     int layer_index)
1540 {
1541   CoglPipelineFilter min_filter;
1542   CoglPipelineFilter mag_filter;
1543 
1544   _cogl_pipeline_get_layer_filters (pipeline, layer_index,
1545                                     &min_filter, &mag_filter);
1546   return min_filter;
1547 }
1548 
1549 CoglPipelineFilter
cogl_pipeline_get_layer_mag_filter(CoglPipeline * pipeline,int layer_index)1550 cogl_pipeline_get_layer_mag_filter (CoglPipeline *pipeline,
1551                                     int layer_index)
1552 {
1553   CoglPipelineFilter min_filter;
1554   CoglPipelineFilter mag_filter;
1555 
1556   _cogl_pipeline_get_layer_filters (pipeline, layer_index,
1557                                     &min_filter, &mag_filter);
1558   return mag_filter;
1559 }
1560 
1561 CoglPipelineFilter
_cogl_pipeline_layer_get_min_filter(CoglPipelineLayer * layer)1562 _cogl_pipeline_layer_get_min_filter (CoglPipelineLayer *layer)
1563 {
1564   CoglPipelineLayer *authority;
1565 
1566   _COGL_RETURN_VAL_IF_FAIL (_cogl_is_pipeline_layer (layer), 0);
1567 
1568   authority =
1569     _cogl_pipeline_layer_get_authority (layer,
1570                                         COGL_PIPELINE_LAYER_STATE_SAMPLER);
1571 
1572   return authority->sampler_cache_entry->min_filter;
1573 }
1574 
1575 CoglPipelineFilter
_cogl_pipeline_layer_get_mag_filter(CoglPipelineLayer * layer)1576 _cogl_pipeline_layer_get_mag_filter (CoglPipelineLayer *layer)
1577 {
1578   CoglPipelineLayer *authority;
1579 
1580   _COGL_RETURN_VAL_IF_FAIL (_cogl_is_pipeline_layer (layer), 0);
1581 
1582   authority =
1583     _cogl_pipeline_layer_get_authority (layer,
1584                                         COGL_PIPELINE_LAYER_STATE_SAMPLER);
1585 
1586   return authority->sampler_cache_entry->mag_filter;
1587 }
1588 
1589 void
cogl_pipeline_set_layer_filters(CoglPipeline * pipeline,int layer_index,CoglPipelineFilter min_filter,CoglPipelineFilter mag_filter)1590 cogl_pipeline_set_layer_filters (CoglPipeline      *pipeline,
1591                                  int                layer_index,
1592                                  CoglPipelineFilter min_filter,
1593                                  CoglPipelineFilter mag_filter)
1594 {
1595   CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_SAMPLER;
1596   CoglPipelineLayer *layer;
1597   CoglPipelineLayer *authority;
1598   const CoglSamplerCacheEntry *sampler_state;
1599 
1600   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1601 
1602   _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
1603 
1604   _COGL_RETURN_IF_FAIL (mag_filter == COGL_PIPELINE_FILTER_NEAREST ||
1605                         mag_filter == COGL_PIPELINE_FILTER_LINEAR);
1606 
1607   /* Note: this will ensure that the layer exists, creating one if it
1608    * doesn't already.
1609    *
1610    * Note: If the layer already existed it's possibly owned by another
1611    * pipeline. If the layer is created then it will be owned by
1612    * pipeline. */
1613   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
1614 
1615   /* Now find the ancestor of the layer that is the authority for the
1616    * state we want to change */
1617   authority = _cogl_pipeline_layer_get_authority (layer, state);
1618 
1619   sampler_state =
1620     _cogl_sampler_cache_update_filters (ctx->sampler_cache,
1621                                         authority->sampler_cache_entry,
1622                                         min_filter,
1623                                         mag_filter);
1624   _cogl_pipeline_set_layer_sampler_state (pipeline,
1625                                           layer,
1626                                           authority,
1627                                           sampler_state);
1628 }
1629 
1630 const CoglSamplerCacheEntry *
_cogl_pipeline_layer_get_sampler_state(CoglPipelineLayer * layer)1631 _cogl_pipeline_layer_get_sampler_state (CoglPipelineLayer *layer)
1632 {
1633   CoglPipelineLayer *authority;
1634 
1635   authority =
1636     _cogl_pipeline_layer_get_authority (layer,
1637                                         COGL_PIPELINE_LAYER_STATE_SAMPLER);
1638 
1639   return authority->sampler_cache_entry;
1640 }
1641 
1642 void
_cogl_pipeline_layer_hash_unit_state(CoglPipelineLayer * authority,CoglPipelineLayer ** authorities,CoglPipelineHashState * state)1643 _cogl_pipeline_layer_hash_unit_state (CoglPipelineLayer *authority,
1644                                       CoglPipelineLayer **authorities,
1645                                       CoglPipelineHashState *state)
1646 {
1647   int unit = authority->unit_index;
1648   state->hash =
1649     _cogl_util_one_at_a_time_hash (state->hash, &unit, sizeof (unit));
1650 }
1651 
1652 void
_cogl_pipeline_layer_hash_texture_type_state(CoglPipelineLayer * authority,CoglPipelineLayer ** authorities,CoglPipelineHashState * state)1653 _cogl_pipeline_layer_hash_texture_type_state (CoglPipelineLayer *authority,
1654                                               CoglPipelineLayer **authorities,
1655                                               CoglPipelineHashState *state)
1656 {
1657   CoglTextureType texture_type = authority->texture_type;
1658 
1659   state->hash = _cogl_util_one_at_a_time_hash (state->hash,
1660                                                &texture_type,
1661                                                sizeof (texture_type));
1662 }
1663 
1664 void
_cogl_pipeline_layer_hash_texture_data_state(CoglPipelineLayer * authority,CoglPipelineLayer ** authorities,CoglPipelineHashState * state)1665 _cogl_pipeline_layer_hash_texture_data_state (CoglPipelineLayer *authority,
1666                                               CoglPipelineLayer **authorities,
1667                                               CoglPipelineHashState *state)
1668 {
1669   GLuint gl_handle;
1670 
1671   cogl_texture_get_gl_texture (authority->texture, &gl_handle, NULL);
1672 
1673   state->hash =
1674     _cogl_util_one_at_a_time_hash (state->hash, &gl_handle, sizeof (gl_handle));
1675 }
1676 
1677 void
_cogl_pipeline_layer_hash_sampler_state(CoglPipelineLayer * authority,CoglPipelineLayer ** authorities,CoglPipelineHashState * state)1678 _cogl_pipeline_layer_hash_sampler_state (CoglPipelineLayer *authority,
1679                                          CoglPipelineLayer **authorities,
1680                                          CoglPipelineHashState *state)
1681 {
1682   state->hash =
1683     _cogl_util_one_at_a_time_hash (state->hash,
1684                                    &authority->sampler_cache_entry,
1685                                    sizeof (authority->sampler_cache_entry));
1686 }
1687 
1688 void
_cogl_pipeline_layer_hash_combine_state(CoglPipelineLayer * authority,CoglPipelineLayer ** authorities,CoglPipelineHashState * state)1689 _cogl_pipeline_layer_hash_combine_state (CoglPipelineLayer *authority,
1690                                          CoglPipelineLayer **authorities,
1691                                          CoglPipelineHashState *state)
1692 {
1693   unsigned int hash = state->hash;
1694   CoglPipelineLayerBigState *b = authority->big_state;
1695   int n_args;
1696   int i;
1697 
1698   hash = _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_func,
1699                                         sizeof (b->texture_combine_rgb_func));
1700   n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_rgb_func);
1701   for (i = 0; i < n_args; i++)
1702     {
1703       hash =
1704         _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_src[i],
1705                                        sizeof (b->texture_combine_rgb_src[i]));
1706       hash =
1707         _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_op[i],
1708                                        sizeof (b->texture_combine_rgb_op[i]));
1709     }
1710 
1711   hash = _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_func,
1712                                         sizeof (b->texture_combine_alpha_func));
1713   n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_alpha_func);
1714   for (i = 0; i < n_args; i++)
1715     {
1716       hash =
1717         _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_src[i],
1718                                        sizeof (b->texture_combine_alpha_src[i]));
1719       hash =
1720         _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_op[i],
1721                                        sizeof (b->texture_combine_alpha_op[i]));
1722     }
1723 
1724   state->hash = hash;
1725 }
1726 
1727 void
_cogl_pipeline_layer_hash_combine_constant_state(CoglPipelineLayer * authority,CoglPipelineLayer ** authorities,CoglPipelineHashState * state)1728 _cogl_pipeline_layer_hash_combine_constant_state (CoglPipelineLayer *authority,
1729                                                   CoglPipelineLayer **authorities,
1730                                                   CoglPipelineHashState *state)
1731 {
1732   CoglPipelineLayerBigState *b = authority->big_state;
1733   CoglBool need_hash = FALSE;
1734   int n_args;
1735   int i;
1736 
1737   /* XXX: If the user also asked to hash the ALPHA_FUNC_STATE then it
1738    * would be nice if we could combine the n_args loops in this
1739    * function and _cogl_pipeline_layer_hash_combine_state.
1740    */
1741 
1742   n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_rgb_func);
1743   for (i = 0; i < n_args; i++)
1744     {
1745       if (b->texture_combine_rgb_src[i] ==
1746           COGL_PIPELINE_COMBINE_SOURCE_CONSTANT)
1747         {
1748           /* XXX: should we be careful to only hash the alpha
1749            * component in the COGL_PIPELINE_COMBINE_OP_SRC_ALPHA case? */
1750           need_hash = TRUE;
1751           goto done;
1752         }
1753     }
1754 
1755   n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_alpha_func);
1756   for (i = 0; i < n_args; i++)
1757     {
1758       if (b->texture_combine_alpha_src[i] ==
1759           COGL_PIPELINE_COMBINE_SOURCE_CONSTANT)
1760         {
1761           /* XXX: should we be careful to only hash the alpha
1762            * component in the COGL_PIPELINE_COMBINE_OP_SRC_ALPHA case? */
1763           need_hash = TRUE;
1764           goto done;
1765         }
1766     }
1767 
1768 done:
1769   if (need_hash)
1770     {
1771       float *constant = b->texture_combine_constant;
1772       state->hash = _cogl_util_one_at_a_time_hash (state->hash, constant,
1773                                                    sizeof (float) * 4);
1774     }
1775 }
1776 
1777 void
_cogl_pipeline_layer_hash_user_matrix_state(CoglPipelineLayer * authority,CoglPipelineLayer ** authorities,CoglPipelineHashState * state)1778 _cogl_pipeline_layer_hash_user_matrix_state (CoglPipelineLayer *authority,
1779                                              CoglPipelineLayer **authorities,
1780                                              CoglPipelineHashState *state)
1781 {
1782   CoglPipelineLayerBigState *big_state = authority->big_state;
1783   state->hash = _cogl_util_one_at_a_time_hash (state->hash, &big_state->matrix,
1784                                                sizeof (float) * 16);
1785 }
1786 
1787 void
_cogl_pipeline_layer_hash_point_sprite_state(CoglPipelineLayer * authority,CoglPipelineLayer ** authorities,CoglPipelineHashState * state)1788 _cogl_pipeline_layer_hash_point_sprite_state (CoglPipelineLayer *authority,
1789                                               CoglPipelineLayer **authorities,
1790                                               CoglPipelineHashState *state)
1791 {
1792   CoglPipelineLayerBigState *big_state = authority->big_state;
1793   state->hash =
1794     _cogl_util_one_at_a_time_hash (state->hash, &big_state->point_sprite_coords,
1795                                    sizeof (big_state->point_sprite_coords));
1796 }
1797 
1798 void
_cogl_pipeline_layer_hash_vertex_snippets_state(CoglPipelineLayer * authority,CoglPipelineLayer ** authorities,CoglPipelineHashState * state)1799 _cogl_pipeline_layer_hash_vertex_snippets_state (CoglPipelineLayer *authority,
1800                                                  CoglPipelineLayer **authorities,
1801                                                  CoglPipelineHashState *state)
1802 {
1803   _cogl_pipeline_snippet_list_hash (&authority->big_state->vertex_snippets,
1804                                     &state->hash);
1805 }
1806 
1807 void
_cogl_pipeline_layer_hash_fragment_snippets_state(CoglPipelineLayer * authority,CoglPipelineLayer ** authorities,CoglPipelineHashState * state)1808 _cogl_pipeline_layer_hash_fragment_snippets_state (CoglPipelineLayer *authority,
1809                                                    CoglPipelineLayer **authorities,
1810                                                    CoglPipelineHashState *state)
1811 {
1812   _cogl_pipeline_snippet_list_hash (&authority->big_state->fragment_snippets,
1813                                     &state->hash);
1814 }
1815