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