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 #ifdef HAVE_CONFIG_H
35 #include "cogl-config.h"
36 #endif
37
38 #include "cogl-context-private.h"
39 #include "cogl-color-private.h"
40 #include "cogl-blend-string.h"
41 #include "cogl-util.h"
42 #include "cogl-depth-state-private.h"
43 #include "cogl-pipeline-state-private.h"
44 #include "cogl-snippet-private.h"
45 #include "cogl-error-private.h"
46
47 #include <test-fixtures/test-unit.h>
48
49 #include "string.h"
50
51 #ifndef GL_FUNC_ADD
52 #define GL_FUNC_ADD 0x8006
53 #endif
54
55 CoglPipeline *
_cogl_pipeline_get_user_program(CoglPipeline * pipeline)56 _cogl_pipeline_get_user_program (CoglPipeline *pipeline)
57 {
58 CoglPipeline *authority;
59
60 _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), NULL);
61
62 authority =
63 _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_USER_SHADER);
64
65 return authority->big_state->user_program;
66 }
67
68 CoglBool
_cogl_pipeline_color_equal(CoglPipeline * authority0,CoglPipeline * authority1)69 _cogl_pipeline_color_equal (CoglPipeline *authority0,
70 CoglPipeline *authority1)
71 {
72 return cogl_color_equal (&authority0->color, &authority1->color);
73 }
74
75 CoglBool
_cogl_pipeline_lighting_state_equal(CoglPipeline * authority0,CoglPipeline * authority1)76 _cogl_pipeline_lighting_state_equal (CoglPipeline *authority0,
77 CoglPipeline *authority1)
78 {
79 CoglPipelineLightingState *state0 = &authority0->big_state->lighting_state;
80 CoglPipelineLightingState *state1 = &authority1->big_state->lighting_state;
81
82 if (memcmp (state0->ambient, state1->ambient, sizeof (float) * 4) != 0)
83 return FALSE;
84 if (memcmp (state0->diffuse, state1->diffuse, sizeof (float) * 4) != 0)
85 return FALSE;
86 if (memcmp (state0->specular, state1->specular, sizeof (float) * 4) != 0)
87 return FALSE;
88 if (memcmp (state0->emission, state1->emission, sizeof (float) * 4) != 0)
89 return FALSE;
90 if (state0->shininess != state1->shininess)
91 return FALSE;
92
93 return TRUE;
94 }
95
96 CoglBool
_cogl_pipeline_alpha_func_state_equal(CoglPipeline * authority0,CoglPipeline * authority1)97 _cogl_pipeline_alpha_func_state_equal (CoglPipeline *authority0,
98 CoglPipeline *authority1)
99 {
100 CoglPipelineAlphaFuncState *alpha_state0 =
101 &authority0->big_state->alpha_state;
102 CoglPipelineAlphaFuncState *alpha_state1 =
103 &authority1->big_state->alpha_state;
104
105 return alpha_state0->alpha_func == alpha_state1->alpha_func;
106 }
107
108 CoglBool
_cogl_pipeline_alpha_func_reference_state_equal(CoglPipeline * authority0,CoglPipeline * authority1)109 _cogl_pipeline_alpha_func_reference_state_equal (CoglPipeline *authority0,
110 CoglPipeline *authority1)
111 {
112 CoglPipelineAlphaFuncState *alpha_state0 =
113 &authority0->big_state->alpha_state;
114 CoglPipelineAlphaFuncState *alpha_state1 =
115 &authority1->big_state->alpha_state;
116
117 return (alpha_state0->alpha_func_reference ==
118 alpha_state1->alpha_func_reference);
119 }
120
121 CoglBool
_cogl_pipeline_blend_state_equal(CoglPipeline * authority0,CoglPipeline * authority1)122 _cogl_pipeline_blend_state_equal (CoglPipeline *authority0,
123 CoglPipeline *authority1)
124 {
125 CoglPipelineBlendState *blend_state0 = &authority0->big_state->blend_state;
126 CoglPipelineBlendState *blend_state1 = &authority1->big_state->blend_state;
127
128 _COGL_GET_CONTEXT (ctx, FALSE);
129
130 if (blend_state0->blend_equation_rgb != blend_state1->blend_equation_rgb)
131 return FALSE;
132
133 if (blend_state0->blend_equation_alpha !=
134 blend_state1->blend_equation_alpha)
135 return FALSE;
136 if (blend_state0->blend_src_factor_alpha !=
137 blend_state1->blend_src_factor_alpha)
138 return FALSE;
139 if (blend_state0->blend_dst_factor_alpha !=
140 blend_state1->blend_dst_factor_alpha)
141 return FALSE;
142
143 if (blend_state0->blend_src_factor_rgb !=
144 blend_state1->blend_src_factor_rgb)
145 return FALSE;
146 if (blend_state0->blend_dst_factor_rgb !=
147 blend_state1->blend_dst_factor_rgb)
148 return FALSE;
149
150 if (blend_state0->blend_src_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR ||
151 blend_state0->blend_src_factor_rgb == GL_CONSTANT_COLOR ||
152 blend_state0->blend_dst_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR ||
153 blend_state0->blend_dst_factor_rgb == GL_CONSTANT_COLOR)
154 {
155 if (!cogl_color_equal (&blend_state0->blend_constant,
156 &blend_state1->blend_constant))
157 return FALSE;
158 }
159
160 return TRUE;
161 }
162
163 CoglBool
_cogl_pipeline_depth_state_equal(CoglPipeline * authority0,CoglPipeline * authority1)164 _cogl_pipeline_depth_state_equal (CoglPipeline *authority0,
165 CoglPipeline *authority1)
166 {
167 if (authority0->big_state->depth_state.test_enabled == FALSE &&
168 authority1->big_state->depth_state.test_enabled == FALSE)
169 return TRUE;
170 else
171 {
172 CoglDepthState *s0 = &authority0->big_state->depth_state;
173 CoglDepthState *s1 = &authority1->big_state->depth_state;
174 return s0->test_enabled == s1->test_enabled &&
175 s0->test_function == s1->test_function &&
176 s0->write_enabled == s1->write_enabled &&
177 s0->range_near == s1->range_near &&
178 s0->range_far == s1->range_far;
179 }
180 }
181
182 CoglBool
_cogl_pipeline_fog_state_equal(CoglPipeline * authority0,CoglPipeline * authority1)183 _cogl_pipeline_fog_state_equal (CoglPipeline *authority0,
184 CoglPipeline *authority1)
185 {
186 CoglPipelineFogState *fog_state0 = &authority0->big_state->fog_state;
187 CoglPipelineFogState *fog_state1 = &authority1->big_state->fog_state;
188
189 if (fog_state0->enabled == fog_state1->enabled &&
190 cogl_color_equal (&fog_state0->color, &fog_state1->color) &&
191 fog_state0->mode == fog_state1->mode &&
192 fog_state0->density == fog_state1->density &&
193 fog_state0->z_near == fog_state1->z_near &&
194 fog_state0->z_far == fog_state1->z_far)
195 return TRUE;
196 else
197 return FALSE;
198 }
199
200 CoglBool
_cogl_pipeline_non_zero_point_size_equal(CoglPipeline * authority0,CoglPipeline * authority1)201 _cogl_pipeline_non_zero_point_size_equal (CoglPipeline *authority0,
202 CoglPipeline *authority1)
203 {
204 return (authority0->big_state->non_zero_point_size ==
205 authority1->big_state->non_zero_point_size);
206 }
207
208 CoglBool
_cogl_pipeline_point_size_equal(CoglPipeline * authority0,CoglPipeline * authority1)209 _cogl_pipeline_point_size_equal (CoglPipeline *authority0,
210 CoglPipeline *authority1)
211 {
212 return authority0->big_state->point_size == authority1->big_state->point_size;
213 }
214
215 CoglBool
_cogl_pipeline_per_vertex_point_size_equal(CoglPipeline * authority0,CoglPipeline * authority1)216 _cogl_pipeline_per_vertex_point_size_equal (CoglPipeline *authority0,
217 CoglPipeline *authority1)
218 {
219 return (authority0->big_state->per_vertex_point_size ==
220 authority1->big_state->per_vertex_point_size);
221 }
222
223 CoglBool
_cogl_pipeline_logic_ops_state_equal(CoglPipeline * authority0,CoglPipeline * authority1)224 _cogl_pipeline_logic_ops_state_equal (CoglPipeline *authority0,
225 CoglPipeline *authority1)
226 {
227 CoglPipelineLogicOpsState *logic_ops_state0 = &authority0->big_state->logic_ops_state;
228 CoglPipelineLogicOpsState *logic_ops_state1 = &authority1->big_state->logic_ops_state;
229
230 return logic_ops_state0->color_mask == logic_ops_state1->color_mask;
231 }
232
233 CoglBool
_cogl_pipeline_cull_face_state_equal(CoglPipeline * authority0,CoglPipeline * authority1)234 _cogl_pipeline_cull_face_state_equal (CoglPipeline *authority0,
235 CoglPipeline *authority1)
236 {
237 CoglPipelineCullFaceState *cull_face_state0
238 = &authority0->big_state->cull_face_state;
239 CoglPipelineCullFaceState *cull_face_state1
240 = &authority1->big_state->cull_face_state;
241
242 /* The cull face state is considered equal if two pipelines are both
243 set to no culling. If the front winding property is ever used for
244 anything else or the comparison is used not just for drawing then
245 this would have to change */
246
247 if (cull_face_state0->mode == COGL_PIPELINE_CULL_FACE_MODE_NONE)
248 return cull_face_state1->mode == COGL_PIPELINE_CULL_FACE_MODE_NONE;
249
250 return (cull_face_state0->mode == cull_face_state1->mode &&
251 cull_face_state0->front_winding == cull_face_state1->front_winding);
252 }
253
254 CoglBool
_cogl_pipeline_user_shader_equal(CoglPipeline * authority0,CoglPipeline * authority1)255 _cogl_pipeline_user_shader_equal (CoglPipeline *authority0,
256 CoglPipeline *authority1)
257 {
258 return (authority0->big_state->user_program ==
259 authority1->big_state->user_program);
260 }
261
262 typedef struct
263 {
264 const CoglBoxedValue **dst_values;
265 const CoglBoxedValue *src_values;
266 int override_count;
267 } GetUniformsClosure;
268
269 static CoglBool
get_uniforms_cb(int uniform_num,void * user_data)270 get_uniforms_cb (int uniform_num, void *user_data)
271 {
272 GetUniformsClosure *data = user_data;
273
274 if (data->dst_values[uniform_num] == NULL)
275 data->dst_values[uniform_num] = data->src_values + data->override_count;
276
277 data->override_count++;
278
279 return TRUE;
280 }
281
282 static void
_cogl_pipeline_get_all_uniform_values(CoglPipeline * pipeline,const CoglBoxedValue ** values)283 _cogl_pipeline_get_all_uniform_values (CoglPipeline *pipeline,
284 const CoglBoxedValue **values)
285 {
286 GetUniformsClosure data;
287
288 _COGL_GET_CONTEXT (ctx, NO_RETVAL);
289
290 memset (values, 0,
291 sizeof (const CoglBoxedValue *) * ctx->n_uniform_names);
292
293 data.dst_values = values;
294
295 do
296 {
297 if ((pipeline->differences & COGL_PIPELINE_STATE_UNIFORMS))
298 {
299 const CoglPipelineUniformsState *uniforms_state =
300 &pipeline->big_state->uniforms_state;
301
302 data.override_count = 0;
303 data.src_values = uniforms_state->override_values;
304
305 _cogl_bitmask_foreach (&uniforms_state->override_mask,
306 get_uniforms_cb,
307 &data);
308 }
309 pipeline = _cogl_pipeline_get_parent (pipeline);
310 }
311 while (pipeline);
312 }
313
314 CoglBool
_cogl_pipeline_uniforms_state_equal(CoglPipeline * authority0,CoglPipeline * authority1)315 _cogl_pipeline_uniforms_state_equal (CoglPipeline *authority0,
316 CoglPipeline *authority1)
317 {
318 unsigned long *differences;
319 const CoglBoxedValue **values0, **values1;
320 int n_longs;
321 int i;
322
323 _COGL_GET_CONTEXT (ctx, FALSE);
324
325 if (authority0 == authority1)
326 return TRUE;
327
328 values0 = g_alloca (sizeof (const CoglBoxedValue *) * ctx->n_uniform_names);
329 values1 = g_alloca (sizeof (const CoglBoxedValue *) * ctx->n_uniform_names);
330
331 n_longs = COGL_FLAGS_N_LONGS_FOR_SIZE (ctx->n_uniform_names);
332 differences = g_alloca (n_longs * sizeof (unsigned long));
333 memset (differences, 0, sizeof (unsigned long) * n_longs);
334 _cogl_pipeline_compare_uniform_differences (differences,
335 authority0,
336 authority1);
337
338 _cogl_pipeline_get_all_uniform_values (authority0, values0);
339 _cogl_pipeline_get_all_uniform_values (authority1, values1);
340
341 COGL_FLAGS_FOREACH_START (differences, n_longs, i)
342 {
343 const CoglBoxedValue *value0 = values0[i];
344 const CoglBoxedValue *value1 = values1[i];
345
346 if (value0 == NULL)
347 {
348 if (value1 != NULL && value1->type != COGL_BOXED_NONE)
349 return FALSE;
350 }
351 else if (value1 == NULL)
352 {
353 if (value0 != NULL && value0->type != COGL_BOXED_NONE)
354 return FALSE;
355 }
356 else if (!_cogl_boxed_value_equal (value0, value1))
357 return FALSE;
358 }
359 COGL_FLAGS_FOREACH_END;
360
361 return TRUE;
362 }
363
364 CoglBool
_cogl_pipeline_vertex_snippets_state_equal(CoglPipeline * authority0,CoglPipeline * authority1)365 _cogl_pipeline_vertex_snippets_state_equal (CoglPipeline *authority0,
366 CoglPipeline *authority1)
367 {
368 return _cogl_pipeline_snippet_list_equal (&authority0->big_state->
369 vertex_snippets,
370 &authority1->big_state->
371 vertex_snippets);
372 }
373
374 CoglBool
_cogl_pipeline_fragment_snippets_state_equal(CoglPipeline * authority0,CoglPipeline * authority1)375 _cogl_pipeline_fragment_snippets_state_equal (CoglPipeline *authority0,
376 CoglPipeline *authority1)
377 {
378 return _cogl_pipeline_snippet_list_equal (&authority0->big_state->
379 fragment_snippets,
380 &authority1->big_state->
381 fragment_snippets);
382 }
383
384 void
cogl_pipeline_get_color(CoglPipeline * pipeline,CoglColor * color)385 cogl_pipeline_get_color (CoglPipeline *pipeline,
386 CoglColor *color)
387 {
388 CoglPipeline *authority;
389
390 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
391
392 authority =
393 _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR);
394
395 *color = authority->color;
396 }
397
398 /* This is used heavily by the cogl journal when logging quads */
399 void
_cogl_pipeline_get_colorubv(CoglPipeline * pipeline,uint8_t * color)400 _cogl_pipeline_get_colorubv (CoglPipeline *pipeline,
401 uint8_t *color)
402 {
403 CoglPipeline *authority =
404 _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR);
405
406 _cogl_color_get_rgba_4ubv (&authority->color, color);
407 }
408
409 void
cogl_pipeline_set_color(CoglPipeline * pipeline,const CoglColor * color)410 cogl_pipeline_set_color (CoglPipeline *pipeline,
411 const CoglColor *color)
412 {
413 CoglPipelineState state = COGL_PIPELINE_STATE_COLOR;
414 CoglPipeline *authority;
415
416 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
417
418 authority = _cogl_pipeline_get_authority (pipeline, state);
419
420 if (cogl_color_equal (color, &authority->color))
421 return;
422
423 /* - Flush journal primitives referencing the current state.
424 * - Make sure the pipeline has no dependants so it may be modified.
425 * - If the pipeline isn't currently an authority for the state being
426 * changed, then initialize that state from the current authority.
427 */
428 _cogl_pipeline_pre_change_notify (pipeline, state, color, FALSE);
429
430 pipeline->color = *color;
431
432 _cogl_pipeline_update_authority (pipeline, authority, state,
433 _cogl_pipeline_color_equal);
434
435 pipeline->dirty_real_blend_enable = TRUE;
436 }
437
438 void
cogl_pipeline_set_color4ub(CoglPipeline * pipeline,uint8_t red,uint8_t green,uint8_t blue,uint8_t alpha)439 cogl_pipeline_set_color4ub (CoglPipeline *pipeline,
440 uint8_t red,
441 uint8_t green,
442 uint8_t blue,
443 uint8_t alpha)
444 {
445 CoglColor color;
446 cogl_color_init_from_4ub (&color, red, green, blue, alpha);
447 cogl_pipeline_set_color (pipeline, &color);
448 }
449
450 void
cogl_pipeline_set_color4f(CoglPipeline * pipeline,float red,float green,float blue,float alpha)451 cogl_pipeline_set_color4f (CoglPipeline *pipeline,
452 float red,
453 float green,
454 float blue,
455 float alpha)
456 {
457 CoglColor color;
458 cogl_color_init_from_4f (&color, red, green, blue, alpha);
459 cogl_pipeline_set_color (pipeline, &color);
460 }
461
462 CoglPipelineBlendEnable
_cogl_pipeline_get_blend_enabled(CoglPipeline * pipeline)463 _cogl_pipeline_get_blend_enabled (CoglPipeline *pipeline)
464 {
465 CoglPipeline *authority;
466
467 _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE);
468
469 authority =
470 _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_BLEND_ENABLE);
471 return authority->blend_enable;
472 }
473
474 static CoglBool
_cogl_pipeline_blend_enable_equal(CoglPipeline * authority0,CoglPipeline * authority1)475 _cogl_pipeline_blend_enable_equal (CoglPipeline *authority0,
476 CoglPipeline *authority1)
477 {
478 return authority0->blend_enable == authority1->blend_enable ? TRUE : FALSE;
479 }
480
481 void
_cogl_pipeline_set_blend_enabled(CoglPipeline * pipeline,CoglPipelineBlendEnable enable)482 _cogl_pipeline_set_blend_enabled (CoglPipeline *pipeline,
483 CoglPipelineBlendEnable enable)
484 {
485 CoglPipelineState state = COGL_PIPELINE_STATE_BLEND_ENABLE;
486 CoglPipeline *authority;
487
488 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
489 _COGL_RETURN_IF_FAIL (enable > 1 &&
490 "don't pass TRUE or FALSE to _set_blend_enabled!");
491
492 authority = _cogl_pipeline_get_authority (pipeline, state);
493
494 if (authority->blend_enable == enable)
495 return;
496
497 /* - Flush journal primitives referencing the current state.
498 * - Make sure the pipeline has no dependants so it may be modified.
499 * - If the pipeline isn't currently an authority for the state being
500 * changed, then initialize that state from the current authority.
501 */
502 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
503
504 pipeline->blend_enable = enable;
505
506 _cogl_pipeline_update_authority (pipeline, authority, state,
507 _cogl_pipeline_blend_enable_equal);
508
509 pipeline->dirty_real_blend_enable = TRUE;
510 }
511
512 void
cogl_pipeline_get_ambient(CoglPipeline * pipeline,CoglColor * ambient)513 cogl_pipeline_get_ambient (CoglPipeline *pipeline,
514 CoglColor *ambient)
515 {
516 CoglPipeline *authority;
517
518 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
519
520 authority =
521 _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING);
522
523 cogl_color_init_from_4fv (ambient,
524 authority->big_state->lighting_state.ambient);
525 }
526
527 void
cogl_pipeline_set_ambient(CoglPipeline * pipeline,const CoglColor * ambient)528 cogl_pipeline_set_ambient (CoglPipeline *pipeline,
529 const CoglColor *ambient)
530 {
531 CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING;
532 CoglPipeline *authority;
533 CoglPipelineLightingState *lighting_state;
534
535 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
536
537 authority = _cogl_pipeline_get_authority (pipeline, state);
538
539 lighting_state = &authority->big_state->lighting_state;
540 if (cogl_color_equal (ambient, &lighting_state->ambient))
541 return;
542
543 /* - Flush journal primitives referencing the current state.
544 * - Make sure the pipeline has no dependants so it may be modified.
545 * - If the pipeline isn't currently an authority for the state being
546 * changed, then initialize that state from the current authority.
547 */
548 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
549
550 lighting_state = &pipeline->big_state->lighting_state;
551 lighting_state->ambient[0] = cogl_color_get_red_float (ambient);
552 lighting_state->ambient[1] = cogl_color_get_green_float (ambient);
553 lighting_state->ambient[2] = cogl_color_get_blue_float (ambient);
554 lighting_state->ambient[3] = cogl_color_get_alpha_float (ambient);
555
556 _cogl_pipeline_update_authority (pipeline, authority, state,
557 _cogl_pipeline_lighting_state_equal);
558
559 pipeline->dirty_real_blend_enable = TRUE;
560 }
561
562 void
cogl_pipeline_get_diffuse(CoglPipeline * pipeline,CoglColor * diffuse)563 cogl_pipeline_get_diffuse (CoglPipeline *pipeline,
564 CoglColor *diffuse)
565 {
566 CoglPipeline *authority;
567
568 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
569
570 authority =
571 _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING);
572
573 cogl_color_init_from_4fv (diffuse,
574 authority->big_state->lighting_state.diffuse);
575 }
576
577 void
cogl_pipeline_set_diffuse(CoglPipeline * pipeline,const CoglColor * diffuse)578 cogl_pipeline_set_diffuse (CoglPipeline *pipeline,
579 const CoglColor *diffuse)
580 {
581 CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING;
582 CoglPipeline *authority;
583 CoglPipelineLightingState *lighting_state;
584
585 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
586
587 authority = _cogl_pipeline_get_authority (pipeline, state);
588
589 lighting_state = &authority->big_state->lighting_state;
590 if (cogl_color_equal (diffuse, &lighting_state->diffuse))
591 return;
592
593 /* - Flush journal primitives referencing the current state.
594 * - Make sure the pipeline has no dependants so it may be modified.
595 * - If the pipeline isn't currently an authority for the state being
596 * changed, then initialize that state from the current authority.
597 */
598 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
599
600 lighting_state = &pipeline->big_state->lighting_state;
601 lighting_state->diffuse[0] = cogl_color_get_red_float (diffuse);
602 lighting_state->diffuse[1] = cogl_color_get_green_float (diffuse);
603 lighting_state->diffuse[2] = cogl_color_get_blue_float (diffuse);
604 lighting_state->diffuse[3] = cogl_color_get_alpha_float (diffuse);
605
606
607 _cogl_pipeline_update_authority (pipeline, authority, state,
608 _cogl_pipeline_lighting_state_equal);
609
610 pipeline->dirty_real_blend_enable = TRUE;
611 }
612
613 void
cogl_pipeline_set_ambient_and_diffuse(CoglPipeline * pipeline,const CoglColor * color)614 cogl_pipeline_set_ambient_and_diffuse (CoglPipeline *pipeline,
615 const CoglColor *color)
616 {
617 cogl_pipeline_set_ambient (pipeline, color);
618 cogl_pipeline_set_diffuse (pipeline, color);
619 }
620
621 void
cogl_pipeline_get_specular(CoglPipeline * pipeline,CoglColor * specular)622 cogl_pipeline_get_specular (CoglPipeline *pipeline,
623 CoglColor *specular)
624 {
625 CoglPipeline *authority;
626
627 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
628
629 authority =
630 _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING);
631
632 cogl_color_init_from_4fv (specular,
633 authority->big_state->lighting_state.specular);
634 }
635
636 void
cogl_pipeline_set_specular(CoglPipeline * pipeline,const CoglColor * specular)637 cogl_pipeline_set_specular (CoglPipeline *pipeline, const CoglColor *specular)
638 {
639 CoglPipeline *authority;
640 CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING;
641 CoglPipelineLightingState *lighting_state;
642
643 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
644
645 authority = _cogl_pipeline_get_authority (pipeline, state);
646
647 lighting_state = &authority->big_state->lighting_state;
648 if (cogl_color_equal (specular, &lighting_state->specular))
649 return;
650
651 /* - Flush journal primitives referencing the current state.
652 * - Make sure the pipeline has no dependants so it may be modified.
653 * - If the pipeline isn't currently an authority for the state being
654 * changed, then initialize that state from the current authority.
655 */
656 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
657
658 lighting_state = &pipeline->big_state->lighting_state;
659 lighting_state->specular[0] = cogl_color_get_red_float (specular);
660 lighting_state->specular[1] = cogl_color_get_green_float (specular);
661 lighting_state->specular[2] = cogl_color_get_blue_float (specular);
662 lighting_state->specular[3] = cogl_color_get_alpha_float (specular);
663
664 _cogl_pipeline_update_authority (pipeline, authority, state,
665 _cogl_pipeline_lighting_state_equal);
666
667 pipeline->dirty_real_blend_enable = TRUE;
668 }
669
670 float
cogl_pipeline_get_shininess(CoglPipeline * pipeline)671 cogl_pipeline_get_shininess (CoglPipeline *pipeline)
672 {
673 CoglPipeline *authority;
674
675 _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), 0);
676
677 authority =
678 _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING);
679
680 return authority->big_state->lighting_state.shininess;
681 }
682
683 void
cogl_pipeline_set_shininess(CoglPipeline * pipeline,float shininess)684 cogl_pipeline_set_shininess (CoglPipeline *pipeline,
685 float shininess)
686 {
687 CoglPipeline *authority;
688 CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING;
689 CoglPipelineLightingState *lighting_state;
690
691 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
692
693 if (shininess < 0.0)
694 {
695 g_warning ("Out of range shininess %f supplied for pipeline\n",
696 shininess);
697 return;
698 }
699
700 authority = _cogl_pipeline_get_authority (pipeline, state);
701
702 lighting_state = &authority->big_state->lighting_state;
703
704 if (lighting_state->shininess == shininess)
705 return;
706
707 /* - Flush journal primitives referencing the current state.
708 * - Make sure the pipeline has no dependants so it may be modified.
709 * - If the pipeline isn't currently an authority for the state being
710 * changed, then initialize that state from the current authority.
711 */
712 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
713
714 lighting_state = &pipeline->big_state->lighting_state;
715 lighting_state->shininess = shininess;
716
717 _cogl_pipeline_update_authority (pipeline, authority, state,
718 _cogl_pipeline_lighting_state_equal);
719 }
720
721 void
cogl_pipeline_get_emission(CoglPipeline * pipeline,CoglColor * emission)722 cogl_pipeline_get_emission (CoglPipeline *pipeline,
723 CoglColor *emission)
724 {
725 CoglPipeline *authority;
726
727 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
728
729 authority =
730 _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LIGHTING);
731
732 cogl_color_init_from_4fv (emission,
733 authority->big_state->lighting_state.emission);
734 }
735
736 void
cogl_pipeline_set_emission(CoglPipeline * pipeline,const CoglColor * emission)737 cogl_pipeline_set_emission (CoglPipeline *pipeline, const CoglColor *emission)
738 {
739 CoglPipeline *authority;
740 CoglPipelineState state = COGL_PIPELINE_STATE_LIGHTING;
741 CoglPipelineLightingState *lighting_state;
742
743 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
744
745 authority = _cogl_pipeline_get_authority (pipeline, state);
746
747 lighting_state = &authority->big_state->lighting_state;
748 if (cogl_color_equal (emission, &lighting_state->emission))
749 return;
750
751 /* - Flush journal primitives referencing the current state.
752 * - Make sure the pipeline has no dependants so it may be modified.
753 * - If the pipeline isn't currently an authority for the state being
754 * changed, then initialize that state from the current authority.
755 */
756 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
757
758 lighting_state = &pipeline->big_state->lighting_state;
759 lighting_state->emission[0] = cogl_color_get_red_float (emission);
760 lighting_state->emission[1] = cogl_color_get_green_float (emission);
761 lighting_state->emission[2] = cogl_color_get_blue_float (emission);
762 lighting_state->emission[3] = cogl_color_get_alpha_float (emission);
763
764 _cogl_pipeline_update_authority (pipeline, authority, state,
765 _cogl_pipeline_lighting_state_equal);
766
767 pipeline->dirty_real_blend_enable = TRUE;
768 }
769
770 static void
_cogl_pipeline_set_alpha_test_function(CoglPipeline * pipeline,CoglPipelineAlphaFunc alpha_func)771 _cogl_pipeline_set_alpha_test_function (CoglPipeline *pipeline,
772 CoglPipelineAlphaFunc alpha_func)
773 {
774 CoglPipelineState state = COGL_PIPELINE_STATE_ALPHA_FUNC;
775 CoglPipeline *authority;
776 CoglPipelineAlphaFuncState *alpha_state;
777
778 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
779
780 authority = _cogl_pipeline_get_authority (pipeline, state);
781
782 alpha_state = &authority->big_state->alpha_state;
783 if (alpha_state->alpha_func == alpha_func)
784 return;
785
786 /* - Flush journal primitives referencing the current state.
787 * - Make sure the pipeline has no dependants so it may be modified.
788 * - If the pipeline isn't currently an authority for the state being
789 * changed, then initialize that state from the current authority.
790 */
791 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
792
793 alpha_state = &pipeline->big_state->alpha_state;
794 alpha_state->alpha_func = alpha_func;
795
796 _cogl_pipeline_update_authority (pipeline, authority, state,
797 _cogl_pipeline_alpha_func_state_equal);
798 }
799
800 static void
_cogl_pipeline_set_alpha_test_function_reference(CoglPipeline * pipeline,float alpha_reference)801 _cogl_pipeline_set_alpha_test_function_reference (CoglPipeline *pipeline,
802 float alpha_reference)
803 {
804 CoglPipelineState state = COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE;
805 CoglPipeline *authority;
806 CoglPipelineAlphaFuncState *alpha_state;
807
808 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
809
810 authority = _cogl_pipeline_get_authority (pipeline, state);
811
812 alpha_state = &authority->big_state->alpha_state;
813 if (alpha_state->alpha_func_reference == alpha_reference)
814 return;
815
816 /* - Flush journal primitives referencing the current state.
817 * - Make sure the pipeline has no dependants so it may be modified.
818 * - If the pipeline isn't currently an authority for the state being
819 * changed, then initialize that state from the current authority.
820 */
821 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
822
823 alpha_state = &pipeline->big_state->alpha_state;
824 alpha_state->alpha_func_reference = alpha_reference;
825
826 _cogl_pipeline_update_authority
827 (pipeline, authority, state,
828 _cogl_pipeline_alpha_func_reference_state_equal);
829 }
830
831 void
cogl_pipeline_set_alpha_test_function(CoglPipeline * pipeline,CoglPipelineAlphaFunc alpha_func,float alpha_reference)832 cogl_pipeline_set_alpha_test_function (CoglPipeline *pipeline,
833 CoglPipelineAlphaFunc alpha_func,
834 float alpha_reference)
835 {
836 _cogl_pipeline_set_alpha_test_function (pipeline, alpha_func);
837 _cogl_pipeline_set_alpha_test_function_reference (pipeline, alpha_reference);
838 }
839
840 CoglPipelineAlphaFunc
cogl_pipeline_get_alpha_test_function(CoglPipeline * pipeline)841 cogl_pipeline_get_alpha_test_function (CoglPipeline *pipeline)
842 {
843 CoglPipeline *authority;
844
845 _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), 0);
846
847 authority =
848 _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_ALPHA_FUNC);
849
850 return authority->big_state->alpha_state.alpha_func;
851 }
852
853 float
cogl_pipeline_get_alpha_test_reference(CoglPipeline * pipeline)854 cogl_pipeline_get_alpha_test_reference (CoglPipeline *pipeline)
855 {
856 CoglPipeline *authority;
857
858 _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), 0.0f);
859
860 authority =
861 _cogl_pipeline_get_authority (pipeline,
862 COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE);
863
864 return authority->big_state->alpha_state.alpha_func_reference;
865 }
866
867 static GLenum
arg_to_gl_blend_factor(CoglBlendStringArgument * arg)868 arg_to_gl_blend_factor (CoglBlendStringArgument *arg)
869 {
870 if (arg->source.is_zero)
871 return GL_ZERO;
872 if (arg->factor.is_one)
873 return GL_ONE;
874 else if (arg->factor.is_src_alpha_saturate)
875 return GL_SRC_ALPHA_SATURATE;
876 else if (arg->factor.source.info->type ==
877 COGL_BLEND_STRING_COLOR_SOURCE_SRC_COLOR)
878 {
879 if (arg->factor.source.mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA)
880 {
881 if (arg->factor.source.one_minus)
882 return GL_ONE_MINUS_SRC_COLOR;
883 else
884 return GL_SRC_COLOR;
885 }
886 else
887 {
888 if (arg->factor.source.one_minus)
889 return GL_ONE_MINUS_SRC_ALPHA;
890 else
891 return GL_SRC_ALPHA;
892 }
893 }
894 else if (arg->factor.source.info->type ==
895 COGL_BLEND_STRING_COLOR_SOURCE_DST_COLOR)
896 {
897 if (arg->factor.source.mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA)
898 {
899 if (arg->factor.source.one_minus)
900 return GL_ONE_MINUS_DST_COLOR;
901 else
902 return GL_DST_COLOR;
903 }
904 else
905 {
906 if (arg->factor.source.one_minus)
907 return GL_ONE_MINUS_DST_ALPHA;
908 else
909 return GL_DST_ALPHA;
910 }
911 }
912 #if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL)
913 else if (arg->factor.source.info->type ==
914 COGL_BLEND_STRING_COLOR_SOURCE_CONSTANT)
915 {
916 if (arg->factor.source.mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA)
917 {
918 if (arg->factor.source.one_minus)
919 return GL_ONE_MINUS_CONSTANT_COLOR;
920 else
921 return GL_CONSTANT_COLOR;
922 }
923 else
924 {
925 if (arg->factor.source.one_minus)
926 return GL_ONE_MINUS_CONSTANT_ALPHA;
927 else
928 return GL_CONSTANT_ALPHA;
929 }
930 }
931 #endif
932
933 g_warning ("Unable to determine valid blend factor from blend string\n");
934 return GL_ONE;
935 }
936
937 static void
setup_blend_state(CoglBlendStringStatement * statement,GLenum * blend_equation,GLint * blend_src_factor,GLint * blend_dst_factor)938 setup_blend_state (CoglBlendStringStatement *statement,
939 GLenum *blend_equation,
940 GLint *blend_src_factor,
941 GLint *blend_dst_factor)
942 {
943 switch (statement->function->type)
944 {
945 case COGL_BLEND_STRING_FUNCTION_ADD:
946 *blend_equation = GL_FUNC_ADD;
947 break;
948 /* TODO - add more */
949 default:
950 g_warning ("Unsupported blend function given");
951 *blend_equation = GL_FUNC_ADD;
952 }
953
954 *blend_src_factor = arg_to_gl_blend_factor (&statement->args[0]);
955 *blend_dst_factor = arg_to_gl_blend_factor (&statement->args[1]);
956 }
957
958 CoglBool
cogl_pipeline_set_blend(CoglPipeline * pipeline,const char * blend_description,CoglError ** error)959 cogl_pipeline_set_blend (CoglPipeline *pipeline,
960 const char *blend_description,
961 CoglError **error)
962 {
963 CoglPipelineState state = COGL_PIPELINE_STATE_BLEND;
964 CoglPipeline *authority;
965 CoglBlendStringStatement statements[2];
966 CoglBlendStringStatement *rgb;
967 CoglBlendStringStatement *a;
968 int count;
969 CoglPipelineBlendState *blend_state;
970
971 _COGL_GET_CONTEXT (ctx, FALSE);
972
973 _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE);
974
975 count =
976 _cogl_blend_string_compile (blend_description,
977 COGL_BLEND_STRING_CONTEXT_BLENDING,
978 statements,
979 error);
980 if (!count)
981 return FALSE;
982
983 if (count == 1)
984 rgb = a = statements;
985 else
986 {
987 rgb = &statements[0];
988 a = &statements[1];
989 }
990
991 authority =
992 _cogl_pipeline_get_authority (pipeline, state);
993
994 /* - Flush journal primitives referencing the current state.
995 * - Make sure the pipeline has no dependants so it may be modified.
996 * - If the pipeline isn't currently an authority for the state being
997 * changed, then initialize that state from the current authority.
998 */
999 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
1000
1001 blend_state = &pipeline->big_state->blend_state;
1002
1003 setup_blend_state (rgb,
1004 &blend_state->blend_equation_rgb,
1005 &blend_state->blend_src_factor_rgb,
1006 &blend_state->blend_dst_factor_rgb);
1007 setup_blend_state (a,
1008 &blend_state->blend_equation_alpha,
1009 &blend_state->blend_src_factor_alpha,
1010 &blend_state->blend_dst_factor_alpha);
1011
1012 /* If we are the current authority see if we can revert to one of our
1013 * ancestors being the authority */
1014 if (pipeline == authority &&
1015 _cogl_pipeline_get_parent (authority) != NULL)
1016 {
1017 CoglPipeline *parent = _cogl_pipeline_get_parent (authority);
1018 CoglPipeline *old_authority =
1019 _cogl_pipeline_get_authority (parent, state);
1020
1021 if (_cogl_pipeline_blend_state_equal (authority, old_authority))
1022 pipeline->differences &= ~state;
1023 }
1024
1025 /* If we weren't previously the authority on this state then we need
1026 * to extended our differences mask and so it's possible that some
1027 * of our ancestry will now become redundant, so we aim to reparent
1028 * ourselves if that's true... */
1029 if (pipeline != authority)
1030 {
1031 pipeline->differences |= state;
1032 _cogl_pipeline_prune_redundant_ancestry (pipeline);
1033 }
1034
1035 pipeline->dirty_real_blend_enable = TRUE;
1036
1037 return TRUE;
1038 }
1039
1040 void
cogl_pipeline_set_blend_constant(CoglPipeline * pipeline,const CoglColor * constant_color)1041 cogl_pipeline_set_blend_constant (CoglPipeline *pipeline,
1042 const CoglColor *constant_color)
1043 {
1044 _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1045
1046 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
1047
1048 if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_BLEND_CONSTANT))
1049 return;
1050
1051 #if defined(HAVE_COGL_GLES2) || defined(HAVE_COGL_GL)
1052 {
1053 CoglPipelineState state = COGL_PIPELINE_STATE_BLEND;
1054 CoglPipeline *authority;
1055 CoglPipelineBlendState *blend_state;
1056
1057 authority = _cogl_pipeline_get_authority (pipeline, state);
1058
1059 blend_state = &authority->big_state->blend_state;
1060 if (cogl_color_equal (constant_color, &blend_state->blend_constant))
1061 return;
1062
1063 /* - Flush journal primitives referencing the current state.
1064 * - Make sure the pipeline has no dependants so it may be modified.
1065 * - If the pipeline isn't currently an authority for the state being
1066 * changed, then initialize that state from the current authority.
1067 */
1068 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
1069
1070 blend_state = &pipeline->big_state->blend_state;
1071 blend_state->blend_constant = *constant_color;
1072
1073 _cogl_pipeline_update_authority (pipeline, authority, state,
1074 _cogl_pipeline_blend_state_equal);
1075
1076 pipeline->dirty_real_blend_enable = TRUE;
1077 }
1078 #endif
1079 }
1080
1081 CoglHandle
cogl_pipeline_get_user_program(CoglPipeline * pipeline)1082 cogl_pipeline_get_user_program (CoglPipeline *pipeline)
1083 {
1084 CoglPipeline *authority;
1085
1086 _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), COGL_INVALID_HANDLE);
1087
1088 authority =
1089 _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_USER_SHADER);
1090
1091 return authority->big_state->user_program;
1092 }
1093
1094 /* XXX: for now we don't mind if the program has vertex shaders
1095 * attached but if we ever make a similar API public we should only
1096 * allow attaching of programs containing fragment shaders. Eventually
1097 * we will have a CoglPipeline abstraction to also cover vertex
1098 * processing.
1099 */
1100 void
cogl_pipeline_set_user_program(CoglPipeline * pipeline,CoglHandle program)1101 cogl_pipeline_set_user_program (CoglPipeline *pipeline,
1102 CoglHandle program)
1103 {
1104 CoglPipelineState state = COGL_PIPELINE_STATE_USER_SHADER;
1105 CoglPipeline *authority;
1106
1107 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
1108
1109 authority = _cogl_pipeline_get_authority (pipeline, state);
1110
1111 if (authority->big_state->user_program == program)
1112 return;
1113
1114 /* - Flush journal primitives referencing the current state.
1115 * - Make sure the pipeline has no dependants so it may be modified.
1116 * - If the pipeline isn't currently an authority for the state being
1117 * changed, then initialize that state from the current authority.
1118 */
1119 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
1120
1121 if (program != COGL_INVALID_HANDLE)
1122 _cogl_pipeline_set_progend (pipeline, COGL_PIPELINE_PROGEND_UNDEFINED);
1123
1124 /* If we are the current authority see if we can revert to one of our
1125 * ancestors being the authority */
1126 if (pipeline == authority &&
1127 _cogl_pipeline_get_parent (authority) != NULL)
1128 {
1129 CoglPipeline *parent = _cogl_pipeline_get_parent (authority);
1130 CoglPipeline *old_authority =
1131 _cogl_pipeline_get_authority (parent, state);
1132
1133 if (old_authority->big_state->user_program == program)
1134 pipeline->differences &= ~state;
1135 }
1136 else if (pipeline != authority)
1137 {
1138 /* If we weren't previously the authority on this state then we
1139 * need to extended our differences mask and so it's possible
1140 * that some of our ancestry will now become redundant, so we
1141 * aim to reparent ourselves if that's true... */
1142 pipeline->differences |= state;
1143 _cogl_pipeline_prune_redundant_ancestry (pipeline);
1144 }
1145
1146 if (program != COGL_INVALID_HANDLE)
1147 cogl_handle_ref (program);
1148 if (authority == pipeline &&
1149 pipeline->big_state->user_program != COGL_INVALID_HANDLE)
1150 cogl_handle_unref (pipeline->big_state->user_program);
1151 pipeline->big_state->user_program = program;
1152
1153 pipeline->dirty_real_blend_enable = TRUE;
1154 }
1155
1156 CoglBool
cogl_pipeline_set_depth_state(CoglPipeline * pipeline,const CoglDepthState * depth_state,CoglError ** error)1157 cogl_pipeline_set_depth_state (CoglPipeline *pipeline,
1158 const CoglDepthState *depth_state,
1159 CoglError **error)
1160 {
1161 CoglPipelineState state = COGL_PIPELINE_STATE_DEPTH;
1162 CoglPipeline *authority;
1163 CoglDepthState *orig_state;
1164
1165 _COGL_GET_CONTEXT (ctx, FALSE);
1166
1167 _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE);
1168 _COGL_RETURN_VAL_IF_FAIL (depth_state->magic == COGL_DEPTH_STATE_MAGIC, FALSE);
1169
1170 authority = _cogl_pipeline_get_authority (pipeline, state);
1171
1172 orig_state = &authority->big_state->depth_state;
1173 if (orig_state->test_enabled == depth_state->test_enabled &&
1174 orig_state->write_enabled == depth_state->write_enabled &&
1175 orig_state->test_function == depth_state->test_function &&
1176 orig_state->range_near == depth_state->range_near &&
1177 orig_state->range_far == depth_state->range_far)
1178 return TRUE;
1179
1180 if (ctx->driver == COGL_DRIVER_GLES1 &&
1181 (depth_state->range_near != 0 ||
1182 depth_state->range_far != 1))
1183 {
1184 _cogl_set_error (error,
1185 COGL_SYSTEM_ERROR,
1186 COGL_SYSTEM_ERROR_UNSUPPORTED,
1187 "glDepthRange not available on GLES 1");
1188 return FALSE;
1189 }
1190
1191 /* - Flush journal primitives referencing the current state.
1192 * - Make sure the pipeline has no dependants so it may be modified.
1193 * - If the pipeline isn't currently an authority for the state being
1194 * changed, then initialize that state from the current authority.
1195 */
1196 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
1197
1198 pipeline->big_state->depth_state = *depth_state;
1199
1200 _cogl_pipeline_update_authority (pipeline, authority, state,
1201 _cogl_pipeline_depth_state_equal);
1202
1203 return TRUE;
1204 }
1205
1206 void
cogl_pipeline_get_depth_state(CoglPipeline * pipeline,CoglDepthState * state)1207 cogl_pipeline_get_depth_state (CoglPipeline *pipeline,
1208 CoglDepthState *state)
1209 {
1210 CoglPipeline *authority;
1211
1212 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
1213
1214 authority =
1215 _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_DEPTH);
1216 *state = authority->big_state->depth_state;
1217 }
1218
1219 CoglColorMask
cogl_pipeline_get_color_mask(CoglPipeline * pipeline)1220 cogl_pipeline_get_color_mask (CoglPipeline *pipeline)
1221 {
1222 CoglPipeline *authority;
1223
1224 _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), 0);
1225
1226 authority =
1227 _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LOGIC_OPS);
1228
1229 return authority->big_state->logic_ops_state.color_mask;
1230 }
1231
1232 void
cogl_pipeline_set_color_mask(CoglPipeline * pipeline,CoglColorMask color_mask)1233 cogl_pipeline_set_color_mask (CoglPipeline *pipeline,
1234 CoglColorMask color_mask)
1235 {
1236 CoglPipelineState state = COGL_PIPELINE_STATE_LOGIC_OPS;
1237 CoglPipeline *authority;
1238 CoglPipelineLogicOpsState *logic_ops_state;
1239
1240 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
1241
1242 authority = _cogl_pipeline_get_authority (pipeline, state);
1243
1244 logic_ops_state = &authority->big_state->logic_ops_state;
1245 if (logic_ops_state->color_mask == color_mask)
1246 return;
1247
1248 /* - Flush journal primitives referencing the current state.
1249 * - Make sure the pipeline has no dependants so it may be modified.
1250 * - If the pipeline isn't currently an authority for the state being
1251 * changed, then initialize that state from the current authority.
1252 */
1253 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
1254
1255 logic_ops_state = &pipeline->big_state->logic_ops_state;
1256 logic_ops_state->color_mask = color_mask;
1257
1258 _cogl_pipeline_update_authority (pipeline, authority, state,
1259 _cogl_pipeline_logic_ops_state_equal);
1260 }
1261
1262 void
_cogl_pipeline_set_fog_state(CoglPipeline * pipeline,const CoglPipelineFogState * fog_state)1263 _cogl_pipeline_set_fog_state (CoglPipeline *pipeline,
1264 const CoglPipelineFogState *fog_state)
1265 {
1266 CoglPipelineState state = COGL_PIPELINE_STATE_FOG;
1267 CoglPipeline *authority;
1268 CoglPipelineFogState *current_fog_state;
1269
1270 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
1271
1272 authority = _cogl_pipeline_get_authority (pipeline, state);
1273
1274 current_fog_state = &authority->big_state->fog_state;
1275
1276 if (current_fog_state->enabled == fog_state->enabled &&
1277 cogl_color_equal (¤t_fog_state->color, &fog_state->color) &&
1278 current_fog_state->mode == fog_state->mode &&
1279 current_fog_state->density == fog_state->density &&
1280 current_fog_state->z_near == fog_state->z_near &&
1281 current_fog_state->z_far == fog_state->z_far)
1282 return;
1283
1284 /* - Flush journal primitives referencing the current state.
1285 * - Make sure the pipeline has no dependants so it may be modified.
1286 * - If the pipeline isn't currently an authority for the state being
1287 * changed, then initialize that state from the current authority.
1288 */
1289 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
1290
1291 pipeline->big_state->fog_state = *fog_state;
1292
1293 _cogl_pipeline_update_authority (pipeline, authority, state,
1294 _cogl_pipeline_fog_state_equal);
1295 }
1296
1297 void
cogl_pipeline_set_cull_face_mode(CoglPipeline * pipeline,CoglPipelineCullFaceMode cull_face_mode)1298 cogl_pipeline_set_cull_face_mode (CoglPipeline *pipeline,
1299 CoglPipelineCullFaceMode cull_face_mode)
1300 {
1301 CoglPipelineState state = COGL_PIPELINE_STATE_CULL_FACE;
1302 CoglPipeline *authority;
1303 CoglPipelineCullFaceState *cull_face_state;
1304
1305 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
1306
1307 authority = _cogl_pipeline_get_authority (pipeline, state);
1308
1309 cull_face_state = &authority->big_state->cull_face_state;
1310
1311 if (cull_face_state->mode == cull_face_mode)
1312 return;
1313
1314 /* - Flush journal primitives referencing the current state.
1315 * - Make sure the pipeline has no dependants so it may be modified.
1316 * - If the pipeline isn't currently an authority for the state being
1317 * changed, then initialize that state from the current authority.
1318 */
1319 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
1320
1321 pipeline->big_state->cull_face_state.mode = cull_face_mode;
1322
1323 _cogl_pipeline_update_authority (pipeline, authority, state,
1324 _cogl_pipeline_cull_face_state_equal);
1325 }
1326
1327 void
cogl_pipeline_set_front_face_winding(CoglPipeline * pipeline,CoglWinding front_winding)1328 cogl_pipeline_set_front_face_winding (CoglPipeline *pipeline,
1329 CoglWinding front_winding)
1330 {
1331 CoglPipelineState state = COGL_PIPELINE_STATE_CULL_FACE;
1332 CoglPipeline *authority;
1333 CoglPipelineCullFaceState *cull_face_state;
1334
1335 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
1336
1337 authority = _cogl_pipeline_get_authority (pipeline, state);
1338
1339 cull_face_state = &authority->big_state->cull_face_state;
1340
1341 if (cull_face_state->front_winding == front_winding)
1342 return;
1343
1344 /* - Flush journal primitives referencing the current state.
1345 * - Make sure the pipeline has no dependants so it may be modified.
1346 * - If the pipeline isn't currently an authority for the state being
1347 * changed, then initialize that state from the current authority.
1348 */
1349 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
1350
1351 pipeline->big_state->cull_face_state.front_winding = front_winding;
1352
1353 _cogl_pipeline_update_authority (pipeline, authority, state,
1354 _cogl_pipeline_cull_face_state_equal);
1355 }
1356
1357 CoglPipelineCullFaceMode
cogl_pipeline_get_cull_face_mode(CoglPipeline * pipeline)1358 cogl_pipeline_get_cull_face_mode (CoglPipeline *pipeline)
1359 {
1360 CoglPipelineState state = COGL_PIPELINE_STATE_CULL_FACE;
1361 CoglPipeline *authority;
1362
1363 _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline),
1364 COGL_PIPELINE_CULL_FACE_MODE_NONE);
1365
1366 authority = _cogl_pipeline_get_authority (pipeline, state);
1367
1368 return authority->big_state->cull_face_state.mode;
1369 }
1370
1371 CoglWinding
cogl_pipeline_get_front_face_winding(CoglPipeline * pipeline)1372 cogl_pipeline_get_front_face_winding (CoglPipeline *pipeline)
1373 {
1374 CoglPipelineState state = COGL_PIPELINE_STATE_CULL_FACE;
1375 CoglPipeline *authority;
1376
1377 _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline),
1378 COGL_PIPELINE_CULL_FACE_MODE_NONE);
1379
1380 authority = _cogl_pipeline_get_authority (pipeline, state);
1381
1382 return authority->big_state->cull_face_state.front_winding;
1383 }
1384
1385 float
cogl_pipeline_get_point_size(CoglPipeline * pipeline)1386 cogl_pipeline_get_point_size (CoglPipeline *pipeline)
1387 {
1388 CoglPipeline *authority;
1389
1390 _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE);
1391
1392 authority =
1393 _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_POINT_SIZE);
1394
1395 return authority->big_state->point_size;
1396 }
1397
1398 static void
_cogl_pipeline_set_non_zero_point_size(CoglPipeline * pipeline,CoglBool value)1399 _cogl_pipeline_set_non_zero_point_size (CoglPipeline *pipeline,
1400 CoglBool value)
1401 {
1402 CoglPipelineState state = COGL_PIPELINE_STATE_NON_ZERO_POINT_SIZE;
1403 CoglPipeline *authority;
1404
1405 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
1406
1407 authority = _cogl_pipeline_get_authority (pipeline, state);
1408
1409 /* - Flush journal primitives referencing the current state.
1410 * - Make sure the pipeline has no dependants so it may be modified.
1411 * - If the pipeline isn't currently an authority for the state being
1412 * changed, then initialize that state from the current authority.
1413 */
1414 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
1415
1416 pipeline->big_state->non_zero_point_size = !!value;
1417
1418 _cogl_pipeline_update_authority (pipeline, authority, state,
1419 _cogl_pipeline_non_zero_point_size_equal);
1420 }
1421
1422 void
cogl_pipeline_set_point_size(CoglPipeline * pipeline,float point_size)1423 cogl_pipeline_set_point_size (CoglPipeline *pipeline,
1424 float point_size)
1425 {
1426 CoglPipelineState state = COGL_PIPELINE_STATE_POINT_SIZE;
1427 CoglPipeline *authority;
1428
1429 _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
1430
1431 authority = _cogl_pipeline_get_authority (pipeline, state);
1432
1433 if (authority->big_state->point_size == point_size)
1434 return;
1435
1436 /* Changing the point size may additionally modify
1437 * COGL_PIPELINE_STATE_NON_ZERO_POINT_SIZE. */
1438
1439 if ((authority->big_state->point_size > 0.0f) != (point_size > 0.0f))
1440 _cogl_pipeline_set_non_zero_point_size (pipeline, point_size > 0.0f);
1441
1442 /* - Flush journal primitives referencing the current state.
1443 * - Make sure the pipeline has no dependants so it may be modified.
1444 * - If the pipeline isn't currently an authority for the state being
1445 * changed, then initialize that state from the current authority.
1446 */
1447 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
1448
1449 pipeline->big_state->point_size = point_size;
1450
1451 _cogl_pipeline_update_authority (pipeline, authority, state,
1452 _cogl_pipeline_point_size_equal);
1453 }
1454
1455 CoglBool
cogl_pipeline_set_per_vertex_point_size(CoglPipeline * pipeline,CoglBool enable,CoglError ** error)1456 cogl_pipeline_set_per_vertex_point_size (CoglPipeline *pipeline,
1457 CoglBool enable,
1458 CoglError **error)
1459 {
1460 CoglPipelineState state = COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE;
1461 CoglPipeline *authority;
1462
1463 _COGL_GET_CONTEXT (ctx, FALSE);
1464 _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE);
1465
1466 authority = _cogl_pipeline_get_authority (pipeline, state);
1467
1468 enable = !!enable;
1469
1470 if (authority->big_state->per_vertex_point_size == enable)
1471 return TRUE;
1472
1473 if (enable && !cogl_has_feature (ctx, COGL_FEATURE_ID_PER_VERTEX_POINT_SIZE))
1474 {
1475 _cogl_set_error (error,
1476 COGL_SYSTEM_ERROR,
1477 COGL_SYSTEM_ERROR_UNSUPPORTED,
1478 "Per-vertex point size is not supported");
1479
1480 return FALSE;
1481 }
1482
1483 /* - Flush journal primitives referencing the current state.
1484 * - Make sure the pipeline has no dependants so it may be modified.
1485 * - If the pipeline isn't currently an authority for the state being
1486 * changed, then initialize that state from the current authority.
1487 */
1488 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
1489
1490 pipeline->big_state->per_vertex_point_size = enable;
1491
1492 _cogl_pipeline_update_authority (pipeline, authority, state,
1493 _cogl_pipeline_point_size_equal);
1494
1495 return TRUE;
1496 }
1497
1498 CoglBool
cogl_pipeline_get_per_vertex_point_size(CoglPipeline * pipeline)1499 cogl_pipeline_get_per_vertex_point_size (CoglPipeline *pipeline)
1500 {
1501 CoglPipeline *authority;
1502
1503 _COGL_RETURN_VAL_IF_FAIL (cogl_is_pipeline (pipeline), FALSE);
1504
1505 authority =
1506 _cogl_pipeline_get_authority (pipeline,
1507 COGL_PIPELINE_STATE_PER_VERTEX_POINT_SIZE);
1508
1509 return authority->big_state->per_vertex_point_size;
1510 }
1511
1512 static CoglBoxedValue *
_cogl_pipeline_override_uniform(CoglPipeline * pipeline,int location)1513 _cogl_pipeline_override_uniform (CoglPipeline *pipeline,
1514 int location)
1515 {
1516 CoglPipelineState state = COGL_PIPELINE_STATE_UNIFORMS;
1517 CoglPipelineUniformsState *uniforms_state;
1518 int override_index;
1519
1520 _COGL_GET_CONTEXT (ctx, NULL);
1521
1522 g_return_val_if_fail (cogl_is_pipeline (pipeline), NULL);
1523 g_return_val_if_fail (location >= 0, NULL);
1524 g_return_val_if_fail (location < ctx->n_uniform_names, NULL);
1525
1526 /* - Flush journal primitives referencing the current state.
1527 * - Make sure the pipeline has no dependants so it may be modified.
1528 * - If the pipeline isn't currently an authority for the state being
1529 * changed, then initialize that state from the current authority.
1530 */
1531 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
1532
1533 uniforms_state = &pipeline->big_state->uniforms_state;
1534
1535 /* Count the number of bits that are set below this location. That
1536 should give us the position where our new value should lie */
1537 override_index = _cogl_bitmask_popcount_upto (&uniforms_state->override_mask,
1538 location);
1539
1540 _cogl_bitmask_set (&uniforms_state->changed_mask, location, TRUE);
1541
1542 /* If this pipeline already has an override for this value then we
1543 can just use it directly */
1544 if (_cogl_bitmask_get (&uniforms_state->override_mask, location))
1545 return uniforms_state->override_values + override_index;
1546
1547 /* We need to create a new override value in the right position
1548 within the array. This is pretty inefficient but the hope is that
1549 it will be much more common to modify an existing uniform rather
1550 than modify a new one so it is more important to optimise the
1551 former case. */
1552
1553 if (uniforms_state->override_values == NULL)
1554 {
1555 g_assert (override_index == 0);
1556 uniforms_state->override_values = g_new (CoglBoxedValue, 1);
1557 }
1558 else
1559 {
1560 /* We need to grow the array and copy in the old values */
1561 CoglBoxedValue *old_values = uniforms_state->override_values;
1562 int old_size = _cogl_bitmask_popcount (&uniforms_state->override_mask);
1563
1564 uniforms_state->override_values = g_new (CoglBoxedValue, old_size + 1);
1565
1566 /* Copy in the old values leaving a gap for the new value */
1567 memcpy (uniforms_state->override_values,
1568 old_values,
1569 sizeof (CoglBoxedValue) * override_index);
1570 memcpy (uniforms_state->override_values + override_index + 1,
1571 old_values + override_index,
1572 sizeof (CoglBoxedValue) * (old_size - override_index));
1573
1574 free (old_values);
1575 }
1576
1577 _cogl_boxed_value_init (uniforms_state->override_values + override_index);
1578
1579 _cogl_bitmask_set (&uniforms_state->override_mask, location, TRUE);
1580
1581 return uniforms_state->override_values + override_index;
1582 }
1583
1584 void
cogl_pipeline_set_uniform_1f(CoglPipeline * pipeline,int uniform_location,float value)1585 cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline,
1586 int uniform_location,
1587 float value)
1588 {
1589 CoglBoxedValue *boxed_value;
1590
1591 boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location);
1592
1593 _cogl_boxed_value_set_1f (boxed_value, value);
1594 }
1595
1596 void
cogl_pipeline_set_uniform_1i(CoglPipeline * pipeline,int uniform_location,int value)1597 cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline,
1598 int uniform_location,
1599 int value)
1600 {
1601 CoglBoxedValue *boxed_value;
1602
1603 boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location);
1604
1605 _cogl_boxed_value_set_1i (boxed_value, value);
1606 }
1607
1608 void
cogl_pipeline_set_uniform_float(CoglPipeline * pipeline,int uniform_location,int n_components,int count,const float * value)1609 cogl_pipeline_set_uniform_float (CoglPipeline *pipeline,
1610 int uniform_location,
1611 int n_components,
1612 int count,
1613 const float *value)
1614 {
1615 CoglBoxedValue *boxed_value;
1616
1617 boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location);
1618
1619 _cogl_boxed_value_set_float (boxed_value, n_components, count, value);
1620 }
1621
1622 void
cogl_pipeline_set_uniform_int(CoglPipeline * pipeline,int uniform_location,int n_components,int count,const int * value)1623 cogl_pipeline_set_uniform_int (CoglPipeline *pipeline,
1624 int uniform_location,
1625 int n_components,
1626 int count,
1627 const int *value)
1628 {
1629 CoglBoxedValue *boxed_value;
1630
1631 boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location);
1632
1633 _cogl_boxed_value_set_int (boxed_value, n_components, count, value);
1634 }
1635
1636 void
cogl_pipeline_set_uniform_matrix(CoglPipeline * pipeline,int uniform_location,int dimensions,int count,CoglBool transpose,const float * value)1637 cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline,
1638 int uniform_location,
1639 int dimensions,
1640 int count,
1641 CoglBool transpose,
1642 const float *value)
1643 {
1644 CoglBoxedValue *boxed_value;
1645
1646 boxed_value = _cogl_pipeline_override_uniform (pipeline, uniform_location);
1647
1648 _cogl_boxed_value_set_matrix (boxed_value,
1649 dimensions,
1650 count,
1651 transpose,
1652 value);
1653 }
1654
1655 static void
_cogl_pipeline_add_vertex_snippet(CoglPipeline * pipeline,CoglSnippet * snippet)1656 _cogl_pipeline_add_vertex_snippet (CoglPipeline *pipeline,
1657 CoglSnippet *snippet)
1658 {
1659 CoglPipelineState state = COGL_PIPELINE_STATE_VERTEX_SNIPPETS;
1660
1661 /* - Flush journal primitives referencing the current state.
1662 * - Make sure the pipeline has no dependants so it may be modified.
1663 * - If the pipeline isn't currently an authority for the state being
1664 * changed, then initialize that state from the current authority.
1665 */
1666 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
1667
1668 _cogl_pipeline_snippet_list_add (&pipeline->big_state->vertex_snippets,
1669 snippet);
1670 }
1671
1672 static void
_cogl_pipeline_add_fragment_snippet(CoglPipeline * pipeline,CoglSnippet * snippet)1673 _cogl_pipeline_add_fragment_snippet (CoglPipeline *pipeline,
1674 CoglSnippet *snippet)
1675 {
1676 CoglPipelineState state = COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS;
1677
1678 /* - Flush journal primitives referencing the current state.
1679 * - Make sure the pipeline has no dependants so it may be modified.
1680 * - If the pipeline isn't currently an authority for the state being
1681 * changed, then initialize that state from the current authority.
1682 */
1683 _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
1684
1685 _cogl_pipeline_snippet_list_add (&pipeline->big_state->fragment_snippets,
1686 snippet);
1687 }
1688
1689 void
cogl_pipeline_add_snippet(CoglPipeline * pipeline,CoglSnippet * snippet)1690 cogl_pipeline_add_snippet (CoglPipeline *pipeline,
1691 CoglSnippet *snippet)
1692 {
1693 g_return_if_fail (cogl_is_pipeline (pipeline));
1694 g_return_if_fail (cogl_is_snippet (snippet));
1695 g_return_if_fail (snippet->hook < COGL_SNIPPET_FIRST_LAYER_HOOK);
1696
1697 if (snippet->hook < COGL_SNIPPET_FIRST_PIPELINE_FRAGMENT_HOOK)
1698 _cogl_pipeline_add_vertex_snippet (pipeline, snippet);
1699 else
1700 _cogl_pipeline_add_fragment_snippet (pipeline, snippet);
1701 }
1702
1703 CoglBool
_cogl_pipeline_has_non_layer_vertex_snippets(CoglPipeline * pipeline)1704 _cogl_pipeline_has_non_layer_vertex_snippets (CoglPipeline *pipeline)
1705 {
1706 CoglPipeline *authority =
1707 _cogl_pipeline_get_authority (pipeline,
1708 COGL_PIPELINE_STATE_VERTEX_SNIPPETS);
1709
1710 return authority->big_state->vertex_snippets.entries != NULL;
1711 }
1712
1713 static CoglBool
check_layer_has_vertex_snippet(CoglPipelineLayer * layer,void * user_data)1714 check_layer_has_vertex_snippet (CoglPipelineLayer *layer,
1715 void *user_data)
1716 {
1717 unsigned long state = COGL_PIPELINE_LAYER_STATE_VERTEX_SNIPPETS;
1718 CoglPipelineLayer *authority =
1719 _cogl_pipeline_layer_get_authority (layer, state);
1720 CoglBool *found_vertex_snippet = user_data;
1721
1722 if (authority->big_state->vertex_snippets.entries)
1723 {
1724 *found_vertex_snippet = TRUE;
1725 return FALSE;
1726 }
1727
1728 return TRUE;
1729 }
1730
1731 CoglBool
_cogl_pipeline_has_vertex_snippets(CoglPipeline * pipeline)1732 _cogl_pipeline_has_vertex_snippets (CoglPipeline *pipeline)
1733 {
1734 CoglBool found_vertex_snippet = FALSE;
1735
1736 if (_cogl_pipeline_has_non_layer_vertex_snippets (pipeline))
1737 return TRUE;
1738
1739 _cogl_pipeline_foreach_layer_internal (pipeline,
1740 check_layer_has_vertex_snippet,
1741 &found_vertex_snippet);
1742
1743 return found_vertex_snippet;
1744 }
1745
1746 CoglBool
_cogl_pipeline_has_non_layer_fragment_snippets(CoglPipeline * pipeline)1747 _cogl_pipeline_has_non_layer_fragment_snippets (CoglPipeline *pipeline)
1748 {
1749 CoglPipeline *authority =
1750 _cogl_pipeline_get_authority (pipeline,
1751 COGL_PIPELINE_STATE_FRAGMENT_SNIPPETS);
1752
1753 return authority->big_state->fragment_snippets.entries != NULL;
1754 }
1755
1756 static CoglBool
check_layer_has_fragment_snippet(CoglPipelineLayer * layer,void * user_data)1757 check_layer_has_fragment_snippet (CoglPipelineLayer *layer,
1758 void *user_data)
1759 {
1760 unsigned long state = COGL_PIPELINE_LAYER_STATE_FRAGMENT_SNIPPETS;
1761 CoglPipelineLayer *authority =
1762 _cogl_pipeline_layer_get_authority (layer, state);
1763 CoglBool *found_fragment_snippet = user_data;
1764
1765 if (authority->big_state->fragment_snippets.entries)
1766 {
1767 *found_fragment_snippet = TRUE;
1768 return FALSE;
1769 }
1770
1771 return TRUE;
1772 }
1773
1774 CoglBool
_cogl_pipeline_has_fragment_snippets(CoglPipeline * pipeline)1775 _cogl_pipeline_has_fragment_snippets (CoglPipeline *pipeline)
1776 {
1777 CoglBool found_fragment_snippet = FALSE;
1778
1779 if (_cogl_pipeline_has_non_layer_fragment_snippets (pipeline))
1780 return TRUE;
1781
1782 _cogl_pipeline_foreach_layer_internal (pipeline,
1783 check_layer_has_fragment_snippet,
1784 &found_fragment_snippet);
1785
1786 return found_fragment_snippet;
1787 }
1788
1789 void
_cogl_pipeline_hash_color_state(CoglPipeline * authority,CoglPipelineHashState * state)1790 _cogl_pipeline_hash_color_state (CoglPipeline *authority,
1791 CoglPipelineHashState *state)
1792 {
1793 state->hash = _cogl_util_one_at_a_time_hash (state->hash, &authority->color,
1794 _COGL_COLOR_DATA_SIZE);
1795 }
1796
1797 void
_cogl_pipeline_hash_blend_enable_state(CoglPipeline * authority,CoglPipelineHashState * state)1798 _cogl_pipeline_hash_blend_enable_state (CoglPipeline *authority,
1799 CoglPipelineHashState *state)
1800 {
1801 uint8_t blend_enable = authority->blend_enable;
1802 state->hash = _cogl_util_one_at_a_time_hash (state->hash, &blend_enable, 1);
1803 }
1804
1805 void
_cogl_pipeline_hash_lighting_state(CoglPipeline * authority,CoglPipelineHashState * state)1806 _cogl_pipeline_hash_lighting_state (CoglPipeline *authority,
1807 CoglPipelineHashState *state)
1808 {
1809 CoglPipelineLightingState *lighting_state =
1810 &authority->big_state->lighting_state;
1811 state->hash =
1812 _cogl_util_one_at_a_time_hash (state->hash, lighting_state,
1813 sizeof (CoglPipelineLightingState));
1814 }
1815
1816 void
_cogl_pipeline_hash_alpha_func_state(CoglPipeline * authority,CoglPipelineHashState * state)1817 _cogl_pipeline_hash_alpha_func_state (CoglPipeline *authority,
1818 CoglPipelineHashState *state)
1819 {
1820 CoglPipelineAlphaFuncState *alpha_state = &authority->big_state->alpha_state;
1821 state->hash =
1822 _cogl_util_one_at_a_time_hash (state->hash, &alpha_state->alpha_func,
1823 sizeof (alpha_state->alpha_func));
1824 }
1825
1826 void
_cogl_pipeline_hash_alpha_func_reference_state(CoglPipeline * authority,CoglPipelineHashState * state)1827 _cogl_pipeline_hash_alpha_func_reference_state (CoglPipeline *authority,
1828 CoglPipelineHashState *state)
1829 {
1830 CoglPipelineAlphaFuncState *alpha_state = &authority->big_state->alpha_state;
1831 float ref = alpha_state->alpha_func_reference;
1832 state->hash =
1833 _cogl_util_one_at_a_time_hash (state->hash, &ref, sizeof (float));
1834 }
1835
1836 void
_cogl_pipeline_hash_blend_state(CoglPipeline * authority,CoglPipelineHashState * state)1837 _cogl_pipeline_hash_blend_state (CoglPipeline *authority,
1838 CoglPipelineHashState *state)
1839 {
1840 CoglPipelineBlendState *blend_state = &authority->big_state->blend_state;
1841 unsigned int hash;
1842
1843 _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1844
1845 if (!authority->real_blend_enable)
1846 return;
1847
1848 hash = state->hash;
1849
1850 hash =
1851 _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_equation_rgb,
1852 sizeof (blend_state->blend_equation_rgb));
1853 hash =
1854 _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_equation_alpha,
1855 sizeof (blend_state->blend_equation_alpha));
1856 hash =
1857 _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_src_factor_alpha,
1858 sizeof (blend_state->blend_src_factor_alpha));
1859 hash =
1860 _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_dst_factor_alpha,
1861 sizeof (blend_state->blend_dst_factor_alpha));
1862
1863 if (blend_state->blend_src_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR ||
1864 blend_state->blend_src_factor_rgb == GL_CONSTANT_COLOR ||
1865 blend_state->blend_dst_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR ||
1866 blend_state->blend_dst_factor_rgb == GL_CONSTANT_COLOR)
1867 {
1868 hash =
1869 _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_constant,
1870 sizeof (blend_state->blend_constant));
1871 }
1872
1873 hash =
1874 _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_src_factor_rgb,
1875 sizeof (blend_state->blend_src_factor_rgb));
1876 hash =
1877 _cogl_util_one_at_a_time_hash (hash, &blend_state->blend_dst_factor_rgb,
1878 sizeof (blend_state->blend_dst_factor_rgb));
1879
1880 state->hash = hash;
1881 }
1882
1883 void
_cogl_pipeline_hash_user_shader_state(CoglPipeline * authority,CoglPipelineHashState * state)1884 _cogl_pipeline_hash_user_shader_state (CoglPipeline *authority,
1885 CoglPipelineHashState *state)
1886 {
1887 CoglHandle user_program = authority->big_state->user_program;
1888 state->hash = _cogl_util_one_at_a_time_hash (state->hash, &user_program,
1889 sizeof (user_program));
1890 }
1891
1892 void
_cogl_pipeline_hash_depth_state(CoglPipeline * authority,CoglPipelineHashState * state)1893 _cogl_pipeline_hash_depth_state (CoglPipeline *authority,
1894 CoglPipelineHashState *state)
1895 {
1896 CoglDepthState *depth_state = &authority->big_state->depth_state;
1897 unsigned int hash = state->hash;
1898
1899 if (depth_state->test_enabled)
1900 {
1901 uint8_t enabled = depth_state->test_enabled;
1902 CoglDepthTestFunction function = depth_state->test_function;
1903 hash = _cogl_util_one_at_a_time_hash (hash, &enabled, sizeof (enabled));
1904 hash = _cogl_util_one_at_a_time_hash (hash, &function, sizeof (function));
1905 }
1906
1907 if (depth_state->write_enabled)
1908 {
1909 uint8_t enabled = depth_state->write_enabled;
1910 float near_val = depth_state->range_near;
1911 float far_val = depth_state->range_far;
1912 hash = _cogl_util_one_at_a_time_hash (hash, &enabled, sizeof (enabled));
1913 hash = _cogl_util_one_at_a_time_hash (hash, &near_val, sizeof (near_val));
1914 hash = _cogl_util_one_at_a_time_hash (hash, &far_val, sizeof (far_val));
1915 }
1916
1917 state->hash = hash;
1918 }
1919
1920 void
_cogl_pipeline_hash_fog_state(CoglPipeline * authority,CoglPipelineHashState * state)1921 _cogl_pipeline_hash_fog_state (CoglPipeline *authority,
1922 CoglPipelineHashState *state)
1923 {
1924 CoglPipelineFogState *fog_state = &authority->big_state->fog_state;
1925 unsigned long hash = state->hash;
1926
1927 if (!fog_state->enabled)
1928 hash = _cogl_util_one_at_a_time_hash (hash, &fog_state->enabled,
1929 sizeof (fog_state->enabled));
1930 else
1931 hash = _cogl_util_one_at_a_time_hash (hash, &fog_state,
1932 sizeof (CoglPipelineFogState));
1933
1934 state->hash = hash;
1935 }
1936
1937 void
_cogl_pipeline_hash_non_zero_point_size_state(CoglPipeline * authority,CoglPipelineHashState * state)1938 _cogl_pipeline_hash_non_zero_point_size_state (CoglPipeline *authority,
1939 CoglPipelineHashState *state)
1940 {
1941 CoglBool non_zero_point_size = authority->big_state->non_zero_point_size;
1942
1943 state->hash = _cogl_util_one_at_a_time_hash (state->hash,
1944 &non_zero_point_size,
1945 sizeof (non_zero_point_size));
1946 }
1947
1948 void
_cogl_pipeline_hash_point_size_state(CoglPipeline * authority,CoglPipelineHashState * state)1949 _cogl_pipeline_hash_point_size_state (CoglPipeline *authority,
1950 CoglPipelineHashState *state)
1951 {
1952 float point_size = authority->big_state->point_size;
1953 state->hash = _cogl_util_one_at_a_time_hash (state->hash, &point_size,
1954 sizeof (point_size));
1955 }
1956
1957 void
_cogl_pipeline_hash_per_vertex_point_size_state(CoglPipeline * authority,CoglPipelineHashState * state)1958 _cogl_pipeline_hash_per_vertex_point_size_state (CoglPipeline *authority,
1959 CoglPipelineHashState *state)
1960 {
1961 CoglBool per_vertex_point_size = authority->big_state->per_vertex_point_size;
1962 state->hash = _cogl_util_one_at_a_time_hash (state->hash,
1963 &per_vertex_point_size,
1964 sizeof (per_vertex_point_size));
1965 }
1966
1967 void
_cogl_pipeline_hash_logic_ops_state(CoglPipeline * authority,CoglPipelineHashState * state)1968 _cogl_pipeline_hash_logic_ops_state (CoglPipeline *authority,
1969 CoglPipelineHashState *state)
1970 {
1971 CoglPipelineLogicOpsState *logic_ops_state = &authority->big_state->logic_ops_state;
1972 state->hash = _cogl_util_one_at_a_time_hash (state->hash, &logic_ops_state->color_mask,
1973 sizeof (CoglColorMask));
1974 }
1975
1976 void
_cogl_pipeline_hash_cull_face_state(CoglPipeline * authority,CoglPipelineHashState * state)1977 _cogl_pipeline_hash_cull_face_state (CoglPipeline *authority,
1978 CoglPipelineHashState *state)
1979 {
1980 CoglPipelineCullFaceState *cull_face_state
1981 = &authority->big_state->cull_face_state;
1982
1983 /* The cull face state is considered equal if two pipelines are both
1984 set to no culling. If the front winding property is ever used for
1985 anything else or the hashing is used not just for drawing then
1986 this would have to change */
1987 if (cull_face_state->mode == COGL_PIPELINE_CULL_FACE_MODE_NONE)
1988 state->hash =
1989 _cogl_util_one_at_a_time_hash (state->hash,
1990 &cull_face_state->mode,
1991 sizeof (CoglPipelineCullFaceMode));
1992 else
1993 state->hash =
1994 _cogl_util_one_at_a_time_hash (state->hash,
1995 cull_face_state,
1996 sizeof (CoglPipelineCullFaceState));
1997 }
1998
1999 void
_cogl_pipeline_hash_uniforms_state(CoglPipeline * authority,CoglPipelineHashState * state)2000 _cogl_pipeline_hash_uniforms_state (CoglPipeline *authority,
2001 CoglPipelineHashState *state)
2002 {
2003 /* This isn't used anywhere yet because the uniform state doesn't
2004 affect program generation. It's quite a hassle to implement so
2005 let's just leave it until something actually needs it */
2006 g_warn_if_reached ();
2007 }
2008
2009 void
_cogl_pipeline_compare_uniform_differences(unsigned long * differences,CoglPipeline * pipeline0,CoglPipeline * pipeline1)2010 _cogl_pipeline_compare_uniform_differences (unsigned long *differences,
2011 CoglPipeline *pipeline0,
2012 CoglPipeline *pipeline1)
2013 {
2014 GSList *head0 = NULL;
2015 GSList *head1 = NULL;
2016 CoglPipeline *node0;
2017 CoglPipeline *node1;
2018 int len0 = 0;
2019 int len1 = 0;
2020 int count;
2021 GSList *common_ancestor0;
2022 GSList *common_ancestor1;
2023
2024 /* This algorithm is copied from
2025 _cogl_pipeline_compare_differences(). It might be nice to share
2026 the code more */
2027
2028 for (node0 = pipeline0; node0; node0 = _cogl_pipeline_get_parent (node0))
2029 {
2030 GSList *link = alloca (sizeof (GSList));
2031 link->next = head0;
2032 link->data = node0;
2033 head0 = link;
2034 len0++;
2035 }
2036 for (node1 = pipeline1; node1; node1 = _cogl_pipeline_get_parent (node1))
2037 {
2038 GSList *link = alloca (sizeof (GSList));
2039 link->next = head1;
2040 link->data = node1;
2041 head1 = link;
2042 len1++;
2043 }
2044
2045 /* NB: There's no point looking at the head entries since we know both
2046 * pipelines must have the same default pipeline as their root node. */
2047 common_ancestor0 = head0;
2048 common_ancestor1 = head1;
2049 head0 = head0->next;
2050 head1 = head1->next;
2051 count = MIN (len0, len1) - 1;
2052 while (count--)
2053 {
2054 if (head0->data != head1->data)
2055 break;
2056 common_ancestor0 = head0;
2057 common_ancestor1 = head1;
2058 head0 = head0->next;
2059 head1 = head1->next;
2060 }
2061
2062 for (head0 = common_ancestor0->next; head0; head0 = head0->next)
2063 {
2064 node0 = head0->data;
2065 if ((node0->differences & COGL_PIPELINE_STATE_UNIFORMS))
2066 {
2067 const CoglPipelineUniformsState *uniforms_state =
2068 &node0->big_state->uniforms_state;
2069 _cogl_bitmask_set_flags (&uniforms_state->override_mask,
2070 differences);
2071 }
2072 }
2073 for (head1 = common_ancestor1->next; head1; head1 = head1->next)
2074 {
2075 node1 = head1->data;
2076 if ((node1->differences & COGL_PIPELINE_STATE_UNIFORMS))
2077 {
2078 const CoglPipelineUniformsState *uniforms_state =
2079 &node1->big_state->uniforms_state;
2080 _cogl_bitmask_set_flags (&uniforms_state->override_mask,
2081 differences);
2082 }
2083 }
2084 }
2085
2086 void
_cogl_pipeline_hash_vertex_snippets_state(CoglPipeline * authority,CoglPipelineHashState * state)2087 _cogl_pipeline_hash_vertex_snippets_state (CoglPipeline *authority,
2088 CoglPipelineHashState *state)
2089 {
2090 _cogl_pipeline_snippet_list_hash (&authority->big_state->vertex_snippets,
2091 &state->hash);
2092 }
2093
2094 void
_cogl_pipeline_hash_fragment_snippets_state(CoglPipeline * authority,CoglPipelineHashState * state)2095 _cogl_pipeline_hash_fragment_snippets_state (CoglPipeline *authority,
2096 CoglPipelineHashState *state)
2097 {
2098 _cogl_pipeline_snippet_list_hash (&authority->big_state->fragment_snippets,
2099 &state->hash);
2100 }
2101
2102 UNIT_TEST (check_blend_constant_ancestry,
2103 0 /* no requirements */,
2104 0 /* no known failures */)
2105 {
2106 CoglPipeline *pipeline = cogl_pipeline_new (test_ctx);
2107 CoglNode *node;
2108 int pipeline_length = 0;
2109 int i;
2110
2111 /* Repeatedly making a copy of a pipeline and changing the same
2112 * state (in this case the blend constant) shouldn't cause a long
2113 * chain of pipelines to be created because the redundant ancestry
2114 * should be pruned. */
2115
2116 for (i = 0; i < 20; i++)
2117 {
2118 CoglColor color;
2119 CoglPipeline *tmp_pipeline;
2120
2121 cogl_color_init_from_4f (&color, i / 20.0f, 0.0f, 0.0f, 1.0f);
2122
2123 tmp_pipeline = cogl_pipeline_copy (pipeline);
2124 cogl_object_unref (pipeline);
2125 pipeline = tmp_pipeline;
2126
2127 cogl_pipeline_set_blend_constant (pipeline, &color);
2128 }
2129
2130 for (node = (CoglNode *) pipeline; node; node = node->parent)
2131 pipeline_length++;
2132
2133 g_assert_cmpint (pipeline_length, <=, 2);
2134
2135 cogl_object_unref (pipeline);
2136 }
2137
2138 UNIT_TEST (check_uniform_ancestry,
2139 0 /* no requirements */,
2140 TEST_KNOWN_FAILURE)
2141 {
2142 CoglPipeline *pipeline = cogl_pipeline_new (test_ctx);
2143 CoglNode *node;
2144 int pipeline_length = 0;
2145 int i;
2146
2147 /* Repeatedly making a copy of a pipeline and changing a uniform
2148 * shouldn't cause a long chain of pipelines to be created */
2149
2150 for (i = 0; i < 20; i++)
2151 {
2152 CoglPipeline *tmp_pipeline;
2153 int uniform_location;
2154
2155 tmp_pipeline = cogl_pipeline_copy (pipeline);
2156 cogl_object_unref (pipeline);
2157 pipeline = tmp_pipeline;
2158
2159 uniform_location =
2160 cogl_pipeline_get_uniform_location (pipeline, "a_uniform");
2161
2162 cogl_pipeline_set_uniform_1i (pipeline, uniform_location, i);
2163 }
2164
2165 for (node = (CoglNode *) pipeline; node; node = node->parent)
2166 pipeline_length++;
2167
2168 g_assert_cmpint (pipeline_length, <=, 2);
2169
2170 cogl_object_unref (pipeline);
2171 }
2172