~darkxst/ubuntu/raring/cogl/lp1163025

« back to all changes in this revision

Viewing changes to cogl/cogl-pipeline-layer.c

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2012-03-13 19:11:11 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20120313191111-3hgk529qkh9m6uk2
Tags: 1.9.8-0ubuntu1
* New upstream release (LP: #941617)
* Updated symbols & library name for soname update
* debian/control.in: Bump minimum glib to 2.28
* debian/patches/02_disable_armv5t_specific_optimization.patch: Disabled

Show diffs side-by-side

added added

removed removed

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