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