1 /*
2  * Cogl
3  *
4  * A Low Level GPU Graphics and Utilities API
5  *
6  * Copyright (C) 2008,2009,2010 Intel Corporation.
7  *
8  * Permission is hereby granted, free of charge, to any person
9  * obtaining a copy of this software and associated documentation
10  * files (the "Software"), to deal in the Software without
11  * restriction, including without limitation the rights to use, copy,
12  * modify, merge, publish, distribute, sublicense, and/or sell copies
13  * of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be
17  * included in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26  * SOFTWARE.
27  *
28  *
29  *
30  * Authors:
31  *   Robert Bragg <robert@linux.intel.com>
32  */
33 
34 #include "cogl-config.h"
35 
36 #include "cogl-context-private.h"
37 #include "cogl-pipeline-private.h"
38 #include "cogl-blend-string.h"
39 #include "cogl-util.h"
40 #include "cogl-snippet-private.h"
41 #include "cogl-texture-private.h"
42 #include "cogl-pipeline-layer-state-private.h"
43 
44 #include "string.h"
45 #if 0
46 #include "cogl-context-private.h"
47 #include "cogl-color-private.h"
48 
49 #endif
50 
51 /*
52  * XXX: consider special casing layer->unit_index so it's not a sparse
53  * property so instead we can assume it's valid for all layer
54  * instances.
55  * - We would need to initialize ->unit_index in
56  *   _cogl_pipeline_layer_copy ().
57  *
58  * XXX: If you use this API you should consider that the given layer
59  * might not be writeable and so a new derived layer will be allocated
60  * and modified instead. The layer modified will be returned so you
61  * can identify when this happens.
62  */
63 CoglPipelineLayer *
_cogl_pipeline_set_layer_unit(CoglPipeline * required_owner,CoglPipelineLayer * layer,int unit_index)64 _cogl_pipeline_set_layer_unit (CoglPipeline *required_owner,
65                                CoglPipelineLayer *layer,
66                                int unit_index)
67 {
68   CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_UNIT;
69   CoglPipelineLayer *authority =
70     _cogl_pipeline_layer_get_authority (layer, change);
71   CoglPipelineLayer *new;
72 
73   if (authority->unit_index == unit_index)
74     return layer;
75 
76   new =
77     _cogl_pipeline_layer_pre_change_notify (required_owner,
78                                             layer,
79                                             change);
80   if (new != layer)
81     layer = new;
82   else
83     {
84       /* If the layer we found is currently the authority on the state
85        * we are changing see if we can revert to one of our ancestors
86        * being the authority. */
87       if (layer == authority &&
88           _cogl_pipeline_layer_get_parent (authority) != NULL)
89         {
90           CoglPipelineLayer *parent =
91             _cogl_pipeline_layer_get_parent (authority);
92           CoglPipelineLayer *old_authority =
93             _cogl_pipeline_layer_get_authority (parent, change);
94 
95           if (old_authority->unit_index == unit_index)
96             {
97               layer->differences &= ~change;
98               return layer;
99             }
100         }
101     }
102 
103   layer->unit_index = unit_index;
104 
105   /* If we weren't previously the authority on this state then we need
106    * to extended our differences mask and so it's possible that some
107    * of our ancestry will now become redundant, so we aim to reparent
108    * ourselves if that's true... */
109   if (layer != authority)
110     {
111       layer->differences |= change;
112       _cogl_pipeline_layer_prune_redundant_ancestry (layer);
113     }
114 
115   return layer;
116 }
117 
118 CoglTexture *
_cogl_pipeline_layer_get_texture_real(CoglPipelineLayer * layer)119 _cogl_pipeline_layer_get_texture_real (CoglPipelineLayer *layer)
120 {
121   CoglPipelineLayer *authority =
122     _cogl_pipeline_layer_get_authority (layer,
123                                         COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA);
124 
125   return authority->texture;
126 }
127 
128 CoglTexture *
cogl_pipeline_get_layer_texture(CoglPipeline * pipeline,int layer_index)129 cogl_pipeline_get_layer_texture (CoglPipeline *pipeline,
130                                  int layer_index)
131 {
132   CoglPipelineLayer *layer =
133     _cogl_pipeline_get_layer (pipeline, layer_index);
134   return _cogl_pipeline_layer_get_texture (layer);
135 }
136 
137 static void
_cogl_pipeline_set_layer_texture_data(CoglPipeline * pipeline,int layer_index,CoglTexture * texture)138 _cogl_pipeline_set_layer_texture_data (CoglPipeline *pipeline,
139                                        int layer_index,
140                                        CoglTexture *texture)
141 {
142   CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA;
143   CoglPipelineLayer *layer;
144   CoglPipelineLayer *authority;
145   CoglPipelineLayer *new;
146 
147   /* Note: this will ensure that the layer exists, creating one if it
148    * doesn't already.
149    *
150    * Note: If the layer already existed it's possibly owned by another
151    * pipeline. If the layer is created then it will be owned by
152    * pipeline. */
153   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
154 
155   /* Now find the ancestor of the layer that is the authority for the
156    * state we want to change */
157   authority = _cogl_pipeline_layer_get_authority (layer, change);
158 
159   if (authority->texture == texture)
160     return;
161 
162   new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
163   if (new != layer)
164     layer = new;
165   else
166     {
167       /* If the original layer we found is currently the authority on
168        * the state we are changing see if we can revert to one of our
169        * ancestors being the authority. */
170       if (layer == authority &&
171           _cogl_pipeline_layer_get_parent (authority) != NULL)
172         {
173           CoglPipelineLayer *parent =
174             _cogl_pipeline_layer_get_parent (authority);
175           CoglPipelineLayer *old_authority =
176             _cogl_pipeline_layer_get_authority (parent, change);
177 
178           if (old_authority->texture == texture)
179             {
180               layer->differences &= ~change;
181 
182               if (layer->texture != NULL)
183                 cogl_object_unref (layer->texture);
184 
185               g_assert (layer->owner == pipeline);
186               if (layer->differences == 0)
187                 _cogl_pipeline_prune_empty_layer_difference (pipeline,
188                                                              layer);
189               goto changed;
190             }
191         }
192     }
193 
194   if (texture != NULL)
195     cogl_object_ref (texture);
196   if (layer == authority &&
197       layer->texture != NULL)
198     cogl_object_unref (layer->texture);
199   layer->texture = texture;
200 
201   /* If we weren't previously the authority on this state then we need
202    * to extended our differences mask and so it's possible that some
203    * of our ancestry will now become redundant, so we aim to reparent
204    * ourselves if that's true... */
205   if (layer != authority)
206     {
207       layer->differences |= change;
208       _cogl_pipeline_layer_prune_redundant_ancestry (layer);
209     }
210 
211 changed:
212 
213   pipeline->dirty_real_blend_enable = TRUE;
214 }
215 
216 void
cogl_pipeline_set_layer_texture(CoglPipeline * pipeline,int layer_index,CoglTexture * texture)217 cogl_pipeline_set_layer_texture (CoglPipeline *pipeline,
218                                  int layer_index,
219                                  CoglTexture *texture)
220 {
221   _cogl_pipeline_set_layer_texture_data (pipeline, layer_index, texture);
222 }
223 
224 void
cogl_pipeline_set_layer_null_texture(CoglPipeline * pipeline,int layer_index)225 cogl_pipeline_set_layer_null_texture (CoglPipeline *pipeline,
226                                       int layer_index)
227 {
228   _cogl_pipeline_set_layer_texture_data (pipeline, layer_index, NULL);
229 }
230 
231 static void
_cogl_pipeline_set_layer_sampler_state(CoglPipeline * pipeline,CoglPipelineLayer * layer,CoglPipelineLayer * authority,const CoglSamplerCacheEntry * state)232 _cogl_pipeline_set_layer_sampler_state (CoglPipeline *pipeline,
233                                         CoglPipelineLayer *layer,
234                                         CoglPipelineLayer *authority,
235                                         const CoglSamplerCacheEntry *state)
236 {
237   CoglPipelineLayer *new;
238   CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_SAMPLER;
239 
240   if (authority->sampler_cache_entry == state)
241     return;
242 
243   new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
244   if (new != layer)
245     layer = new;
246   else
247     {
248       /* If the original layer we found is currently the authority on
249        * the state we are changing see if we can revert to one of our
250        * ancestors being the authority. */
251       if (layer == authority &&
252           _cogl_pipeline_layer_get_parent (authority) != NULL)
253         {
254           CoglPipelineLayer *parent =
255             _cogl_pipeline_layer_get_parent (authority);
256           CoglPipelineLayer *old_authority =
257             _cogl_pipeline_layer_get_authority (parent, change);
258 
259           if (old_authority->sampler_cache_entry == state)
260             {
261               layer->differences &= ~change;
262 
263               g_assert (layer->owner == pipeline);
264               if (layer->differences == 0)
265                 _cogl_pipeline_prune_empty_layer_difference (pipeline,
266                                                              layer);
267               return;
268             }
269         }
270     }
271 
272   layer->sampler_cache_entry = state;
273 
274   /* If we weren't previously the authority on this state then we need
275    * to extended our differences mask and so it's possible that some
276    * of our ancestry will now become redundant, so we aim to reparent
277    * ourselves if that's true... */
278   if (layer != authority)
279     {
280       layer->differences |= change;
281       _cogl_pipeline_layer_prune_redundant_ancestry (layer);
282     }
283 }
284 
285 static CoglSamplerCacheWrapMode
public_to_internal_wrap_mode(CoglPipelineWrapMode mode)286 public_to_internal_wrap_mode (CoglPipelineWrapMode mode)
287 {
288   return (CoglSamplerCacheWrapMode)mode;
289 }
290 
291 static CoglPipelineWrapMode
internal_to_public_wrap_mode(CoglSamplerCacheWrapMode internal_mode)292 internal_to_public_wrap_mode (CoglSamplerCacheWrapMode internal_mode)
293 {
294   g_return_val_if_fail (internal_mode !=
295                         COGL_SAMPLER_CACHE_WRAP_MODE_CLAMP_TO_BORDER,
296                         COGL_PIPELINE_WRAP_MODE_AUTOMATIC);
297   return (CoglPipelineWrapMode)internal_mode;
298 }
299 
300 void
cogl_pipeline_set_layer_wrap_mode_s(CoglPipeline * pipeline,int layer_index,CoglPipelineWrapMode mode)301 cogl_pipeline_set_layer_wrap_mode_s (CoglPipeline *pipeline,
302                                      int layer_index,
303                                      CoglPipelineWrapMode mode)
304 {
305   CoglPipelineLayerState       change = COGL_PIPELINE_LAYER_STATE_SAMPLER;
306   CoglPipelineLayer           *layer;
307   CoglPipelineLayer           *authority;
308   CoglSamplerCacheWrapMode     internal_mode =
309     public_to_internal_wrap_mode (mode);
310   const CoglSamplerCacheEntry *sampler_state;
311 
312   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
313 
314   g_return_if_fail (cogl_is_pipeline (pipeline));
315 
316   /* Note: this will ensure that the layer exists, creating one if it
317    * doesn't already.
318    *
319    * Note: If the layer already existed it's possibly owned by another
320    * pipeline. If the layer is created then it will be owned by
321    * pipeline. */
322   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
323 
324   /* Now find the ancestor of the layer that is the authority for the
325    * state we want to change */
326   authority = _cogl_pipeline_layer_get_authority (layer, change);
327 
328   sampler_state =
329     _cogl_sampler_cache_update_wrap_modes (ctx->sampler_cache,
330                                            authority->sampler_cache_entry,
331                                            internal_mode,
332                                            authority->sampler_cache_entry->
333                                            wrap_mode_t);
334   _cogl_pipeline_set_layer_sampler_state (pipeline,
335                                           layer,
336                                           authority,
337                                           sampler_state);
338 }
339 
340 void
cogl_pipeline_set_layer_wrap_mode_t(CoglPipeline * pipeline,int layer_index,CoglPipelineWrapMode mode)341 cogl_pipeline_set_layer_wrap_mode_t (CoglPipeline *pipeline,
342                                      int layer_index,
343                                      CoglPipelineWrapMode mode)
344 {
345   CoglPipelineLayerState       change = COGL_PIPELINE_LAYER_STATE_SAMPLER;
346   CoglPipelineLayer           *layer;
347   CoglPipelineLayer           *authority;
348   CoglSamplerCacheWrapMode     internal_mode =
349     public_to_internal_wrap_mode (mode);
350   const CoglSamplerCacheEntry *sampler_state;
351 
352   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
353 
354   g_return_if_fail (cogl_is_pipeline (pipeline));
355 
356   /* Note: this will ensure that the layer exists, creating one if it
357    * doesn't already.
358    *
359    * Note: If the layer already existed it's possibly owned by another
360    * pipeline. If the layer is created then it will be owned by
361    * pipeline. */
362   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
363 
364   /* Now find the ancestor of the layer that is the authority for the
365    * state we want to change */
366   authority = _cogl_pipeline_layer_get_authority (layer, change);
367 
368   sampler_state =
369     _cogl_sampler_cache_update_wrap_modes (ctx->sampler_cache,
370                                            authority->sampler_cache_entry,
371                                            authority->sampler_cache_entry->
372                                            wrap_mode_s,
373                                            internal_mode);
374   _cogl_pipeline_set_layer_sampler_state (pipeline,
375                                           layer,
376                                           authority,
377                                           sampler_state);
378 }
379 
380 void
cogl_pipeline_set_layer_wrap_mode(CoglPipeline * pipeline,int layer_index,CoglPipelineWrapMode mode)381 cogl_pipeline_set_layer_wrap_mode (CoglPipeline *pipeline,
382                                    int layer_index,
383                                    CoglPipelineWrapMode mode)
384 {
385   CoglPipelineLayerState       change = COGL_PIPELINE_LAYER_STATE_SAMPLER;
386   CoglPipelineLayer           *layer;
387   CoglPipelineLayer           *authority;
388   CoglSamplerCacheWrapMode     internal_mode =
389     public_to_internal_wrap_mode (mode);
390   const CoglSamplerCacheEntry *sampler_state;
391 
392   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
393 
394   g_return_if_fail (cogl_is_pipeline (pipeline));
395 
396   /* Note: this will ensure that the layer exists, creating one if it
397    * doesn't already.
398    *
399    * Note: If the layer already existed it's possibly owned by another
400    * pipeline. If the layer is created then it will be owned by
401    * pipeline. */
402   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
403 
404   /* Now find the ancestor of the layer that is the authority for the
405    * state we want to change */
406   authority = _cogl_pipeline_layer_get_authority (layer, change);
407 
408   sampler_state =
409     _cogl_sampler_cache_update_wrap_modes (ctx->sampler_cache,
410                                            authority->sampler_cache_entry,
411                                            internal_mode,
412                                            internal_mode);
413   _cogl_pipeline_set_layer_sampler_state (pipeline,
414                                           layer,
415                                           authority,
416                                           sampler_state);
417 }
418 
419 /* FIXME: deprecate this API */
420 CoglPipelineWrapMode
_cogl_pipeline_layer_get_wrap_mode_s(CoglPipelineLayer * layer)421 _cogl_pipeline_layer_get_wrap_mode_s (CoglPipelineLayer *layer)
422 {
423   CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_SAMPLER;
424   CoglPipelineLayer     *authority;
425   const CoglSamplerCacheEntry *sampler_state;
426 
427   g_return_val_if_fail (_cogl_is_pipeline_layer (layer), FALSE);
428 
429   /* Now find the ancestor of the layer that is the authority for the
430    * state we want to change */
431   authority = _cogl_pipeline_layer_get_authority (layer, change);
432 
433   sampler_state = authority->sampler_cache_entry;
434   return internal_to_public_wrap_mode (sampler_state->wrap_mode_s);
435 }
436 
437 CoglPipelineWrapMode
cogl_pipeline_get_layer_wrap_mode_s(CoglPipeline * pipeline,int layer_index)438 cogl_pipeline_get_layer_wrap_mode_s (CoglPipeline *pipeline, int layer_index)
439 {
440   CoglPipelineLayer *layer;
441 
442   g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
443 
444   /* Note: this will ensure that the layer exists, creating one if it
445    * doesn't already.
446    *
447    * Note: If the layer already existed it's possibly owned by another
448    * pipeline. If the layer is created then it will be owned by
449    * pipeline. */
450   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
451   /* FIXME: we shouldn't ever construct a layer in a getter function */
452 
453   return _cogl_pipeline_layer_get_wrap_mode_s (layer);
454 }
455 
456 /* FIXME: deprecate this API */
457 CoglPipelineWrapMode
_cogl_pipeline_layer_get_wrap_mode_t(CoglPipelineLayer * layer)458 _cogl_pipeline_layer_get_wrap_mode_t (CoglPipelineLayer *layer)
459 {
460   CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_SAMPLER;
461   CoglPipelineLayer     *authority;
462   const CoglSamplerCacheEntry *sampler_state;
463 
464   g_return_val_if_fail (_cogl_is_pipeline_layer (layer), FALSE);
465 
466   /* Now find the ancestor of the layer that is the authority for the
467    * state we want to change */
468   authority = _cogl_pipeline_layer_get_authority (layer, change);
469 
470   sampler_state = authority->sampler_cache_entry;
471   return internal_to_public_wrap_mode (sampler_state->wrap_mode_t);
472 }
473 
474 CoglPipelineWrapMode
cogl_pipeline_get_layer_wrap_mode_t(CoglPipeline * pipeline,int layer_index)475 cogl_pipeline_get_layer_wrap_mode_t (CoglPipeline *pipeline, int layer_index)
476 {
477   CoglPipelineLayer *layer;
478 
479   g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
480 
481   /* Note: this will ensure that the layer exists, creating one if it
482    * doesn't already.
483    *
484    * Note: If the layer already existed it's possibly owned by another
485    * pipeline. If the layer is created then it will be owned by
486    * pipeline. */
487   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
488   /* FIXME: we shouldn't ever construct a layer in a getter function */
489 
490   return _cogl_pipeline_layer_get_wrap_mode_t (layer);
491 }
492 
493 void
_cogl_pipeline_layer_get_wrap_modes(CoglPipelineLayer * layer,CoglSamplerCacheWrapMode * wrap_mode_s,CoglSamplerCacheWrapMode * wrap_mode_t)494 _cogl_pipeline_layer_get_wrap_modes (CoglPipelineLayer *layer,
495                                      CoglSamplerCacheWrapMode *wrap_mode_s,
496                                      CoglSamplerCacheWrapMode *wrap_mode_t)
497 {
498   CoglPipelineLayer *authority =
499     _cogl_pipeline_layer_get_authority (layer,
500                                         COGL_PIPELINE_LAYER_STATE_SAMPLER);
501 
502   *wrap_mode_s = authority->sampler_cache_entry->wrap_mode_s;
503   *wrap_mode_t = authority->sampler_cache_entry->wrap_mode_t;
504 }
505 
506 gboolean
cogl_pipeline_set_layer_point_sprite_coords_enabled(CoglPipeline * pipeline,int layer_index,gboolean enable,GError ** error)507 cogl_pipeline_set_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
508                                                      int layer_index,
509                                                      gboolean enable,
510                                                      GError **error)
511 {
512   CoglPipelineLayerState       change =
513     COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS;
514   CoglPipelineLayer           *layer;
515   CoglPipelineLayer           *new;
516   CoglPipelineLayer           *authority;
517 
518   _COGL_GET_CONTEXT (ctx, FALSE);
519 
520   g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
521 
522   /* Note: this will ensure that the layer exists, creating one if it
523    * doesn't already.
524    *
525    * Note: If the layer already existed it's possibly owned by another
526    * pipeline. If the layer is created then it will be owned by
527    * pipeline. */
528   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
529 
530   /* Now find the ancestor of the layer that is the authority for the
531    * state we want to change */
532   authority = _cogl_pipeline_layer_get_authority (layer, change);
533 
534   if (authority->big_state->point_sprite_coords == enable)
535     return TRUE;
536 
537   new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
538   if (new != layer)
539     layer = new;
540   else
541     {
542       /* If the original layer we found is currently the authority on
543        * the state we are changing see if we can revert to one of our
544        * ancestors being the authority. */
545       if (layer == authority &&
546           _cogl_pipeline_layer_get_parent (authority) != NULL)
547         {
548           CoglPipelineLayer *parent =
549             _cogl_pipeline_layer_get_parent (authority);
550           CoglPipelineLayer *old_authority =
551             _cogl_pipeline_layer_get_authority (parent, change);
552 
553           if (old_authority->big_state->point_sprite_coords == enable)
554             {
555               layer->differences &= ~change;
556 
557               g_assert (layer->owner == pipeline);
558               if (layer->differences == 0)
559                 _cogl_pipeline_prune_empty_layer_difference (pipeline,
560                                                              layer);
561               return TRUE;
562             }
563         }
564     }
565 
566   layer->big_state->point_sprite_coords = enable;
567 
568   /* If we weren't previously the authority on this state then we need
569    * to extended our differences mask and so it's possible that some
570    * of our ancestry will now become redundant, so we aim to reparent
571    * ourselves if that's true... */
572   if (layer != authority)
573     {
574       layer->differences |= change;
575       _cogl_pipeline_layer_prune_redundant_ancestry (layer);
576     }
577 
578   return TRUE;
579 }
580 
581 gboolean
cogl_pipeline_get_layer_point_sprite_coords_enabled(CoglPipeline * pipeline,int layer_index)582 cogl_pipeline_get_layer_point_sprite_coords_enabled (CoglPipeline *pipeline,
583                                                      int layer_index)
584 {
585   CoglPipelineLayerState       change =
586     COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS;
587   CoglPipelineLayer *layer;
588   CoglPipelineLayer *authority;
589 
590   g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
591 
592   /* Note: this will ensure that the layer exists, creating one if it
593    * doesn't already.
594    *
595    * Note: If the layer already existed it's possibly owned by another
596    * pipeline. If the layer is created then it will be owned by
597    * pipeline. */
598   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
599   /* FIXME: we shouldn't ever construct a layer in a getter function */
600 
601   authority = _cogl_pipeline_layer_get_authority (layer, change);
602 
603   return authority->big_state->point_sprite_coords;
604 }
605 
606 static void
_cogl_pipeline_layer_add_vertex_snippet(CoglPipeline * pipeline,int layer_index,CoglSnippet * snippet)607 _cogl_pipeline_layer_add_vertex_snippet (CoglPipeline *pipeline,
608                                          int layer_index,
609                                          CoglSnippet *snippet)
610 {
611   CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS;
612   CoglPipelineLayer *layer, *authority;
613 
614   /* Note: this will ensure that the layer exists, creating one if it
615    * doesn't already.
616    *
617    * Note: If the layer already existed it's possibly owned by another
618    * pipeline. If the layer is created then it will be owned by
619    * pipeline. */
620   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
621 
622   /* Now find the ancestor of the layer that is the authority for the
623    * state we want to change */
624   authority = _cogl_pipeline_layer_get_authority (layer, change);
625 
626   layer = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
627 
628   _cogl_pipeline_snippet_list_add (&layer->big_state->vertex_snippets,
629                                    snippet);
630 
631   /* If we weren't previously the authority on this state then we need
632    * to extended our differences mask and so it's possible that some
633    * of our ancestry will now become redundant, so we aim to reparent
634    * ourselves if that's true... */
635   if (layer != authority)
636     {
637       layer->differences |= change;
638       _cogl_pipeline_layer_prune_redundant_ancestry (layer);
639     }
640 }
641 
642 static void
_cogl_pipeline_layer_add_fragment_snippet(CoglPipeline * pipeline,int layer_index,CoglSnippet * snippet)643 _cogl_pipeline_layer_add_fragment_snippet (CoglPipeline *pipeline,
644                                            int layer_index,
645                                            CoglSnippet *snippet)
646 {
647   CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS;
648   CoglPipelineLayer *layer, *authority;
649 
650   /* Note: this will ensure that the layer exists, creating one if it
651    * doesn't already.
652    *
653    * Note: If the layer already existed it's possibly owned by another
654    * pipeline. If the layer is created then it will be owned by
655    * pipeline. */
656   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
657 
658   /* Now find the ancestor of the layer that is the authority for the
659    * state we want to change */
660   authority = _cogl_pipeline_layer_get_authority (layer, change);
661 
662   layer = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
663 
664   _cogl_pipeline_snippet_list_add (&layer->big_state->fragment_snippets,
665                                    snippet);
666 
667   /* If we weren't previously the authority on this state then we need
668    * to extended our differences mask and so it's possible that some
669    * of our ancestry will now become redundant, so we aim to reparent
670    * ourselves if that's true... */
671   if (layer != authority)
672     {
673       layer->differences |= change;
674       _cogl_pipeline_layer_prune_redundant_ancestry (layer);
675     }
676 }
677 
678 void
cogl_pipeline_add_layer_snippet(CoglPipeline * pipeline,int layer_index,CoglSnippet * snippet)679 cogl_pipeline_add_layer_snippet (CoglPipeline *pipeline,
680                                  int layer_index,
681                                  CoglSnippet *snippet)
682 {
683   g_return_if_fail (cogl_is_pipeline (pipeline));
684   g_return_if_fail (cogl_is_snippet (snippet));
685   g_return_if_fail (snippet->hook >= COGL_SNIPPET_FIRST_LAYER_HOOK);
686 
687   if (snippet->hook < COGL_SNIPPET_FIRST_LAYER_FRAGMENT_HOOK)
688     _cogl_pipeline_layer_add_vertex_snippet (pipeline,
689                                              layer_index,
690                                              snippet);
691   else
692     _cogl_pipeline_layer_add_fragment_snippet (pipeline,
693                                                layer_index,
694                                                snippet);
695 }
696 
697 gboolean
_cogl_pipeline_layer_texture_data_equal(CoglPipelineLayer * authority0,CoglPipelineLayer * authority1,CoglPipelineEvalFlags flags)698 _cogl_pipeline_layer_texture_data_equal (CoglPipelineLayer *authority0,
699                                          CoglPipelineLayer *authority1,
700                                          CoglPipelineEvalFlags flags)
701 {
702   if (authority0->texture == NULL)
703     {
704       if (authority1->texture == NULL)
705         return TRUE;
706       else
707         return FALSE;
708     }
709   else if (authority1->texture == NULL)
710     return FALSE;
711   else
712     {
713       GLuint gl_handle0, gl_handle1;
714 
715       cogl_texture_get_gl_texture (authority0->texture, &gl_handle0, NULL);
716       cogl_texture_get_gl_texture (authority1->texture, &gl_handle1, NULL);
717 
718       return gl_handle0 == gl_handle1;
719     }
720 }
721 
722 gboolean
_cogl_pipeline_layer_combine_state_equal(CoglPipelineLayer * authority0,CoglPipelineLayer * authority1)723 _cogl_pipeline_layer_combine_state_equal (CoglPipelineLayer *authority0,
724                                           CoglPipelineLayer *authority1)
725 {
726   CoglPipelineLayerBigState *big_state0 = authority0->big_state;
727   CoglPipelineLayerBigState *big_state1 = authority1->big_state;
728   int n_args;
729   int i;
730 
731   if (big_state0->texture_combine_rgb_func !=
732       big_state1->texture_combine_rgb_func)
733     return FALSE;
734 
735   if (big_state0->texture_combine_alpha_func !=
736       big_state1->texture_combine_alpha_func)
737     return FALSE;
738 
739   n_args =
740     _cogl_get_n_args_for_combine_func (big_state0->texture_combine_rgb_func);
741   for (i = 0; i < n_args; i++)
742     {
743       if ((big_state0->texture_combine_rgb_src[i] !=
744            big_state1->texture_combine_rgb_src[i]) ||
745           (big_state0->texture_combine_rgb_op[i] !=
746            big_state1->texture_combine_rgb_op[i]))
747         return FALSE;
748     }
749 
750   n_args =
751     _cogl_get_n_args_for_combine_func (big_state0->texture_combine_alpha_func);
752   for (i = 0; i < n_args; i++)
753     {
754       if ((big_state0->texture_combine_alpha_src[i] !=
755            big_state1->texture_combine_alpha_src[i]) ||
756           (big_state0->texture_combine_alpha_op[i] !=
757            big_state1->texture_combine_alpha_op[i]))
758         return FALSE;
759     }
760 
761   return TRUE;
762 }
763 
764 gboolean
_cogl_pipeline_layer_combine_constant_equal(CoglPipelineLayer * authority0,CoglPipelineLayer * authority1)765 _cogl_pipeline_layer_combine_constant_equal (CoglPipelineLayer *authority0,
766                                              CoglPipelineLayer *authority1)
767 {
768   return memcmp (authority0->big_state->texture_combine_constant,
769                  authority1->big_state->texture_combine_constant,
770                  sizeof (float) * 4) == 0 ? TRUE : FALSE;
771 }
772 
773 gboolean
_cogl_pipeline_layer_sampler_equal(CoglPipelineLayer * authority0,CoglPipelineLayer * authority1)774 _cogl_pipeline_layer_sampler_equal (CoglPipelineLayer *authority0,
775                                     CoglPipelineLayer *authority1)
776 {
777   /* We compare the actual sampler objects rather than just the entry
778      pointers because two states with different values can lead to the
779      same state in GL terms when AUTOMATIC is used as a wrap mode */
780   return (authority0->sampler_cache_entry->sampler_object ==
781           authority1->sampler_cache_entry->sampler_object);
782 }
783 
784 gboolean
_cogl_pipeline_layer_user_matrix_equal(CoglPipelineLayer * authority0,CoglPipelineLayer * authority1)785 _cogl_pipeline_layer_user_matrix_equal (CoglPipelineLayer *authority0,
786                                         CoglPipelineLayer *authority1)
787 {
788   CoglPipelineLayerBigState *big_state0 = authority0->big_state;
789   CoglPipelineLayerBigState *big_state1 = authority1->big_state;
790 
791   if (!graphene_matrix_equal (&big_state0->matrix, &big_state1->matrix))
792     return FALSE;
793 
794   return TRUE;
795 }
796 
797 gboolean
_cogl_pipeline_layer_point_sprite_coords_equal(CoglPipelineLayer * authority0,CoglPipelineLayer * authority1)798 _cogl_pipeline_layer_point_sprite_coords_equal (CoglPipelineLayer *authority0,
799                                                 CoglPipelineLayer *authority1)
800 {
801   CoglPipelineLayerBigState *big_state0 = authority0->big_state;
802   CoglPipelineLayerBigState *big_state1 = authority1->big_state;
803 
804   return big_state0->point_sprite_coords == big_state1->point_sprite_coords;
805 }
806 
807 gboolean
_cogl_pipeline_layer_vertex_snippets_equal(CoglPipelineLayer * authority0,CoglPipelineLayer * authority1)808 _cogl_pipeline_layer_vertex_snippets_equal (CoglPipelineLayer *authority0,
809                                             CoglPipelineLayer *authority1)
810 {
811   return _cogl_pipeline_snippet_list_equal (&authority0->big_state->
812                                             vertex_snippets,
813                                             &authority1->big_state->
814                                             vertex_snippets);
815 }
816 
817 gboolean
_cogl_pipeline_layer_fragment_snippets_equal(CoglPipelineLayer * authority0,CoglPipelineLayer * authority1)818 _cogl_pipeline_layer_fragment_snippets_equal (CoglPipelineLayer *authority0,
819                                               CoglPipelineLayer *authority1)
820 {
821   return _cogl_pipeline_snippet_list_equal (&authority0->big_state->
822                                             fragment_snippets,
823                                             &authority1->big_state->
824                                             fragment_snippets);
825 }
826 
827 static void
setup_texture_combine_state(CoglBlendStringStatement * statement,CoglPipelineCombineFunc * texture_combine_func,CoglPipelineCombineSource * texture_combine_src,CoglPipelineCombineOp * texture_combine_op)828 setup_texture_combine_state (CoglBlendStringStatement *statement,
829                              CoglPipelineCombineFunc *texture_combine_func,
830                              CoglPipelineCombineSource *texture_combine_src,
831                              CoglPipelineCombineOp *texture_combine_op)
832 {
833   int i;
834 
835   switch (statement->function->type)
836     {
837     case COGL_BLEND_STRING_FUNCTION_REPLACE:
838       *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_REPLACE;
839       break;
840     case COGL_BLEND_STRING_FUNCTION_MODULATE:
841       *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_MODULATE;
842       break;
843     case COGL_BLEND_STRING_FUNCTION_ADD:
844       *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_ADD;
845       break;
846     case COGL_BLEND_STRING_FUNCTION_ADD_SIGNED:
847       *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED;
848       break;
849     case COGL_BLEND_STRING_FUNCTION_INTERPOLATE:
850       *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE;
851       break;
852     case COGL_BLEND_STRING_FUNCTION_SUBTRACT:
853       *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_SUBTRACT;
854       break;
855     case COGL_BLEND_STRING_FUNCTION_DOT3_RGB:
856       *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB;
857       break;
858     case COGL_BLEND_STRING_FUNCTION_DOT3_RGBA:
859       *texture_combine_func = COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA;
860       break;
861     }
862 
863   for (i = 0; i < statement->function->argc; i++)
864     {
865       CoglBlendStringArgument *arg = &statement->args[i];
866 
867       switch (arg->source.info->type)
868         {
869         case COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT:
870           texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_CONSTANT;
871           break;
872         case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE:
873           texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
874           break;
875         case COGL_BLEND_STRING_COLOR_SOURCE_TEXTURE_N:
876           texture_combine_src[i] =
877             COGL_PIPELINE_COMBINE_SOURCE_TEXTURE0 + arg->source.texture;
878           break;
879         case COGL_BLEND_STRING_COLOR_SOURCE_PRIMARY:
880           texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_PRIMARY_COLOR;
881           break;
882         case COGL_BLEND_STRING_COLOR_SOURCE_PREVIOUS:
883           texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_PREVIOUS;
884           break;
885         default:
886           g_warning ("Unexpected texture combine source");
887           texture_combine_src[i] = COGL_PIPELINE_COMBINE_SOURCE_TEXTURE;
888         }
889 
890       if (arg->source.mask == COGL_BLEND_STRING_CHANNEL_MASK_RGB)
891         {
892           if (statement->args[i].source.one_minus)
893             texture_combine_op[i] =
894               COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_COLOR;
895           else
896             texture_combine_op[i] = COGL_PIPELINE_COMBINE_OP_SRC_COLOR;
897         }
898       else
899         {
900           if (statement->args[i].source.one_minus)
901             texture_combine_op[i] =
902               COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA;
903           else
904             texture_combine_op[i] = COGL_PIPELINE_COMBINE_OP_SRC_ALPHA;
905         }
906     }
907 }
908 
909 gboolean
cogl_pipeline_set_layer_combine(CoglPipeline * pipeline,int layer_index,const char * combine_description,GError ** error)910 cogl_pipeline_set_layer_combine (CoglPipeline *pipeline,
911 				 int layer_index,
912 				 const char *combine_description,
913                                  GError **error)
914 {
915   CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_COMBINE;
916   CoglPipelineLayer *authority;
917   CoglPipelineLayer *layer;
918   CoglBlendStringStatement statements[2];
919   CoglBlendStringStatement split[2];
920   CoglBlendStringStatement *rgb;
921   CoglBlendStringStatement *a;
922   int count;
923 
924   g_return_val_if_fail (cogl_is_pipeline (pipeline), FALSE);
925 
926   /* Note: this will ensure that the layer exists, creating one if it
927    * doesn't already.
928    *
929    * Note: If the layer already existed it's possibly owned by another
930    * pipeline. If the layer is created then it will be owned by
931    * pipeline. */
932   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
933 
934   /* Now find the ancestor of the layer that is the authority for the
935    * state we want to change */
936   authority = _cogl_pipeline_layer_get_authority (layer, state);
937 
938   count =
939     _cogl_blend_string_compile (combine_description,
940                                 COGL_BLEND_STRING_CONTEXT_TEXTURE_COMBINE,
941                                 statements,
942                                 error);
943   if (!count)
944     return FALSE;
945 
946   if (statements[0].mask == COGL_BLEND_STRING_CHANNEL_MASK_RGBA)
947     {
948       _cogl_blend_string_split_rgba_statement (statements,
949                                                &split[0], &split[1]);
950       rgb = &split[0];
951       a = &split[1];
952     }
953   else
954     {
955       rgb = &statements[0];
956       a = &statements[1];
957     }
958 
959   /* FIXME: compare the new state with the current state! */
960 
961   /* possibly flush primitives referencing the current state... */
962   layer = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state);
963 
964   setup_texture_combine_state (rgb,
965                                &layer->big_state->texture_combine_rgb_func,
966                                layer->big_state->texture_combine_rgb_src,
967                                layer->big_state->texture_combine_rgb_op);
968 
969   setup_texture_combine_state (a,
970                                &layer->big_state->texture_combine_alpha_func,
971                                layer->big_state->texture_combine_alpha_src,
972                                layer->big_state->texture_combine_alpha_op);
973 
974   /* If the original layer we found is currently the authority on
975    * the state we are changing see if we can revert to one of our
976    * ancestors being the authority. */
977   if (layer == authority &&
978       _cogl_pipeline_layer_get_parent (authority) != NULL)
979     {
980       CoglPipelineLayer *parent = _cogl_pipeline_layer_get_parent (authority);
981       CoglPipelineLayer *old_authority =
982         _cogl_pipeline_layer_get_authority (parent, state);
983 
984       if (_cogl_pipeline_layer_combine_state_equal (authority,
985                                                     old_authority))
986         {
987           layer->differences &= ~state;
988 
989           g_assert (layer->owner == pipeline);
990           if (layer->differences == 0)
991             _cogl_pipeline_prune_empty_layer_difference (pipeline,
992                                                          layer);
993           goto changed;
994         }
995     }
996 
997   /* If we weren't previously the authority on this state then we need
998    * to extended our differences mask and so it's possible that some
999    * of our ancestry will now become redundant, so we aim to reparent
1000    * ourselves if that's true... */
1001   if (layer != authority)
1002     {
1003       layer->differences |= state;
1004       _cogl_pipeline_layer_prune_redundant_ancestry (layer);
1005     }
1006 
1007 changed:
1008 
1009   pipeline->dirty_real_blend_enable = TRUE;
1010   return TRUE;
1011 }
1012 
1013 void
cogl_pipeline_set_layer_combine_constant(CoglPipeline * pipeline,int layer_index,const CoglColor * constant_color)1014 cogl_pipeline_set_layer_combine_constant (CoglPipeline *pipeline,
1015 				          int layer_index,
1016                                           const CoglColor *constant_color)
1017 {
1018   CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT;
1019   CoglPipelineLayer     *layer;
1020   CoglPipelineLayer     *authority;
1021   CoglPipelineLayer     *new;
1022   float                  color_as_floats[4];
1023 
1024   g_return_if_fail (cogl_is_pipeline (pipeline));
1025 
1026   /* Note: this will ensure that the layer exists, creating one if it
1027    * doesn't already.
1028    *
1029    * Note: If the layer already existed it's possibly owned by another
1030    * pipeline. If the layer is created then it will be owned by
1031    * pipeline. */
1032   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
1033 
1034   /* Now find the ancestor of the layer that is the authority for the
1035    * state we want to change */
1036   authority = _cogl_pipeline_layer_get_authority (layer, state);
1037 
1038   color_as_floats[0] = cogl_color_get_red_float (constant_color);
1039   color_as_floats[1] = cogl_color_get_green_float (constant_color);
1040   color_as_floats[2] = cogl_color_get_blue_float (constant_color);
1041   color_as_floats[3] = cogl_color_get_alpha_float (constant_color);
1042 
1043   if (memcmp (authority->big_state->texture_combine_constant,
1044               color_as_floats, sizeof (float) * 4) == 0)
1045     return;
1046 
1047   new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state);
1048   if (new != layer)
1049     layer = new;
1050   else
1051     {
1052       /* If the original layer we found is currently the authority on
1053        * the state we are changing see if we can revert to one of our
1054        * ancestors being the authority. */
1055       if (layer == authority &&
1056           _cogl_pipeline_layer_get_parent (authority) != NULL)
1057         {
1058           CoglPipelineLayer *parent =
1059             _cogl_pipeline_layer_get_parent (authority);
1060           CoglPipelineLayer *old_authority =
1061             _cogl_pipeline_layer_get_authority (parent, state);
1062           CoglPipelineLayerBigState *old_big_state = old_authority->big_state;
1063 
1064           if (memcmp (old_big_state->texture_combine_constant,
1065                       color_as_floats, sizeof (float) * 4) == 0)
1066             {
1067               layer->differences &= ~state;
1068 
1069               g_assert (layer->owner == pipeline);
1070               if (layer->differences == 0)
1071                 _cogl_pipeline_prune_empty_layer_difference (pipeline,
1072                                                              layer);
1073               goto changed;
1074             }
1075         }
1076     }
1077 
1078   memcpy (layer->big_state->texture_combine_constant,
1079           color_as_floats,
1080           sizeof (color_as_floats));
1081 
1082   /* If we weren't previously the authority on this state then we need
1083    * to extended our differences mask and so it's possible that some
1084    * of our ancestry will now become redundant, so we aim to reparent
1085    * ourselves if that's true... */
1086   if (layer != authority)
1087     {
1088       layer->differences |= state;
1089       _cogl_pipeline_layer_prune_redundant_ancestry (layer);
1090     }
1091 
1092 changed:
1093 
1094   pipeline->dirty_real_blend_enable = TRUE;
1095 }
1096 
1097 void
_cogl_pipeline_get_layer_combine_constant(CoglPipeline * pipeline,int layer_index,float * constant)1098 _cogl_pipeline_get_layer_combine_constant (CoglPipeline *pipeline,
1099                                            int layer_index,
1100                                            float *constant)
1101 {
1102   CoglPipelineLayerState       change =
1103     COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT;
1104   CoglPipelineLayer *layer;
1105   CoglPipelineLayer *authority;
1106 
1107   g_return_if_fail (cogl_is_pipeline (pipeline));
1108 
1109   /* Note: this will ensure that the layer exists, creating one if it
1110    * doesn't already.
1111    *
1112    * Note: If the layer already existed it's possibly owned by another
1113    * pipeline. If the layer is created then it will be owned by
1114    * pipeline. */
1115   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
1116   /* FIXME: we shouldn't ever construct a layer in a getter function */
1117 
1118   authority = _cogl_pipeline_layer_get_authority (layer, change);
1119   memcpy (constant, authority->big_state->texture_combine_constant,
1120           sizeof (float) * 4);
1121 }
1122 
1123 /* We should probably make a public API version of this that has a
1124    matrix out-param. For an internal API it's good to be able to avoid
1125    copying the matrix */
1126 const graphene_matrix_t *
_cogl_pipeline_get_layer_matrix(CoglPipeline * pipeline,int layer_index)1127 _cogl_pipeline_get_layer_matrix (CoglPipeline *pipeline, int layer_index)
1128 {
1129   CoglPipelineLayerState       change =
1130     COGL_PIPELINE_LAYER_STATE_USER_MATRIX;
1131   CoglPipelineLayer *layer;
1132   CoglPipelineLayer *authority;
1133 
1134   g_return_val_if_fail (cogl_is_pipeline (pipeline), NULL);
1135 
1136   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
1137 
1138   authority = _cogl_pipeline_layer_get_authority (layer, change);
1139   return &authority->big_state->matrix;
1140 }
1141 
1142 void
cogl_pipeline_set_layer_matrix(CoglPipeline * pipeline,int layer_index,const graphene_matrix_t * matrix)1143 cogl_pipeline_set_layer_matrix (CoglPipeline *pipeline,
1144 				int layer_index,
1145                                 const graphene_matrix_t *matrix)
1146 {
1147   CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_USER_MATRIX;
1148   CoglPipelineLayer     *layer;
1149   CoglPipelineLayer     *authority;
1150   CoglPipelineLayer     *new;
1151 
1152   g_return_if_fail (cogl_is_pipeline (pipeline));
1153 
1154   /* Note: this will ensure that the layer exists, creating one if it
1155    * doesn't already.
1156    *
1157    * Note: If the layer already existed it's possibly owned by another
1158    * pipeline. If the layer is created then it will be owned by
1159    * pipeline. */
1160   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
1161 
1162   /* Now find the ancestor of the layer that is the authority for the
1163    * state we want to change */
1164   authority = _cogl_pipeline_layer_get_authority (layer, state);
1165 
1166   if (graphene_matrix_equal (matrix, &authority->big_state->matrix))
1167     return;
1168 
1169   new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, state);
1170   if (new != layer)
1171     layer = new;
1172   else
1173     {
1174       /* If the original layer we found is currently the authority on
1175        * the state we are changing see if we can revert to one of our
1176        * ancestors being the authority. */
1177       if (layer == authority &&
1178           _cogl_pipeline_layer_get_parent (authority) != NULL)
1179         {
1180           CoglPipelineLayer *parent =
1181             _cogl_pipeline_layer_get_parent (authority);
1182           CoglPipelineLayer *old_authority =
1183             _cogl_pipeline_layer_get_authority (parent, state);
1184 
1185           if (graphene_matrix_equal (matrix, &old_authority->big_state->matrix))
1186             {
1187               layer->differences &= ~state;
1188 
1189               g_assert (layer->owner == pipeline);
1190               if (layer->differences == 0)
1191                 _cogl_pipeline_prune_empty_layer_difference (pipeline,
1192                                                              layer);
1193               return;
1194             }
1195         }
1196     }
1197 
1198   layer->big_state->matrix = *matrix;
1199 
1200   /* If we weren't previously the authority on this state then we need
1201    * to extended our differences mask and so it's possible that some
1202    * of our ancestry will now become redundant, so we aim to reparent
1203    * ourselves if that's true... */
1204   if (layer != authority)
1205     {
1206       layer->differences |= state;
1207       _cogl_pipeline_layer_prune_redundant_ancestry (layer);
1208     }
1209 }
1210 
1211 CoglTexture *
_cogl_pipeline_layer_get_texture(CoglPipelineLayer * layer)1212 _cogl_pipeline_layer_get_texture (CoglPipelineLayer *layer)
1213 {
1214   g_return_val_if_fail (_cogl_is_pipeline_layer (layer), NULL);
1215 
1216   return _cogl_pipeline_layer_get_texture_real (layer);
1217 }
1218 
1219 gboolean
_cogl_pipeline_layer_has_user_matrix(CoglPipeline * pipeline,int layer_index)1220 _cogl_pipeline_layer_has_user_matrix (CoglPipeline *pipeline,
1221                                       int layer_index)
1222 {
1223   CoglPipelineLayer *layer;
1224   CoglPipelineLayer *authority;
1225 
1226   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
1227 
1228   authority =
1229     _cogl_pipeline_layer_get_authority (layer,
1230                                         COGL_PIPELINE_LAYER_STATE_USER_MATRIX);
1231 
1232   /* If the authority is the default pipeline then no, otherwise yes */
1233   return _cogl_pipeline_layer_get_parent (authority) ? TRUE : FALSE;
1234 }
1235 
1236 void
_cogl_pipeline_layer_get_filters(CoglPipelineLayer * layer,CoglPipelineFilter * min_filter,CoglPipelineFilter * mag_filter)1237 _cogl_pipeline_layer_get_filters (CoglPipelineLayer *layer,
1238                                   CoglPipelineFilter *min_filter,
1239                                   CoglPipelineFilter *mag_filter)
1240 {
1241   CoglPipelineLayer *authority =
1242     _cogl_pipeline_layer_get_authority (layer,
1243                                         COGL_PIPELINE_LAYER_STATE_SAMPLER);
1244 
1245   *min_filter = authority->sampler_cache_entry->min_filter;
1246   *mag_filter = authority->sampler_cache_entry->mag_filter;
1247 }
1248 
1249 void
_cogl_pipeline_get_layer_filters(CoglPipeline * pipeline,int layer_index,CoglPipelineFilter * min_filter,CoglPipelineFilter * mag_filter)1250 _cogl_pipeline_get_layer_filters (CoglPipeline *pipeline,
1251                                   int layer_index,
1252                                   CoglPipelineFilter *min_filter,
1253                                   CoglPipelineFilter *mag_filter)
1254 {
1255   CoglPipelineLayer *layer;
1256   CoglPipelineLayer *authority;
1257 
1258   g_return_if_fail (cogl_is_pipeline (pipeline));
1259 
1260   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
1261 
1262   authority =
1263     _cogl_pipeline_layer_get_authority (layer,
1264                                         COGL_PIPELINE_LAYER_STATE_SAMPLER);
1265 
1266   *min_filter = authority->sampler_cache_entry->min_filter;
1267   *mag_filter = authority->sampler_cache_entry->mag_filter;
1268 }
1269 
1270 CoglPipelineFilter
cogl_pipeline_get_layer_min_filter(CoglPipeline * pipeline,int layer_index)1271 cogl_pipeline_get_layer_min_filter (CoglPipeline *pipeline,
1272                                     int layer_index)
1273 {
1274   CoglPipelineFilter min_filter;
1275   CoglPipelineFilter mag_filter;
1276 
1277   _cogl_pipeline_get_layer_filters (pipeline, layer_index,
1278                                     &min_filter, &mag_filter);
1279   return min_filter;
1280 }
1281 
1282 CoglPipelineFilter
cogl_pipeline_get_layer_mag_filter(CoglPipeline * pipeline,int layer_index)1283 cogl_pipeline_get_layer_mag_filter (CoglPipeline *pipeline,
1284                                     int layer_index)
1285 {
1286   CoglPipelineFilter min_filter;
1287   CoglPipelineFilter mag_filter;
1288 
1289   _cogl_pipeline_get_layer_filters (pipeline, layer_index,
1290                                     &min_filter, &mag_filter);
1291   return mag_filter;
1292 }
1293 
1294 CoglPipelineFilter
_cogl_pipeline_layer_get_min_filter(CoglPipelineLayer * layer)1295 _cogl_pipeline_layer_get_min_filter (CoglPipelineLayer *layer)
1296 {
1297   CoglPipelineLayer *authority;
1298 
1299   g_return_val_if_fail (_cogl_is_pipeline_layer (layer), 0);
1300 
1301   authority =
1302     _cogl_pipeline_layer_get_authority (layer,
1303                                         COGL_PIPELINE_LAYER_STATE_SAMPLER);
1304 
1305   return authority->sampler_cache_entry->min_filter;
1306 }
1307 
1308 CoglPipelineFilter
_cogl_pipeline_layer_get_mag_filter(CoglPipelineLayer * layer)1309 _cogl_pipeline_layer_get_mag_filter (CoglPipelineLayer *layer)
1310 {
1311   CoglPipelineLayer *authority;
1312 
1313   g_return_val_if_fail (_cogl_is_pipeline_layer (layer), 0);
1314 
1315   authority =
1316     _cogl_pipeline_layer_get_authority (layer,
1317                                         COGL_PIPELINE_LAYER_STATE_SAMPLER);
1318 
1319   return authority->sampler_cache_entry->mag_filter;
1320 }
1321 
1322 void
cogl_pipeline_set_layer_filters(CoglPipeline * pipeline,int layer_index,CoglPipelineFilter min_filter,CoglPipelineFilter mag_filter)1323 cogl_pipeline_set_layer_filters (CoglPipeline      *pipeline,
1324                                  int                layer_index,
1325                                  CoglPipelineFilter min_filter,
1326                                  CoglPipelineFilter mag_filter)
1327 {
1328   CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_SAMPLER;
1329   CoglPipelineLayer *layer;
1330   CoglPipelineLayer *authority;
1331   const CoglSamplerCacheEntry *sampler_state;
1332 
1333   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1334 
1335   g_return_if_fail (cogl_is_pipeline (pipeline));
1336 
1337   g_return_if_fail (mag_filter == COGL_PIPELINE_FILTER_NEAREST ||
1338                     mag_filter == COGL_PIPELINE_FILTER_LINEAR);
1339 
1340   /* Note: this will ensure that the layer exists, creating one if it
1341    * doesn't already.
1342    *
1343    * Note: If the layer already existed it's possibly owned by another
1344    * pipeline. If the layer is created then it will be owned by
1345    * pipeline. */
1346   layer = _cogl_pipeline_get_layer (pipeline, layer_index);
1347 
1348   /* Now find the ancestor of the layer that is the authority for the
1349    * state we want to change */
1350   authority = _cogl_pipeline_layer_get_authority (layer, state);
1351 
1352   sampler_state =
1353     _cogl_sampler_cache_update_filters (ctx->sampler_cache,
1354                                         authority->sampler_cache_entry,
1355                                         min_filter,
1356                                         mag_filter);
1357   _cogl_pipeline_set_layer_sampler_state (pipeline,
1358                                           layer,
1359                                           authority,
1360                                           sampler_state);
1361 }
1362 
1363 void
cogl_pipeline_set_layer_max_mipmap_level(CoglPipeline * pipeline,int layer,int max_level)1364 cogl_pipeline_set_layer_max_mipmap_level (CoglPipeline *pipeline,
1365                                           int           layer,
1366                                           int           max_level)
1367 {
1368   CoglTexture *texture = cogl_pipeline_get_layer_texture (pipeline, layer);
1369 
1370   if (texture != NULL)
1371     cogl_texture_set_max_level (texture, max_level);
1372 }
1373 
1374 const CoglSamplerCacheEntry *
_cogl_pipeline_layer_get_sampler_state(CoglPipelineLayer * layer)1375 _cogl_pipeline_layer_get_sampler_state (CoglPipelineLayer *layer)
1376 {
1377   CoglPipelineLayer *authority;
1378 
1379   authority =
1380     _cogl_pipeline_layer_get_authority (layer,
1381                                         COGL_PIPELINE_LAYER_STATE_SAMPLER);
1382 
1383   return authority->sampler_cache_entry;
1384 }
1385 
1386 void
_cogl_pipeline_layer_hash_unit_state(CoglPipelineLayer * authority,CoglPipelineLayer ** authorities,CoglPipelineHashState * state)1387 _cogl_pipeline_layer_hash_unit_state (CoglPipelineLayer *authority,
1388                                       CoglPipelineLayer **authorities,
1389                                       CoglPipelineHashState *state)
1390 {
1391   int unit = authority->unit_index;
1392   state->hash =
1393     _cogl_util_one_at_a_time_hash (state->hash, &unit, sizeof (unit));
1394 }
1395 
1396 void
_cogl_pipeline_layer_hash_texture_data_state(CoglPipelineLayer * authority,CoglPipelineLayer ** authorities,CoglPipelineHashState * state)1397 _cogl_pipeline_layer_hash_texture_data_state (CoglPipelineLayer *authority,
1398                                               CoglPipelineLayer **authorities,
1399                                               CoglPipelineHashState *state)
1400 {
1401   GLuint gl_handle;
1402 
1403   cogl_texture_get_gl_texture (authority->texture, &gl_handle, NULL);
1404 
1405   state->hash =
1406     _cogl_util_one_at_a_time_hash (state->hash, &gl_handle, sizeof (gl_handle));
1407 }
1408 
1409 void
_cogl_pipeline_layer_hash_sampler_state(CoglPipelineLayer * authority,CoglPipelineLayer ** authorities,CoglPipelineHashState * state)1410 _cogl_pipeline_layer_hash_sampler_state (CoglPipelineLayer *authority,
1411                                          CoglPipelineLayer **authorities,
1412                                          CoglPipelineHashState *state)
1413 {
1414   state->hash =
1415     _cogl_util_one_at_a_time_hash (state->hash,
1416                                    &authority->sampler_cache_entry,
1417                                    sizeof (authority->sampler_cache_entry));
1418 }
1419 
1420 void
_cogl_pipeline_layer_hash_combine_state(CoglPipelineLayer * authority,CoglPipelineLayer ** authorities,CoglPipelineHashState * state)1421 _cogl_pipeline_layer_hash_combine_state (CoglPipelineLayer *authority,
1422                                          CoglPipelineLayer **authorities,
1423                                          CoglPipelineHashState *state)
1424 {
1425   unsigned int hash = state->hash;
1426   CoglPipelineLayerBigState *b = authority->big_state;
1427   int n_args;
1428   int i;
1429 
1430   hash = _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_func,
1431                                         sizeof (b->texture_combine_rgb_func));
1432   n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_rgb_func);
1433   for (i = 0; i < n_args; i++)
1434     {
1435       hash =
1436         _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_src[i],
1437                                        sizeof (b->texture_combine_rgb_src[i]));
1438       hash =
1439         _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_rgb_op[i],
1440                                        sizeof (b->texture_combine_rgb_op[i]));
1441     }
1442 
1443   hash = _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_func,
1444                                         sizeof (b->texture_combine_alpha_func));
1445   n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_alpha_func);
1446   for (i = 0; i < n_args; i++)
1447     {
1448       hash =
1449         _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_src[i],
1450                                        sizeof (b->texture_combine_alpha_src[i]));
1451       hash =
1452         _cogl_util_one_at_a_time_hash (hash, &b->texture_combine_alpha_op[i],
1453                                        sizeof (b->texture_combine_alpha_op[i]));
1454     }
1455 
1456   state->hash = hash;
1457 }
1458 
1459 void
_cogl_pipeline_layer_hash_combine_constant_state(CoglPipelineLayer * authority,CoglPipelineLayer ** authorities,CoglPipelineHashState * state)1460 _cogl_pipeline_layer_hash_combine_constant_state (CoglPipelineLayer *authority,
1461                                                   CoglPipelineLayer **authorities,
1462                                                   CoglPipelineHashState *state)
1463 {
1464   CoglPipelineLayerBigState *b = authority->big_state;
1465   gboolean need_hash = FALSE;
1466   int n_args;
1467   int i;
1468 
1469   /* XXX: If the user also asked to hash the ALPHA_FUNC_STATE then it
1470    * would be nice if we could combine the n_args loops in this
1471    * function and _cogl_pipeline_layer_hash_combine_state.
1472    */
1473 
1474   n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_rgb_func);
1475   for (i = 0; i < n_args; i++)
1476     {
1477       if (b->texture_combine_rgb_src[i] ==
1478           COGL_PIPELINE_COMBINE_SOURCE_CONSTANT)
1479         {
1480           /* XXX: should we be careful to only hash the alpha
1481            * component in the COGL_PIPELINE_COMBINE_OP_SRC_ALPHA case? */
1482           need_hash = TRUE;
1483           goto done;
1484         }
1485     }
1486 
1487   n_args = _cogl_get_n_args_for_combine_func (b->texture_combine_alpha_func);
1488   for (i = 0; i < n_args; i++)
1489     {
1490       if (b->texture_combine_alpha_src[i] ==
1491           COGL_PIPELINE_COMBINE_SOURCE_CONSTANT)
1492         {
1493           /* XXX: should we be careful to only hash the alpha
1494            * component in the COGL_PIPELINE_COMBINE_OP_SRC_ALPHA case? */
1495           need_hash = TRUE;
1496           goto done;
1497         }
1498     }
1499 
1500 done:
1501   if (need_hash)
1502     {
1503       float *constant = b->texture_combine_constant;
1504       state->hash = _cogl_util_one_at_a_time_hash (state->hash, constant,
1505                                                    sizeof (float) * 4);
1506     }
1507 }
1508 
1509 void
_cogl_pipeline_layer_hash_user_matrix_state(CoglPipelineLayer * authority,CoglPipelineLayer ** authorities,CoglPipelineHashState * state)1510 _cogl_pipeline_layer_hash_user_matrix_state (CoglPipelineLayer *authority,
1511                                              CoglPipelineLayer **authorities,
1512                                              CoglPipelineHashState *state)
1513 {
1514   CoglPipelineLayerBigState *big_state = authority->big_state;
1515   state->hash = _cogl_util_one_at_a_time_hash (state->hash, &big_state->matrix,
1516                                                sizeof (float) * 16);
1517 }
1518 
1519 void
_cogl_pipeline_layer_hash_point_sprite_state(CoglPipelineLayer * authority,CoglPipelineLayer ** authorities,CoglPipelineHashState * state)1520 _cogl_pipeline_layer_hash_point_sprite_state (CoglPipelineLayer *authority,
1521                                               CoglPipelineLayer **authorities,
1522                                               CoglPipelineHashState *state)
1523 {
1524   CoglPipelineLayerBigState *big_state = authority->big_state;
1525   state->hash =
1526     _cogl_util_one_at_a_time_hash (state->hash, &big_state->point_sprite_coords,
1527                                    sizeof (big_state->point_sprite_coords));
1528 }
1529 
1530 void
_cogl_pipeline_layer_hash_vertex_snippets_state(CoglPipelineLayer * authority,CoglPipelineLayer ** authorities,CoglPipelineHashState * state)1531 _cogl_pipeline_layer_hash_vertex_snippets_state (CoglPipelineLayer *authority,
1532                                                  CoglPipelineLayer **authorities,
1533                                                  CoglPipelineHashState *state)
1534 {
1535   _cogl_pipeline_snippet_list_hash (&authority->big_state->vertex_snippets,
1536                                     &state->hash);
1537 }
1538 
1539 void
_cogl_pipeline_layer_hash_fragment_snippets_state(CoglPipelineLayer * authority,CoglPipelineLayer ** authorities,CoglPipelineHashState * state)1540 _cogl_pipeline_layer_hash_fragment_snippets_state (CoglPipelineLayer *authority,
1541                                                    CoglPipelineLayer **authorities,
1542                                                    CoglPipelineHashState *state)
1543 {
1544   _cogl_pipeline_snippet_list_hash (&authority->big_state->fragment_snippets,
1545                                     &state->hash);
1546 }
1547