~noskcaj/ubuntu/trusty/cogl/1.16.2

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha, Jeremy Bicha, Rico Tzschichholz
  • Date: 2013-02-26 16:43:25 UTC
  • mfrom: (1.1.10)
  • Revision ID: package-import@ubuntu.com-20130226164325-t4z9rylpa20v0p6q
Tags: 1.13.4-0ubuntu1
[ Jeremy Bicha ]
* New upstream release
  - soname bump
* debian/control.in:
  - Bump minimum glib to 2.32
  - Drop obsolete breaks/replaces
  - Bump libclutter-1.0-dev breaks for soname transition
* debian/libcogl-dev.install:
  - Add some missing files

[ Rico Tzschichholz ]
* debian/control.in:
  - Build-depend on libxrandr-dev

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-debug.h"
33
 
#include "cogl-pipeline-opengl-private.h"
34
 
#include "cogl-pipeline-private.h"
35
 
#include "cogl-context-private.h"
36
 
#include "cogl-texture-private.h"
37
 
#include "cogl-framebuffer-private.h"
38
 
#include "cogl-offscreen.h"
39
 
 
40
 
/* This is needed to set the color attribute on GLES2 */
41
 
#ifdef HAVE_COGL_GLES2
42
 
#include "cogl-pipeline-progend-glsl-private.h"
43
 
#endif
44
 
 
45
 
#include <glib.h>
46
 
#include <string.h>
47
 
 
48
 
/*
49
 
 * GL/GLES compatability defines for pipeline thingies:
50
 
 */
51
 
 
52
 
/* These aren't defined in the GLES headers */
53
 
#ifndef GL_POINT_SPRITE
54
 
#define GL_POINT_SPRITE 0x8861
55
 
#endif
56
 
#ifndef GL_COORD_REPLACE
57
 
#define GL_COORD_REPLACE 0x8862
58
 
#endif
59
 
#ifndef GL_CLAMP_TO_BORDER
60
 
#define GL_CLAMP_TO_BORDER 0x812d
61
 
#endif
62
 
 
63
 
 
64
 
static void
65
 
texture_unit_init (CoglTextureUnit *unit, int index_)
66
 
{
67
 
  unit->index = index_;
68
 
  unit->enabled_gl_target = 0;
69
 
  unit->gl_texture = 0;
70
 
  unit->gl_target = 0;
71
 
  unit->is_foreign = FALSE;
72
 
  unit->dirty_gl_texture = FALSE;
73
 
  unit->matrix_stack = _cogl_matrix_stack_new ();
74
 
 
75
 
  unit->layer = NULL;
76
 
  unit->layer_changes_since_flush = 0;
77
 
  unit->texture_storage_changed = FALSE;
78
 
}
79
 
 
80
 
static void
81
 
texture_unit_free (CoglTextureUnit *unit)
82
 
{
83
 
  if (unit->layer)
84
 
    cogl_object_unref (unit->layer);
85
 
  cogl_object_unref (unit->matrix_stack);
86
 
}
87
 
 
88
 
CoglTextureUnit *
89
 
_cogl_get_texture_unit (int index_)
90
 
{
91
 
  _COGL_GET_CONTEXT (ctx, NULL);
92
 
 
93
 
  if (ctx->texture_units->len < (index_ + 1))
94
 
    {
95
 
      int i;
96
 
      int prev_len = ctx->texture_units->len;
97
 
      ctx->texture_units = g_array_set_size (ctx->texture_units, index_ + 1);
98
 
      for (i = prev_len; i <= index_; i++)
99
 
        {
100
 
          CoglTextureUnit *unit =
101
 
            &g_array_index (ctx->texture_units, CoglTextureUnit, i);
102
 
 
103
 
          texture_unit_init (unit, i);
104
 
        }
105
 
    }
106
 
 
107
 
  return &g_array_index (ctx->texture_units, CoglTextureUnit, index_);
108
 
}
109
 
 
110
 
void
111
 
_cogl_destroy_texture_units (void)
112
 
{
113
 
  int i;
114
 
 
115
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
116
 
 
117
 
  for (i = 0; i < ctx->texture_units->len; i++)
118
 
    {
119
 
      CoglTextureUnit *unit =
120
 
        &g_array_index (ctx->texture_units, CoglTextureUnit, i);
121
 
      texture_unit_free (unit);
122
 
    }
123
 
  g_array_free (ctx->texture_units, TRUE);
124
 
}
125
 
 
126
 
void
127
 
_cogl_set_active_texture_unit (int unit_index)
128
 
{
129
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
130
 
 
131
 
  if (ctx->active_texture_unit != unit_index)
132
 
    {
133
 
      GE (ctx, glActiveTexture (GL_TEXTURE0 + unit_index));
134
 
      ctx->active_texture_unit = unit_index;
135
 
    }
136
 
}
137
 
 
138
 
/* Note: _cogl_bind_gl_texture_transient conceptually has slightly
139
 
 * different semantics to OpenGL's glBindTexture because Cogl never
140
 
 * cares about tracking multiple textures bound to different targets
141
 
 * on the same texture unit.
142
 
 *
143
 
 * glBindTexture lets you bind multiple textures to a single texture
144
 
 * unit if they are bound to different targets. So it does something
145
 
 * like:
146
 
 *   unit->current_texture[target] = texture;
147
 
 *
148
 
 * Cogl only lets you associate one texture with the currently active
149
 
 * texture unit, so the target is basically a redundant parameter
150
 
 * that's implicitly set on that texture.
151
 
 *
152
 
 * Technically this is just a thin wrapper around glBindTexture so
153
 
 * actually it does have the GL semantics but it seems worth
154
 
 * mentioning the conceptual difference in case anyone wonders why we
155
 
 * don't associate the gl_texture with a gl_target in the
156
 
 * CoglTextureUnit.
157
 
 */
158
 
void
159
 
_cogl_bind_gl_texture_transient (GLenum gl_target,
160
 
                                 GLuint gl_texture,
161
 
                                 CoglBool is_foreign)
162
 
{
163
 
  CoglTextureUnit *unit;
164
 
 
165
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
166
 
 
167
 
  /* We choose to always make texture unit 1 active for transient
168
 
   * binds so that in the common case where multitexturing isn't used
169
 
   * we can simply ignore the state of this texture unit. Notably we
170
 
   * didn't use a large texture unit (.e.g. (GL_MAX_TEXTURE_UNITS - 1)
171
 
   * in case the driver doesn't have a sparse data structure for
172
 
   * texture units.
173
 
   */
174
 
  _cogl_set_active_texture_unit (1);
175
 
  unit = _cogl_get_texture_unit (1);
176
 
 
177
 
  /* NB: If we have previously bound a foreign texture to this texture
178
 
   * unit we don't know if that texture has since been deleted and we
179
 
   * are seeing the texture name recycled */
180
 
  if (unit->gl_texture == gl_texture &&
181
 
      !unit->dirty_gl_texture &&
182
 
      !unit->is_foreign)
183
 
    return;
184
 
 
185
 
  GE (ctx, glBindTexture (gl_target, gl_texture));
186
 
 
187
 
  unit->dirty_gl_texture = TRUE;
188
 
  unit->is_foreign = is_foreign;
189
 
}
190
 
 
191
 
void
192
 
_cogl_delete_gl_texture (GLuint gl_texture)
193
 
{
194
 
  int i;
195
 
 
196
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
197
 
 
198
 
  for (i = 0; i < ctx->texture_units->len; i++)
199
 
    {
200
 
      CoglTextureUnit *unit =
201
 
        &g_array_index (ctx->texture_units, CoglTextureUnit, i);
202
 
 
203
 
      if (unit->gl_texture == gl_texture)
204
 
        {
205
 
          unit->gl_texture = 0;
206
 
          unit->gl_target = 0;
207
 
          unit->dirty_gl_texture = FALSE;
208
 
        }
209
 
    }
210
 
 
211
 
  GE (ctx, glDeleteTextures (1, &gl_texture));
212
 
}
213
 
 
214
 
/* Whenever the underlying GL texture storage of a CoglTexture is
215
 
 * changed (e.g. due to migration out of a texture atlas) then we are
216
 
 * notified. This lets us ensure that we reflush that texture's state
217
 
 * if it is reused again with the same texture unit.
218
 
 */
219
 
void
220
 
_cogl_pipeline_texture_storage_change_notify (CoglTexture *texture)
221
 
{
222
 
  int i;
223
 
 
224
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
225
 
 
226
 
  for (i = 0; i < ctx->texture_units->len; i++)
227
 
    {
228
 
      CoglTextureUnit *unit =
229
 
        &g_array_index (ctx->texture_units, CoglTextureUnit, i);
230
 
 
231
 
      if (unit->layer &&
232
 
          _cogl_pipeline_layer_get_texture (unit->layer) == texture)
233
 
        unit->texture_storage_changed = TRUE;
234
 
 
235
 
      /* NB: the texture may be bound to multiple texture units so
236
 
       * we continue to check the rest */
237
 
    }
238
 
}
239
 
 
240
 
static void
241
 
set_glsl_program (GLuint gl_program)
242
 
{
243
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
244
 
 
245
 
  if (ctx->current_gl_program != gl_program)
246
 
    {
247
 
      GLenum gl_error;
248
 
 
249
 
      while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
250
 
        ;
251
 
      ctx->glUseProgram (gl_program);
252
 
      if (ctx->glGetError () == GL_NO_ERROR)
253
 
        ctx->current_gl_program = gl_program;
254
 
      else
255
 
        {
256
 
          GE( ctx, glUseProgram (0) );
257
 
          ctx->current_gl_program = 0;
258
 
        }
259
 
    }
260
 
}
261
 
 
262
 
void
263
 
_cogl_use_fragment_program (GLuint gl_program, CoglPipelineProgramType type)
264
 
{
265
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
266
 
 
267
 
  /* If we're changing program type... */
268
 
  if (type != ctx->current_fragment_program_type)
269
 
    {
270
 
      /* ... disable the old type */
271
 
      switch (ctx->current_fragment_program_type)
272
 
        {
273
 
        case COGL_PIPELINE_PROGRAM_TYPE_GLSL:
274
 
          /* If the program contains a vertex shader then we shouldn't
275
 
             disable it */
276
 
          if (ctx->current_vertex_program_type !=
277
 
              COGL_PIPELINE_PROGRAM_TYPE_GLSL)
278
 
            set_glsl_program (0);
279
 
          break;
280
 
 
281
 
        case COGL_PIPELINE_PROGRAM_TYPE_ARBFP:
282
 
#ifdef HAVE_COGL_GL
283
 
          GE( ctx, glDisable (GL_FRAGMENT_PROGRAM_ARB) );
284
 
#endif
285
 
          break;
286
 
 
287
 
        case COGL_PIPELINE_PROGRAM_TYPE_FIXED:
288
 
          /* don't need to to anything */
289
 
          break;
290
 
        }
291
 
 
292
 
      /* ... and enable the new type */
293
 
      switch (type)
294
 
        {
295
 
        case COGL_PIPELINE_PROGRAM_TYPE_ARBFP:
296
 
#ifdef HAVE_COGL_GL
297
 
          GE( ctx, glEnable (GL_FRAGMENT_PROGRAM_ARB) );
298
 
#endif
299
 
          break;
300
 
 
301
 
        case COGL_PIPELINE_PROGRAM_TYPE_GLSL:
302
 
        case COGL_PIPELINE_PROGRAM_TYPE_FIXED:
303
 
          /* don't need to to anything */
304
 
          break;
305
 
        }
306
 
    }
307
 
 
308
 
  if (type == COGL_PIPELINE_PROGRAM_TYPE_GLSL)
309
 
    {
310
 
#ifdef COGL_PIPELINE_FRAGEND_GLSL
311
 
      set_glsl_program (gl_program);
312
 
 
313
 
#else
314
 
 
315
 
      g_warning ("Unexpected use of GLSL fragend!");
316
 
 
317
 
#endif /* COGL_PIPELINE_FRAGEND_GLSL */
318
 
    }
319
 
#ifndef COGL_PIPELINE_FRAGEND_ARBFP
320
 
  else if (type == COGL_PIPELINE_PROGRAM_TYPE_ARBFP)
321
 
    g_warning ("Unexpected use of ARBFP fragend!");
322
 
#endif /* COGL_PIPELINE_FRAGEND_ARBFP */
323
 
 
324
 
  ctx->current_fragment_program_type = type;
325
 
}
326
 
 
327
 
void
328
 
_cogl_use_vertex_program (GLuint gl_program, CoglPipelineProgramType type)
329
 
{
330
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
331
 
 
332
 
  /* If we're changing program type... */
333
 
  if (type != ctx->current_vertex_program_type)
334
 
    {
335
 
      /* ... disable the old type */
336
 
      switch (ctx->current_vertex_program_type)
337
 
        {
338
 
        case COGL_PIPELINE_PROGRAM_TYPE_GLSL:
339
 
          /* If the program contains a fragment shader then we shouldn't
340
 
             disable it */
341
 
          if (ctx->current_fragment_program_type !=
342
 
              COGL_PIPELINE_PROGRAM_TYPE_GLSL)
343
 
            set_glsl_program (0);
344
 
          break;
345
 
 
346
 
        case COGL_PIPELINE_PROGRAM_TYPE_ARBFP:
347
 
          /* It doesn't make sense to enable ARBfp for the vertex program */
348
 
          g_assert_not_reached ();
349
 
          break;
350
 
 
351
 
        case COGL_PIPELINE_PROGRAM_TYPE_FIXED:
352
 
          /* don't need to to anything */
353
 
          break;
354
 
        }
355
 
 
356
 
      /* ... and enable the new type */
357
 
      switch (type)
358
 
        {
359
 
        case COGL_PIPELINE_PROGRAM_TYPE_ARBFP:
360
 
          /* It doesn't make sense to enable ARBfp for the vertex program */
361
 
          g_assert_not_reached ();
362
 
          break;
363
 
 
364
 
        case COGL_PIPELINE_PROGRAM_TYPE_GLSL:
365
 
        case COGL_PIPELINE_PROGRAM_TYPE_FIXED:
366
 
          /* don't need to to anything */
367
 
          break;
368
 
        }
369
 
    }
370
 
 
371
 
  if (type == COGL_PIPELINE_PROGRAM_TYPE_GLSL)
372
 
    {
373
 
#ifdef COGL_PIPELINE_VERTEND_GLSL
374
 
      set_glsl_program (gl_program);
375
 
 
376
 
#else
377
 
 
378
 
      g_warning ("Unexpected use of GLSL vertend!");
379
 
 
380
 
#endif /* COGL_PIPELINE_VERTEND_GLSL */
381
 
    }
382
 
#ifndef COGL_PIPELINE_VERTEND_ARBFP
383
 
  else if (type == COGL_PIPELINE_PROGRAM_TYPE_ARBFP)
384
 
    g_warning ("Unexpected use of ARBFP vertend!");
385
 
#endif /* COGL_PIPELINE_VERTEND_ARBFP */
386
 
 
387
 
  ctx->current_vertex_program_type = type;
388
 
}
389
 
 
390
 
#if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL)
391
 
 
392
 
static CoglBool
393
 
blend_factor_uses_constant (GLenum blend_factor)
394
 
{
395
 
  return (blend_factor == GL_CONSTANT_COLOR ||
396
 
          blend_factor == GL_ONE_MINUS_CONSTANT_COLOR ||
397
 
          blend_factor == GL_CONSTANT_ALPHA ||
398
 
          blend_factor == GL_ONE_MINUS_CONSTANT_ALPHA);
399
 
}
400
 
 
401
 
#endif
402
 
 
403
 
static void
404
 
flush_depth_state (CoglContext *ctx,
405
 
                   CoglDepthState *depth_state)
406
 
{
407
 
  if (ctx->depth_test_enabled_cache != depth_state->test_enabled)
408
 
    {
409
 
      if (depth_state->test_enabled == TRUE)
410
 
        GE (ctx, glEnable (GL_DEPTH_TEST));
411
 
      else
412
 
        GE (ctx, glDisable (GL_DEPTH_TEST));
413
 
      ctx->depth_test_enabled_cache = depth_state->test_enabled;
414
 
    }
415
 
 
416
 
  if (ctx->depth_test_function_cache != depth_state->test_function &&
417
 
      depth_state->test_enabled == TRUE)
418
 
    {
419
 
      GE (ctx, glDepthFunc (depth_state->test_function));
420
 
      ctx->depth_test_function_cache = depth_state->test_function;
421
 
    }
422
 
 
423
 
  if (ctx->depth_writing_enabled_cache != depth_state->write_enabled)
424
 
    {
425
 
      GE (ctx, glDepthMask (depth_state->write_enabled ?
426
 
                            GL_TRUE : GL_FALSE));
427
 
      ctx->depth_writing_enabled_cache = depth_state->write_enabled;
428
 
    }
429
 
 
430
 
  if (ctx->driver != COGL_DRIVER_GLES1 &&
431
 
      (ctx->depth_range_near_cache != depth_state->range_near ||
432
 
       ctx->depth_range_far_cache != depth_state->range_far))
433
 
    {
434
 
      if (ctx->driver == COGL_DRIVER_GLES2)
435
 
        GE (ctx, glDepthRangef (depth_state->range_near,
436
 
                                depth_state->range_far));
437
 
      else
438
 
        GE (ctx, glDepthRange (depth_state->range_near,
439
 
                               depth_state->range_far));
440
 
 
441
 
      ctx->depth_range_near_cache = depth_state->range_near;
442
 
      ctx->depth_range_far_cache = depth_state->range_far;
443
 
    }
444
 
}
445
 
 
446
 
static void
447
 
_cogl_pipeline_flush_color_blend_alpha_depth_state (
448
 
                                            CoglPipeline *pipeline,
449
 
                                            unsigned long pipelines_difference,
450
 
                                            CoglBool      skip_gl_color)
451
 
{
452
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
453
 
 
454
 
  /* On GLES2 we'll flush the color later */
455
 
  if (ctx->driver != COGL_DRIVER_GLES2 &&
456
 
      !skip_gl_color)
457
 
    {
458
 
      if ((pipelines_difference & COGL_PIPELINE_STATE_COLOR) ||
459
 
          /* Assume if we were previously told to skip the color, then
460
 
           * the current color needs updating... */
461
 
          ctx->current_pipeline_skip_gl_color)
462
 
        {
463
 
          CoglPipeline *authority =
464
 
            _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR);
465
 
          GE (ctx, glColor4ub (cogl_color_get_red_byte (&authority->color),
466
 
                               cogl_color_get_green_byte (&authority->color),
467
 
                               cogl_color_get_blue_byte (&authority->color),
468
 
                               cogl_color_get_alpha_byte (&authority->color)));
469
 
        }
470
 
    }
471
 
 
472
 
  if (pipelines_difference & COGL_PIPELINE_STATE_BLEND)
473
 
    {
474
 
      CoglPipeline *authority =
475
 
        _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_BLEND);
476
 
      CoglPipelineBlendState *blend_state =
477
 
        &authority->big_state->blend_state;
478
 
 
479
 
      /* GLES 1 only has glBlendFunc */
480
 
      if (ctx->driver == COGL_DRIVER_GLES1)
481
 
        {
482
 
          GE (ctx, glBlendFunc (blend_state->blend_src_factor_rgb,
483
 
                                blend_state->blend_dst_factor_rgb));
484
 
        }
485
 
#if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL)
486
 
      else
487
 
        {
488
 
          if (blend_factor_uses_constant (blend_state->blend_src_factor_rgb) ||
489
 
              blend_factor_uses_constant (blend_state
490
 
                                          ->blend_src_factor_alpha) ||
491
 
              blend_factor_uses_constant (blend_state->blend_dst_factor_rgb) ||
492
 
              blend_factor_uses_constant (blend_state->blend_dst_factor_alpha))
493
 
            {
494
 
              float red =
495
 
                cogl_color_get_red_float (&blend_state->blend_constant);
496
 
              float green =
497
 
                cogl_color_get_green_float (&blend_state->blend_constant);
498
 
              float blue =
499
 
                cogl_color_get_blue_float (&blend_state->blend_constant);
500
 
              float alpha =
501
 
                cogl_color_get_alpha_float (&blend_state->blend_constant);
502
 
 
503
 
 
504
 
              GE (ctx, glBlendColor (red, green, blue, alpha));
505
 
            }
506
 
 
507
 
          if (ctx->glBlendEquationSeparate &&
508
 
              blend_state->blend_equation_rgb !=
509
 
              blend_state->blend_equation_alpha)
510
 
            GE (ctx,
511
 
                glBlendEquationSeparate (blend_state->blend_equation_rgb,
512
 
                                         blend_state->blend_equation_alpha));
513
 
          else
514
 
            GE (ctx, glBlendEquation (blend_state->blend_equation_rgb));
515
 
 
516
 
          if (ctx->glBlendFuncSeparate &&
517
 
              (blend_state->blend_src_factor_rgb !=
518
 
               blend_state->blend_src_factor_alpha ||
519
 
               (blend_state->blend_dst_factor_rgb !=
520
 
                blend_state->blend_dst_factor_alpha)))
521
 
            GE (ctx, glBlendFuncSeparate (blend_state->blend_src_factor_rgb,
522
 
                                          blend_state->blend_dst_factor_rgb,
523
 
                                          blend_state->blend_src_factor_alpha,
524
 
                                          blend_state->blend_dst_factor_alpha));
525
 
          else
526
 
            GE (ctx, glBlendFunc (blend_state->blend_src_factor_rgb,
527
 
                                  blend_state->blend_dst_factor_rgb));
528
 
        }
529
 
#endif
530
 
    }
531
 
 
532
 
#if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
533
 
 
534
 
  if (ctx->driver != COGL_DRIVER_GLES2)
535
 
    {
536
 
      /* Under GLES2 the alpha function is implemented as part of the
537
 
         fragment shader */
538
 
      if (pipelines_difference & (COGL_PIPELINE_STATE_ALPHA_FUNC |
539
 
                                  COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE))
540
 
        {
541
 
          CoglPipeline *authority =
542
 
            _cogl_pipeline_get_authority (pipeline,
543
 
                                          COGL_PIPELINE_STATE_ALPHA_FUNC);
544
 
          CoglPipelineAlphaFuncState *alpha_state =
545
 
            &authority->big_state->alpha_state;
546
 
 
547
 
          /* NB: Currently the Cogl defines are compatible with the GL ones: */
548
 
          GE (ctx, glAlphaFunc (alpha_state->alpha_func,
549
 
                                alpha_state->alpha_func_reference));
550
 
        }
551
 
 
552
 
      /* Under GLES2 the lighting parameters are implemented as uniforms
553
 
         in the progend */
554
 
      if (pipelines_difference & COGL_PIPELINE_STATE_LIGHTING)
555
 
        {
556
 
          CoglPipeline *authority =
557
 
            _cogl_pipeline_get_authority (pipeline,
558
 
                                          COGL_PIPELINE_STATE_LIGHTING);
559
 
          CoglPipelineLightingState *lighting_state =
560
 
            &authority->big_state->lighting_state;
561
 
 
562
 
          GE (ctx, glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT,
563
 
                                 lighting_state->ambient));
564
 
          GE (ctx, glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE,
565
 
                                 lighting_state->diffuse));
566
 
          GE (ctx, glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR,
567
 
                                 lighting_state->specular));
568
 
          GE (ctx, glMaterialfv (GL_FRONT_AND_BACK, GL_EMISSION,
569
 
                                 lighting_state->emission));
570
 
          GE (ctx, glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS,
571
 
                                 &lighting_state->shininess));
572
 
        }
573
 
    }
574
 
 
575
 
#endif
576
 
 
577
 
  if (pipelines_difference & COGL_PIPELINE_STATE_DEPTH)
578
 
    {
579
 
      CoglPipeline *authority =
580
 
        _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_DEPTH);
581
 
      CoglDepthState *depth_state = &authority->big_state->depth_state;
582
 
 
583
 
      flush_depth_state (ctx, depth_state);
584
 
    }
585
 
 
586
 
  if (pipelines_difference & COGL_PIPELINE_STATE_LOGIC_OPS)
587
 
    {
588
 
      CoglPipeline *authority =
589
 
        _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LOGIC_OPS);
590
 
      CoglPipelineLogicOpsState *logic_ops_state = &authority->big_state->logic_ops_state;
591
 
      CoglColorMask color_mask = logic_ops_state->color_mask;
592
 
 
593
 
      if (ctx->current_draw_buffer)
594
 
        color_mask &= ctx->current_draw_buffer->color_mask;
595
 
 
596
 
      GE (ctx, glColorMask (!!(color_mask & COGL_COLOR_MASK_RED),
597
 
                            !!(color_mask & COGL_COLOR_MASK_GREEN),
598
 
                            !!(color_mask & COGL_COLOR_MASK_BLUE),
599
 
                            !!(color_mask & COGL_COLOR_MASK_ALPHA)));
600
 
      ctx->current_gl_color_mask = color_mask;
601
 
    }
602
 
 
603
 
  if (pipelines_difference & COGL_PIPELINE_STATE_CULL_FACE)
604
 
    {
605
 
      CoglPipeline *authority =
606
 
        _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_CULL_FACE);
607
 
      CoglPipelineCullFaceState *cull_face_state
608
 
        = &authority->big_state->cull_face_state;
609
 
 
610
 
      if (cull_face_state->mode == COGL_PIPELINE_CULL_FACE_MODE_NONE)
611
 
        GE( ctx, glDisable (GL_CULL_FACE) );
612
 
      else
613
 
        {
614
 
          CoglBool invert_winding;
615
 
 
616
 
          GE( ctx, glEnable (GL_CULL_FACE) );
617
 
 
618
 
          switch (cull_face_state->mode)
619
 
            {
620
 
            case COGL_PIPELINE_CULL_FACE_MODE_NONE:
621
 
              g_assert_not_reached ();
622
 
 
623
 
            case COGL_PIPELINE_CULL_FACE_MODE_FRONT:
624
 
              GE( ctx, glCullFace (GL_FRONT) );
625
 
              break;
626
 
 
627
 
            case COGL_PIPELINE_CULL_FACE_MODE_BACK:
628
 
              GE( ctx, glCullFace (GL_BACK) );
629
 
              break;
630
 
 
631
 
            case COGL_PIPELINE_CULL_FACE_MODE_BOTH:
632
 
              GE( ctx, glCullFace (GL_FRONT_AND_BACK) );
633
 
              break;
634
 
            }
635
 
 
636
 
          /* If we are painting to an offscreen framebuffer then we
637
 
             need to invert the winding of the front face because
638
 
             everything is painted upside down */
639
 
          invert_winding = cogl_is_offscreen (ctx->current_draw_buffer);
640
 
 
641
 
          switch (cull_face_state->front_winding)
642
 
            {
643
 
            case COGL_WINDING_CLOCKWISE:
644
 
              GE( ctx, glFrontFace (invert_winding ? GL_CCW : GL_CW) );
645
 
              break;
646
 
 
647
 
            case COGL_WINDING_COUNTER_CLOCKWISE:
648
 
              GE( ctx, glFrontFace (invert_winding ? GL_CW : GL_CCW) );
649
 
              break;
650
 
            }
651
 
        }
652
 
    }
653
 
 
654
 
  if (pipeline->real_blend_enable != ctx->gl_blend_enable_cache)
655
 
    {
656
 
      if (pipeline->real_blend_enable)
657
 
        GE (ctx, glEnable (GL_BLEND));
658
 
      else
659
 
        GE (ctx, glDisable (GL_BLEND));
660
 
      /* XXX: we shouldn't update any other blend state if blending
661
 
       * is disabled! */
662
 
      ctx->gl_blend_enable_cache = pipeline->real_blend_enable;
663
 
    }
664
 
}
665
 
 
666
 
static int
667
 
get_max_activateable_texture_units (void)
668
 
{
669
 
  _COGL_GET_CONTEXT (ctx, 0);
670
 
 
671
 
  if (G_UNLIKELY (ctx->max_activateable_texture_units == -1))
672
 
    {
673
 
      GLint values[3];
674
 
      int n_values = 0;
675
 
      int i;
676
 
 
677
 
#ifdef HAVE_COGL_GL
678
 
      if (ctx->driver == COGL_DRIVER_GL)
679
 
        {
680
 
          /* GL_MAX_TEXTURE_COORDS is provided for both GLSL and ARBfp. It
681
 
             defines the number of texture coordinates that can be
682
 
             uploaded (but doesn't necessarily relate to how many texture
683
 
             images can be sampled) */
684
 
          if (cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL) ||
685
 
              cogl_has_feature (ctx, COGL_FEATURE_ID_ARBFP))
686
 
            /* Previously this code subtracted the value by one but there
687
 
               was no explanation for why it did this and it doesn't seem
688
 
               to make sense so it has been removed */
689
 
            GE (ctx, glGetIntegerv (GL_MAX_TEXTURE_COORDS,
690
 
                                    values + n_values++));
691
 
 
692
 
          /* GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS is defined for GLSL but
693
 
             not ARBfp */
694
 
          if (cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL))
695
 
            GE (ctx, glGetIntegerv (GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
696
 
                                    values + n_values++));
697
 
        }
698
 
#endif /* HAVE_COGL_GL */
699
 
 
700
 
#ifdef HAVE_COGL_GLES2
701
 
      if (ctx->driver == COGL_DRIVER_GLES2)
702
 
        {
703
 
          GE (ctx, glGetIntegerv (GL_MAX_VERTEX_ATTRIBS, values + n_values));
704
 
          /* Two of the vertex attribs need to be used for the position
705
 
             and color */
706
 
          values[n_values++] -= 2;
707
 
 
708
 
          GE (ctx, glGetIntegerv (GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
709
 
                                  values + n_values++));
710
 
        }
711
 
#endif
712
 
 
713
 
#if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES) /* not GLES2 */
714
 
      if (ctx->driver != COGL_DRIVER_GLES2)
715
 
        {
716
 
          /* GL_MAX_TEXTURE_UNITS defines the number of units that are
717
 
             usable from the fixed function pipeline, therefore it isn't
718
 
             available in GLES2. These are also tied to the number of
719
 
             texture coordinates that can be uploaded so it should be less
720
 
             than that available from the shader extensions */
721
 
          GE (ctx, glGetIntegerv (GL_MAX_TEXTURE_UNITS,
722
 
                                  values + n_values++));
723
 
 
724
 
        }
725
 
#endif
726
 
 
727
 
      g_assert (n_values <= G_N_ELEMENTS (values) &&
728
 
                n_values > 0);
729
 
 
730
 
      /* Use the maximum value */
731
 
      ctx->max_activateable_texture_units = values[0];
732
 
      for (i = 1; i < n_values; i++)
733
 
        ctx->max_activateable_texture_units =
734
 
          MAX (values[i], ctx->max_activateable_texture_units);
735
 
    }
736
 
 
737
 
  return ctx->max_activateable_texture_units;
738
 
}
739
 
 
740
 
typedef struct
741
 
{
742
 
  int i;
743
 
  unsigned long *layer_differences;
744
 
} CoglPipelineFlushLayerState;
745
 
 
746
 
static CoglBool
747
 
flush_layers_common_gl_state_cb (CoglPipelineLayer *layer, void *user_data)
748
 
{
749
 
  CoglPipelineFlushLayerState *flush_state = user_data;
750
 
  int                          unit_index = flush_state->i;
751
 
  CoglTextureUnit             *unit = _cogl_get_texture_unit (unit_index);
752
 
  unsigned long                layers_difference =
753
 
    flush_state->layer_differences[unit_index];
754
 
 
755
 
  _COGL_GET_CONTEXT (ctx, FALSE);
756
 
 
757
 
  /* There may not be enough texture units so we can bail out if
758
 
   * that's the case...
759
 
   */
760
 
  if (G_UNLIKELY (unit_index >= get_max_activateable_texture_units ()))
761
 
    {
762
 
      static CoglBool shown_warning = FALSE;
763
 
 
764
 
      if (!shown_warning)
765
 
        {
766
 
          g_warning ("Your hardware does not have enough texture units"
767
 
                     "to handle this many texture layers");
768
 
          shown_warning = TRUE;
769
 
        }
770
 
      return FALSE;
771
 
    }
772
 
 
773
 
  if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA)
774
 
    {
775
 
      CoglTexture *texture = _cogl_pipeline_layer_get_texture_real (layer);
776
 
      GLuint gl_texture;
777
 
      GLenum gl_target;
778
 
 
779
 
      if (texture == NULL)
780
 
        switch (_cogl_pipeline_layer_get_texture_type (layer))
781
 
          {
782
 
          case COGL_TEXTURE_TYPE_2D:
783
 
            texture = COGL_TEXTURE (ctx->default_gl_texture_2d_tex);
784
 
            break;
785
 
          case COGL_TEXTURE_TYPE_3D:
786
 
            texture = COGL_TEXTURE (ctx->default_gl_texture_3d_tex);
787
 
            break;
788
 
          case COGL_TEXTURE_TYPE_RECTANGLE:
789
 
            texture = COGL_TEXTURE (ctx->default_gl_texture_rect_tex);
790
 
            break;
791
 
          }
792
 
 
793
 
      cogl_texture_get_gl_texture (texture,
794
 
                                   &gl_texture,
795
 
                                   &gl_target);
796
 
 
797
 
      _cogl_set_active_texture_unit (unit_index);
798
 
 
799
 
      /* NB: There are several Cogl components and some code in
800
 
       * Clutter that will temporarily bind arbitrary GL textures to
801
 
       * query and modify texture object parameters. If you look at
802
 
       * _cogl_bind_gl_texture_transient() you can see we make sure
803
 
       * that such code always binds to texture unit 1 which means we
804
 
       * can't rely on the unit->gl_texture state if unit->index == 1.
805
 
       *
806
 
       * Because texture unit 1 is a bit special we actually defer any
807
 
       * necessary glBindTexture for it until the end of
808
 
       * _cogl_pipeline_flush_gl_state().
809
 
       *
810
 
       * NB: we get notified whenever glDeleteTextures is used (see
811
 
       * _cogl_delete_gl_texture()) where we invalidate
812
 
       * unit->gl_texture references to deleted textures so it's safe
813
 
       * to compare unit->gl_texture with gl_texture.  (Without the
814
 
       * hook it would be possible to delete a GL texture and create a
815
 
       * new one with the same name and comparing unit->gl_texture and
816
 
       * gl_texture wouldn't detect that.)
817
 
       *
818
 
       * NB: for foreign textures we don't know how the deletion of
819
 
       * the GL texture objects correspond to the deletion of the
820
 
       * CoglTextures so if there was previously a foreign texture
821
 
       * associated with the texture unit then we can't assume that we
822
 
       * aren't seeing a recycled texture name so we have to bind.
823
 
       */
824
 
      if (unit->gl_texture != gl_texture || unit->is_foreign)
825
 
        {
826
 
          if (unit_index == 1)
827
 
            unit->dirty_gl_texture = TRUE;
828
 
          else
829
 
            GE (ctx, glBindTexture (gl_target, gl_texture));
830
 
          unit->gl_texture = gl_texture;
831
 
          unit->gl_target = gl_target;
832
 
        }
833
 
 
834
 
      unit->is_foreign = _cogl_texture_is_foreign (texture);
835
 
 
836
 
      /* The texture_storage_changed boolean indicates if the
837
 
       * CoglTexture's underlying GL texture storage has changed since
838
 
       * it was flushed to the texture unit. We've just flushed the
839
 
       * latest state so we can reset this. */
840
 
      unit->texture_storage_changed = FALSE;
841
 
    }
842
 
 
843
 
  if ((layers_difference & COGL_PIPELINE_LAYER_STATE_SAMPLER) &&
844
 
      (ctx->private_feature_flags & COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS))
845
 
    {
846
 
      const CoglSamplerCacheEntry *sampler_state;
847
 
 
848
 
      sampler_state = _cogl_pipeline_layer_get_sampler_state (layer);
849
 
 
850
 
      GE( ctx, glBindSampler (unit_index, sampler_state->sampler_object) );
851
 
    }
852
 
 
853
 
  /* Under GLES2 the fragment shader will use gl_PointCoord instead of
854
 
     replacing the texture coordinates */
855
 
#if defined (HAVE_COGL_GLES) || defined (HAVE_COGL_GL)
856
 
  if (ctx->driver != COGL_DRIVER_GLES2 &&
857
 
      (layers_difference & COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS))
858
 
    {
859
 
      CoglPipelineState change = COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS;
860
 
      CoglPipelineLayer *authority =
861
 
        _cogl_pipeline_layer_get_authority (layer, change);
862
 
      CoglPipelineLayerBigState *big_state = authority->big_state;
863
 
 
864
 
      _cogl_set_active_texture_unit (unit_index);
865
 
 
866
 
      GE (ctx, glTexEnvi (GL_POINT_SPRITE, GL_COORD_REPLACE,
867
 
                          big_state->point_sprite_coords));
868
 
    }
869
 
#endif
870
 
 
871
 
  cogl_object_ref (layer);
872
 
  if (unit->layer != NULL)
873
 
    cogl_object_unref (unit->layer);
874
 
 
875
 
  unit->layer = layer;
876
 
  unit->layer_changes_since_flush = 0;
877
 
 
878
 
  flush_state->i++;
879
 
 
880
 
  return TRUE;
881
 
}
882
 
 
883
 
static void
884
 
_cogl_pipeline_flush_common_gl_state (CoglPipeline  *pipeline,
885
 
                                      unsigned long  pipelines_difference,
886
 
                                      unsigned long *layer_differences,
887
 
                                      CoglBool       skip_gl_color)
888
 
{
889
 
  CoglPipelineFlushLayerState state;
890
 
 
891
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
892
 
 
893
 
  _cogl_pipeline_flush_color_blend_alpha_depth_state (pipeline,
894
 
                                                      pipelines_difference,
895
 
                                                      skip_gl_color);
896
 
 
897
 
  state.i = 0;
898
 
  state.layer_differences = layer_differences;
899
 
  _cogl_pipeline_foreach_layer_internal (pipeline,
900
 
                                         flush_layers_common_gl_state_cb,
901
 
                                         &state);
902
 
}
903
 
 
904
 
/* Re-assert the layer's wrap modes on the given CoglTexture.
905
 
 *
906
 
 * Note: we don't simply forward the wrap modes to layer->texture
907
 
 * since the actual texture being used may have been overridden.
908
 
 */
909
 
static void
910
 
_cogl_pipeline_layer_forward_wrap_modes (CoglPipelineLayer *layer,
911
 
                                         CoglTexture *texture)
912
 
{
913
 
  CoglSamplerCacheWrapMode wrap_mode_s, wrap_mode_t, wrap_mode_p;
914
 
  GLenum gl_wrap_mode_s, gl_wrap_mode_t, gl_wrap_mode_p;
915
 
 
916
 
  if (texture == NULL)
917
 
    return;
918
 
 
919
 
  _cogl_pipeline_layer_get_wrap_modes (layer,
920
 
                                       &wrap_mode_s,
921
 
                                       &wrap_mode_t,
922
 
                                       &wrap_mode_p);
923
 
 
924
 
  /* Update the wrap mode on the texture object. The texture backend
925
 
     should cache the value so that it will be a no-op if the object
926
 
     already has the same wrap mode set. The backend is best placed to
927
 
     do this because it knows how many of the coordinates will
928
 
     actually be used (ie, a 1D texture only cares about the 's'
929
 
     coordinate but a 3D texture would use all three). GL uses the
930
 
     wrap mode as part of the texture object state but we are
931
 
     pretending it's part of the per-layer environment state. This
932
 
     will break if the application tries to use different modes in
933
 
     different layers using the same texture. */
934
 
 
935
 
  if (wrap_mode_s == COGL_SAMPLER_CACHE_WRAP_MODE_AUTOMATIC)
936
 
    gl_wrap_mode_s = GL_CLAMP_TO_EDGE;
937
 
  else
938
 
    gl_wrap_mode_s = wrap_mode_s;
939
 
 
940
 
  if (wrap_mode_t == COGL_SAMPLER_CACHE_WRAP_MODE_AUTOMATIC)
941
 
    gl_wrap_mode_t = GL_CLAMP_TO_EDGE;
942
 
  else
943
 
    gl_wrap_mode_t = wrap_mode_t;
944
 
 
945
 
  if (wrap_mode_p == COGL_SAMPLER_CACHE_WRAP_MODE_AUTOMATIC)
946
 
    gl_wrap_mode_p = GL_CLAMP_TO_EDGE;
947
 
  else
948
 
    gl_wrap_mode_p = wrap_mode_p;
949
 
 
950
 
  _cogl_texture_set_wrap_mode_parameters (texture,
951
 
                                          gl_wrap_mode_s,
952
 
                                          gl_wrap_mode_t,
953
 
                                          gl_wrap_mode_p);
954
 
}
955
 
 
956
 
/* OpenGL associates the min/mag filters and repeat modes with the
957
 
 * texture object not the texture unit so we always have to re-assert
958
 
 * the filter and repeat modes whenever we use a texture since it may
959
 
 * be referenced by multiple pipelines with different modes.
960
 
 *
961
 
 * This function is bypassed in favour of sampler objects if
962
 
 * GL_ARB_sampler_objects is advertised. This fallback won't work if
963
 
 * the same texture is bound to multiple layers with different sampler
964
 
 * state.
965
 
 */
966
 
static void
967
 
foreach_texture_unit_update_filter_and_wrap_modes (void)
968
 
{
969
 
  int i;
970
 
 
971
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
972
 
 
973
 
  for (i = 0; i < ctx->texture_units->len; i++)
974
 
    {
975
 
      CoglTextureUnit *unit =
976
 
        &g_array_index (ctx->texture_units, CoglTextureUnit, i);
977
 
 
978
 
      if (unit->layer)
979
 
        {
980
 
          CoglTexture *texture = _cogl_pipeline_layer_get_texture (unit->layer);
981
 
 
982
 
          if (texture != NULL)
983
 
            {
984
 
              CoglPipelineFilter min;
985
 
              CoglPipelineFilter mag;
986
 
 
987
 
              _cogl_pipeline_layer_get_filters (unit->layer, &min, &mag);
988
 
              _cogl_texture_set_filters (texture, min, mag);
989
 
 
990
 
              _cogl_pipeline_layer_forward_wrap_modes (unit->layer, texture);
991
 
            }
992
 
        }
993
 
    }
994
 
}
995
 
 
996
 
typedef struct
997
 
{
998
 
  int i;
999
 
  unsigned long *layer_differences;
1000
 
} CoglPipelineCompareLayersState;
1001
 
 
1002
 
static CoglBool
1003
 
compare_layer_differences_cb (CoglPipelineLayer *layer, void *user_data)
1004
 
{
1005
 
  CoglPipelineCompareLayersState *state = user_data;
1006
 
  CoglTextureUnit *unit = _cogl_get_texture_unit (state->i);
1007
 
 
1008
 
  if (unit->layer == layer)
1009
 
    state->layer_differences[state->i] = unit->layer_changes_since_flush;
1010
 
  else if (unit->layer)
1011
 
    {
1012
 
      state->layer_differences[state->i] = unit->layer_changes_since_flush;
1013
 
      state->layer_differences[state->i] |=
1014
 
        _cogl_pipeline_layer_compare_differences (layer, unit->layer);
1015
 
    }
1016
 
  else
1017
 
    state->layer_differences[state->i] = COGL_PIPELINE_LAYER_STATE_ALL_SPARSE;
1018
 
 
1019
 
  /* XXX: There is always a possibility that a CoglTexture's
1020
 
   * underlying GL texture storage has been changed since it was last
1021
 
   * bound to a texture unit which is why we have a callback into
1022
 
   * _cogl_pipeline_texture_storage_change_notify whenever a textures
1023
 
   * underlying GL texture storage changes which will set the
1024
 
   * unit->texture_intern_changed flag. If we see that's been set here
1025
 
   * then we force an update of the texture state...
1026
 
   */
1027
 
  if (unit->texture_storage_changed)
1028
 
    state->layer_differences[state->i] |=
1029
 
      COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA;
1030
 
 
1031
 
  state->i++;
1032
 
 
1033
 
  return TRUE;
1034
 
}
1035
 
 
1036
 
typedef struct
1037
 
{
1038
 
  const CoglPipelineFragend *fragend;
1039
 
  CoglPipeline *pipeline;
1040
 
  unsigned long *layer_differences;
1041
 
  CoglBool error_adding_layer;
1042
 
  CoglBool added_layer;
1043
 
} CoglPipelineFragendAddLayerState;
1044
 
 
1045
 
 
1046
 
static CoglBool
1047
 
fragend_add_layer_cb (CoglPipelineLayer *layer,
1048
 
                      void *user_data)
1049
 
{
1050
 
  CoglPipelineFragendAddLayerState *state = user_data;
1051
 
  const CoglPipelineFragend *fragend = state->fragend;
1052
 
  CoglPipeline *pipeline = state->pipeline;
1053
 
  int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
1054
 
 
1055
 
  /* Either generate per layer code snippets or setup the
1056
 
   * fixed function glTexEnv for each layer... */
1057
 
  if (G_LIKELY (fragend->add_layer (pipeline,
1058
 
                                    layer,
1059
 
                                    state->layer_differences[unit_index])))
1060
 
    state->added_layer = TRUE;
1061
 
  else
1062
 
    {
1063
 
      state->error_adding_layer = TRUE;
1064
 
      return FALSE;
1065
 
    }
1066
 
 
1067
 
  return TRUE;
1068
 
}
1069
 
 
1070
 
typedef struct
1071
 
{
1072
 
  CoglFramebuffer *framebuffer;
1073
 
  const CoglPipelineVertend *vertend;
1074
 
  CoglPipeline *pipeline;
1075
 
  unsigned long *layer_differences;
1076
 
  CoglBool error_adding_layer;
1077
 
  CoglBool added_layer;
1078
 
} CoglPipelineVertendAddLayerState;
1079
 
 
1080
 
 
1081
 
static CoglBool
1082
 
vertend_add_layer_cb (CoglPipelineLayer *layer,
1083
 
                      void *user_data)
1084
 
{
1085
 
  CoglPipelineVertendAddLayerState *state = user_data;
1086
 
  const CoglPipelineVertend *vertend = state->vertend;
1087
 
  CoglPipeline *pipeline = state->pipeline;
1088
 
  int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
1089
 
 
1090
 
  /* Either enerate per layer code snippets or setup the
1091
 
   * fixed function matrix uniforms for each layer... */
1092
 
  if (G_LIKELY (vertend->add_layer (pipeline,
1093
 
                                    layer,
1094
 
                                    state->layer_differences[unit_index],
1095
 
                                    state->framebuffer)))
1096
 
    state->added_layer = TRUE;
1097
 
  else
1098
 
    {
1099
 
      state->error_adding_layer = TRUE;
1100
 
      return FALSE;
1101
 
    }
1102
 
 
1103
 
  return TRUE;
1104
 
}
1105
 
 
1106
 
/*
1107
 
 * _cogl_pipeline_flush_gl_state:
1108
 
 *
1109
 
 * Details of override options:
1110
 
 * ->fallback_mask: is a bitmask of the pipeline layers that need to be
1111
 
 *    replaced with the default, fallback textures. The fallback textures are
1112
 
 *    fully transparent textures so they hopefully wont contribute to the
1113
 
 *    texture combining.
1114
 
 *
1115
 
 *    The intention of fallbacks is to try and preserve
1116
 
 *    the number of layers the user is expecting so that texture coordinates
1117
 
 *    they gave will mostly still correspond to the textures they intended, and
1118
 
 *    have a fighting chance of looking close to their originally intended
1119
 
 *    result.
1120
 
 *
1121
 
 * ->disable_mask: is a bitmask of the pipeline layers that will simply have
1122
 
 *    texturing disabled. It's only really intended for disabling all layers
1123
 
 *    > X; i.e. we'd expect to see a contiguous run of 0 starting from the LSB
1124
 
 *    and at some point the remaining bits flip to 1. It might work to disable
1125
 
 *    arbitrary layers; though I'm not sure a.t.m how OpenGL would take to
1126
 
 *    that.
1127
 
 *
1128
 
 *    The intention of the disable_mask is for emitting geometry when the user
1129
 
 *    hasn't supplied enough texture coordinates for all the layers and it's
1130
 
 *    not possible to auto generate default texture coordinates for those
1131
 
 *    layers.
1132
 
 *
1133
 
 * ->layer0_override_texture: forcibly tells us to bind this GL texture name for
1134
 
 *    layer 0 instead of plucking the gl_texture from the CoglTexture of layer
1135
 
 *    0.
1136
 
 *
1137
 
 *    The intention of this is for any primitives that supports sliced textures.
1138
 
 *    The code will can iterate each of the slices and re-flush the pipeline
1139
 
 *    forcing the GL texture of each slice in turn.
1140
 
 *
1141
 
 * ->wrap_mode_overrides: overrides the wrap modes set on each
1142
 
 *    layer. This is used to implement the automatic wrap mode.
1143
 
 *
1144
 
 * XXX: It might also help if we could specify a texture matrix for code
1145
 
 *    dealing with slicing that would be multiplied with the users own matrix.
1146
 
 *
1147
 
 *    Normaly texture coords in the range [0, 1] refer to the extents of the
1148
 
 *    texture, but when your GL texture represents a slice of the real texture
1149
 
 *    (from the users POV) then a texture matrix would be a neat way of
1150
 
 *    transforming the mapping for each slice.
1151
 
 *
1152
 
 *    Currently for textured rectangles we manually calculate the texture
1153
 
 *    coords for each slice based on the users given coords, but this solution
1154
 
 *    isn't ideal, and can't be used with CoglVertexBuffers.
1155
 
 */
1156
 
void
1157
 
_cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
1158
 
                               CoglFramebuffer *framebuffer,
1159
 
                               CoglBool skip_gl_color,
1160
 
                               int n_tex_coord_attribs)
1161
 
{
1162
 
  unsigned long    pipelines_difference;
1163
 
  int              n_layers;
1164
 
  unsigned long   *layer_differences;
1165
 
  int              i;
1166
 
  CoglTextureUnit *unit1;
1167
 
 
1168
 
  COGL_STATIC_TIMER (pipeline_flush_timer,
1169
 
                     "Mainloop", /* parent */
1170
 
                     "Material Flush",
1171
 
                     "The time spent flushing material state",
1172
 
                     0 /* no application private data */);
1173
 
 
1174
 
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1175
 
 
1176
 
  COGL_TIMER_START (_cogl_uprof_context, pipeline_flush_timer);
1177
 
 
1178
 
  if (ctx->current_pipeline == pipeline)
1179
 
    {
1180
 
      /* Bail out asap if we've been asked to re-flush the already current
1181
 
       * pipeline and we can see the pipeline hasn't changed */
1182
 
      if (ctx->current_pipeline_age == pipeline->age &&
1183
 
          ctx->current_pipeline_skip_gl_color == skip_gl_color)
1184
 
        goto done;
1185
 
 
1186
 
      pipelines_difference = ctx->current_pipeline_changes_since_flush;
1187
 
    }
1188
 
  else if (ctx->current_pipeline)
1189
 
    {
1190
 
      pipelines_difference = ctx->current_pipeline_changes_since_flush;
1191
 
      pipelines_difference |=
1192
 
        _cogl_pipeline_compare_differences (ctx->current_pipeline,
1193
 
                                            pipeline);
1194
 
    }
1195
 
  else
1196
 
    pipelines_difference = COGL_PIPELINE_STATE_ALL_SPARSE;
1197
 
 
1198
 
  /* Get a layer_differences mask for each layer to be flushed */
1199
 
  n_layers = cogl_pipeline_get_n_layers (pipeline);
1200
 
  if (n_layers)
1201
 
    {
1202
 
      CoglPipelineCompareLayersState state;
1203
 
      layer_differences = g_alloca (sizeof (unsigned long *) * n_layers);
1204
 
      memset (layer_differences, 0, sizeof (layer_differences));
1205
 
      state.i = 0;
1206
 
      state.layer_differences = layer_differences;
1207
 
      _cogl_pipeline_foreach_layer_internal (pipeline,
1208
 
                                             compare_layer_differences_cb,
1209
 
                                             &state);
1210
 
    }
1211
 
  else
1212
 
    layer_differences = NULL;
1213
 
 
1214
 
  /* Make sure we generate the texture coordinate array to be at least
1215
 
     the number of layers. This is important because the vertend will
1216
 
     try to pass along the corresponding varying for each layer
1217
 
     regardless of whether the fragment shader is actually using
1218
 
     it. Also it is possible that the application is assuming that if
1219
 
     the attribute isn't passed then it will default to 0,0. This is
1220
 
     what test-cogl-primitive does */
1221
 
  if (n_layers > n_tex_coord_attribs)
1222
 
    n_tex_coord_attribs = n_layers;
1223
 
 
1224
 
  /* First flush everything that's the same regardless of which
1225
 
   * pipeline backend is being used...
1226
 
   *
1227
 
   * 1) top level state:
1228
 
   *  glColor (or skip if a vertex attribute is being used for color)
1229
 
   *  blend state
1230
 
   *  alpha test state (except for GLES 2.0)
1231
 
   *
1232
 
   * 2) then foreach layer:
1233
 
   *  determine gl_target/gl_texture
1234
 
   *  bind texture
1235
 
   *
1236
 
   *  Note: After _cogl_pipeline_flush_common_gl_state you can expect
1237
 
   *  all state of the layers corresponding texture unit to be
1238
 
   *  updated.
1239
 
   */
1240
 
  _cogl_pipeline_flush_common_gl_state (pipeline,
1241
 
                                        pipelines_difference,
1242
 
                                        layer_differences,
1243
 
                                        skip_gl_color);
1244
 
 
1245
 
  /* Now flush the fragment processing state according to the current
1246
 
   * fragment processing backend.
1247
 
   *
1248
 
   * Note: Some of the backends may not support the current pipeline
1249
 
   * configuration and in that case it will report an error and we
1250
 
   * will fallback to a different backend.
1251
 
   *
1252
 
   * NB: if pipeline->backend != COGL_PIPELINE_FRAGEND_UNDEFINED then
1253
 
   * we have previously managed to successfully flush this pipeline
1254
 
   * with the given backend so we will simply use that to avoid
1255
 
   * fallback code paths.
1256
 
   */
1257
 
 
1258
 
  if (pipeline->fragend == COGL_PIPELINE_FRAGEND_UNDEFINED)
1259
 
    _cogl_pipeline_set_fragend (pipeline, COGL_PIPELINE_FRAGEND_DEFAULT);
1260
 
 
1261
 
  for (i = pipeline->fragend;
1262
 
       i < G_N_ELEMENTS (_cogl_pipeline_fragends);
1263
 
       i++, _cogl_pipeline_set_fragend (pipeline, i))
1264
 
    {
1265
 
      const CoglPipelineFragend *fragend = _cogl_pipeline_fragends[i];
1266
 
      CoglPipelineFragendAddLayerState state;
1267
 
 
1268
 
      /* E.g. For fragends generating code they can setup their
1269
 
       * scratch buffers here... */
1270
 
      if (G_UNLIKELY (!fragend->start (pipeline,
1271
 
                                       n_layers,
1272
 
                                       pipelines_difference,
1273
 
                                       n_tex_coord_attribs)))
1274
 
        continue;
1275
 
 
1276
 
      state.fragend = fragend;
1277
 
      state.pipeline = pipeline;
1278
 
      state.layer_differences = layer_differences;
1279
 
      state.error_adding_layer = FALSE;
1280
 
      state.added_layer = FALSE;
1281
 
      _cogl_pipeline_foreach_layer_internal (pipeline,
1282
 
                                             fragend_add_layer_cb,
1283
 
                                             &state);
1284
 
 
1285
 
      if (G_UNLIKELY (state.error_adding_layer))
1286
 
        continue;
1287
 
 
1288
 
      if (!state.added_layer &&
1289
 
          fragend->passthrough &&
1290
 
          G_UNLIKELY (!fragend->passthrough (pipeline)))
1291
 
        continue;
1292
 
 
1293
 
      /* For fragends generating code they may compile and link their
1294
 
       * programs here, update any uniforms and tell OpenGL to use
1295
 
       * that program.
1296
 
       */
1297
 
      if (G_UNLIKELY (!fragend->end (pipeline, pipelines_difference)))
1298
 
        continue;
1299
 
 
1300
 
      break;
1301
 
    }
1302
 
 
1303
 
  if (G_UNLIKELY (i >= G_N_ELEMENTS (_cogl_pipeline_fragends)))
1304
 
    g_warning ("No usable pipeline fragment backend was found!");
1305
 
 
1306
 
  /* Now flush the vertex processing state according to the current
1307
 
   * vertex processing backend.
1308
 
   */
1309
 
 
1310
 
  if (pipeline->vertend == COGL_PIPELINE_VERTEND_UNDEFINED)
1311
 
    _cogl_pipeline_set_vertend (pipeline, COGL_PIPELINE_VERTEND_DEFAULT);
1312
 
 
1313
 
  for (i = pipeline->vertend;
1314
 
       i < G_N_ELEMENTS (_cogl_pipeline_vertends);
1315
 
       i++, _cogl_pipeline_set_vertend (pipeline, i))
1316
 
    {
1317
 
      const CoglPipelineVertend *vertend = _cogl_pipeline_vertends[i];
1318
 
      CoglPipelineVertendAddLayerState state;
1319
 
 
1320
 
      /* E.g. For vertends generating code they can setup their
1321
 
       * scratch buffers here... */
1322
 
      if (G_UNLIKELY (!vertend->start (pipeline,
1323
 
                                       n_layers,
1324
 
                                       pipelines_difference,
1325
 
                                       n_tex_coord_attribs)))
1326
 
        continue;
1327
 
 
1328
 
      state.framebuffer = framebuffer;
1329
 
      state.vertend = vertend;
1330
 
      state.pipeline = pipeline;
1331
 
      state.layer_differences = layer_differences;
1332
 
      state.error_adding_layer = FALSE;
1333
 
      state.added_layer = FALSE;
1334
 
      _cogl_pipeline_foreach_layer_internal (pipeline,
1335
 
                                             vertend_add_layer_cb,
1336
 
                                             &state);
1337
 
 
1338
 
      if (G_UNLIKELY (state.error_adding_layer))
1339
 
        continue;
1340
 
 
1341
 
      /* For vertends generating code they may compile and link their
1342
 
       * programs here, update any uniforms and tell OpenGL to use
1343
 
       * that program.
1344
 
       */
1345
 
      if (G_UNLIKELY (!vertend->end (pipeline, pipelines_difference)))
1346
 
        continue;
1347
 
 
1348
 
      break;
1349
 
    }
1350
 
 
1351
 
  if (G_UNLIKELY (i >= G_N_ELEMENTS (_cogl_pipeline_vertends)))
1352
 
    g_warning ("No usable pipeline vertex backend was found!");
1353
 
 
1354
 
  for (i = 0; i < COGL_PIPELINE_N_PROGENDS; i++)
1355
 
    if (_cogl_pipeline_progends[i]->end)
1356
 
      _cogl_pipeline_progends[i]->end (pipeline, pipelines_difference,
1357
 
                                       n_tex_coord_attribs);
1358
 
 
1359
 
  /* FIXME: This reference is actually resulting in lots of
1360
 
   * copy-on-write reparenting because one-shot pipelines end up
1361
 
   * living for longer than necessary and so any later modification of
1362
 
   * the parent will cause a copy-on-write.
1363
 
   *
1364
 
   * XXX: The issue should largely go away when we switch to using
1365
 
   * weak pipelines for overrides.
1366
 
   */
1367
 
  cogl_object_ref (pipeline);
1368
 
  if (ctx->current_pipeline != NULL)
1369
 
    cogl_object_unref (ctx->current_pipeline);
1370
 
  ctx->current_pipeline = pipeline;
1371
 
  ctx->current_pipeline_changes_since_flush = 0;
1372
 
  ctx->current_pipeline_skip_gl_color = skip_gl_color;
1373
 
  ctx->current_pipeline_age = pipeline->age;
1374
 
 
1375
 
done:
1376
 
 
1377
 
  /* We can't assume the color will be retained between flushes on
1378
 
     GLES2 because the generic attribute values are not stored as part
1379
 
     of the program object so they could be overridden by any
1380
 
     attribute changes in another program */
1381
 
#ifdef HAVE_COGL_GLES2
1382
 
  if (ctx->driver == COGL_DRIVER_GLES2 && !skip_gl_color)
1383
 
    {
1384
 
      int attribute;
1385
 
      CoglPipeline *authority =
1386
 
        _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR);
1387
 
      int name_index = COGL_ATTRIBUTE_COLOR_NAME_INDEX;
1388
 
 
1389
 
      attribute =
1390
 
        _cogl_pipeline_progend_glsl_get_attrib_location (pipeline, name_index);
1391
 
      if (attribute != -1)
1392
 
        GE (ctx,
1393
 
            glVertexAttrib4f (attribute,
1394
 
                              cogl_color_get_red_float (&authority->color),
1395
 
                              cogl_color_get_green_float (&authority->color),
1396
 
                              cogl_color_get_blue_float (&authority->color),
1397
 
                              cogl_color_get_alpha_float (&authority->color)));
1398
 
    }
1399
 
#endif
1400
 
 
1401
 
  /* Give any progends a chance to update any uniforms that might not
1402
 
     depend on the material state. This is used on GLES2 to update the
1403
 
     matrices */
1404
 
  for (i = 0; i < COGL_PIPELINE_N_PROGENDS; i++)
1405
 
    if (_cogl_pipeline_progends[i]->pre_paint)
1406
 
      _cogl_pipeline_progends[i]->pre_paint (pipeline, framebuffer);
1407
 
 
1408
 
  /* Handle the fact that OpenGL associates texture filter and wrap
1409
 
   * modes with the texture objects not the texture units... */
1410
 
  if (!(ctx->private_feature_flags & COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS))
1411
 
    foreach_texture_unit_update_filter_and_wrap_modes ();
1412
 
 
1413
 
  /* If this pipeline has more than one layer then we always need
1414
 
   * to make sure we rebind the texture for unit 1.
1415
 
   *
1416
 
   * NB: various components of Cogl may temporarily bind arbitrary
1417
 
   * textures to texture unit 1 so they can query and modify texture
1418
 
   * object parameters. cogl-pipeline.c (See
1419
 
   * _cogl_bind_gl_texture_transient)
1420
 
   */
1421
 
  unit1 = _cogl_get_texture_unit (1);
1422
 
  if (cogl_pipeline_get_n_layers (pipeline) > 1 && unit1->dirty_gl_texture)
1423
 
    {
1424
 
      _cogl_set_active_texture_unit (1);
1425
 
      GE (ctx, glBindTexture (unit1->gl_target, unit1->gl_texture));
1426
 
      unit1->dirty_gl_texture = FALSE;
1427
 
    }
1428
 
 
1429
 
  COGL_TIMER_STOP (_cogl_uprof_context, pipeline_flush_timer);
1430
 
}
1431