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