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