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