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