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