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 (&current_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