1 /*
2  * Cogl
3  *
4  * A Low Level GPU Graphics and Utilities API
5  *
6  * Copyright (C) 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-util.h"
39 #include "cogl-context-private.h"
40 #include "cogl-object-private.h"
41 #include "cogl-journal-private.h"
42 #include "cogl-attribute.h"
43 #include "cogl-attribute-private.h"
44 #include "cogl-pipeline.h"
45 #include "cogl-pipeline-private.h"
46 #include "cogl-pipeline-opengl-private.h"
47 #include "cogl-texture-private.h"
48 #include "cogl-framebuffer-private.h"
49 #include "cogl-indices-private.h"
50 #ifdef COGL_PIPELINE_PROGEND_GLSL
51 #include "cogl-pipeline-progend-glsl-private.h"
52 #endif
53 #include "cogl-private.h"
54 #include "cogl-gtype-private.h"
55 
56 #include <string.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 
60 /* This isn't defined in the GLES headers */
61 #ifndef GL_UNSIGNED_INT
62 #define GL_UNSIGNED_INT 0x1405
63 #endif
64 
65 static void _cogl_attribute_free (CoglAttribute *attribute);
66 
67 COGL_OBJECT_DEFINE (Attribute, attribute);
68 COGL_GTYPE_DEFINE_CLASS (Attribute, attribute);
69 
70 static CoglBool
validate_cogl_attribute_name(const char * name,char ** real_attribute_name,CoglAttributeNameID * name_id,CoglBool * normalized,int * layer_number)71 validate_cogl_attribute_name (const char *name,
72                               char **real_attribute_name,
73                               CoglAttributeNameID *name_id,
74                               CoglBool *normalized,
75                               int *layer_number)
76 {
77   name = name + 5; /* skip "cogl_" */
78 
79   *normalized = FALSE;
80   *layer_number = 0;
81 
82   if (strcmp (name, "position_in") == 0)
83     *name_id = COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY;
84   else if (strcmp (name, "color_in") == 0)
85     {
86       *name_id = COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY;
87       *normalized = TRUE;
88     }
89   else if (strcmp (name, "tex_coord_in") == 0)
90     {
91       *real_attribute_name = "cogl_tex_coord0_in";
92       *name_id = COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY;
93     }
94   else if (strncmp (name, "tex_coord", strlen ("tex_coord")) == 0)
95     {
96       char *endptr;
97       *layer_number = strtoul (name + 9, &endptr, 10);
98       if (strcmp (endptr, "_in") != 0)
99 	{
100 	  g_warning ("Texture coordinate attributes should either be named "
101                      "\"cogl_tex_coord_in\" or named with a texture unit index "
102                      "like \"cogl_tex_coord2_in\"\n");
103           return FALSE;
104 	}
105       *name_id = COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY;
106     }
107   else if (strcmp (name, "normal_in") == 0)
108     {
109       *name_id = COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY;
110       *normalized = TRUE;
111     }
112   else if (strcmp (name, "point_size_in") == 0)
113     *name_id = COGL_ATTRIBUTE_NAME_ID_POINT_SIZE_ARRAY;
114   else
115     {
116       g_warning ("Unknown cogl_* attribute name cogl_%s\n", name);
117       return FALSE;
118     }
119 
120   return TRUE;
121 }
122 
123 CoglAttributeNameState *
_cogl_attribute_register_attribute_name(CoglContext * context,const char * name)124 _cogl_attribute_register_attribute_name (CoglContext *context,
125                                          const char *name)
126 {
127   CoglAttributeNameState *name_state = g_new (CoglAttributeNameState, 1);
128   int name_index = context->n_attribute_names++;
129   char *name_copy = g_strdup (name);
130 
131   name_state->name = NULL;
132   name_state->name_index = name_index;
133   if (strncmp (name, "cogl_", 5) == 0)
134     {
135       if (!validate_cogl_attribute_name (name,
136                                          &name_state->name,
137                                          &name_state->name_id,
138                                          &name_state->normalized_default,
139                                          &name_state->layer_number))
140         goto error;
141     }
142   else
143     {
144       name_state->name_id = COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY;
145       name_state->normalized_default = FALSE;
146       name_state->layer_number = 0;
147     }
148 
149   if (name_state->name == NULL)
150     name_state->name = name_copy;
151 
152   g_hash_table_insert (context->attribute_name_states_hash,
153                        name_copy, name_state);
154 
155   if (G_UNLIKELY (context->attribute_name_index_map == NULL))
156     context->attribute_name_index_map =
157       g_array_new (FALSE, FALSE, sizeof (void *));
158 
159   g_array_set_size (context->attribute_name_index_map, name_index + 1);
160 
161   g_array_index (context->attribute_name_index_map,
162                  CoglAttributeNameState *, name_index) = name_state;
163 
164   return name_state;
165 
166 error:
167   free (name_state);
168   return NULL;
169 }
170 
171 static CoglBool
validate_n_components(const CoglAttributeNameState * name_state,int n_components)172 validate_n_components (const CoglAttributeNameState *name_state,
173                        int n_components)
174 {
175   switch (name_state->name_id)
176     {
177     case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
178       if (G_UNLIKELY (n_components == 1))
179         {
180           g_critical ("glVertexPointer doesn't allow 1 component vertex "
181                       "positions so we currently only support \"cogl_vertex\" "
182                       "attributes where n_components == 2, 3 or 4");
183           return FALSE;
184         }
185       break;
186     case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
187       if (G_UNLIKELY (n_components != 3 && n_components != 4))
188         {
189           g_critical ("glColorPointer expects 3 or 4 component colors so we "
190                       "currently only support \"cogl_color\" attributes where "
191                       "n_components == 3 or 4");
192           return FALSE;
193         }
194       break;
195     case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
196       break;
197     case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY:
198       if (G_UNLIKELY (n_components != 3))
199         {
200           g_critical ("glNormalPointer expects 3 component normals so we "
201                       "currently only support \"cogl_normal\" attributes "
202                       "where n_components == 3");
203           return FALSE;
204         }
205       break;
206     case COGL_ATTRIBUTE_NAME_ID_POINT_SIZE_ARRAY:
207       if (G_UNLIKELY (n_components != 1))
208         {
209           g_critical ("The point size attribute can only have one "
210                       "component");
211           return FALSE;
212         }
213       break;
214     case COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY:
215       return TRUE;
216     }
217 
218   return TRUE;
219 }
220 
221 CoglAttribute *
cogl_attribute_new(CoglAttributeBuffer * attribute_buffer,const char * name,size_t stride,size_t offset,int n_components,CoglAttributeType type)222 cogl_attribute_new (CoglAttributeBuffer *attribute_buffer,
223                     const char *name,
224                     size_t stride,
225                     size_t offset,
226                     int n_components,
227                     CoglAttributeType type)
228 {
229   CoglAttribute *attribute = g_slice_new (CoglAttribute);
230   CoglBuffer *buffer = COGL_BUFFER (attribute_buffer);
231   CoglContext *ctx = buffer->context;
232 
233   attribute->is_buffered = TRUE;
234 
235   attribute->name_state =
236     g_hash_table_lookup (ctx->attribute_name_states_hash, name);
237   if (!attribute->name_state)
238     {
239       CoglAttributeNameState *name_state =
240         _cogl_attribute_register_attribute_name (ctx, name);
241       if (!name_state)
242         goto error;
243       attribute->name_state = name_state;
244     }
245 
246   attribute->d.buffered.attribute_buffer = cogl_object_ref (attribute_buffer);
247   attribute->d.buffered.stride = stride;
248   attribute->d.buffered.offset = offset;
249   attribute->d.buffered.n_components = n_components;
250   attribute->d.buffered.type = type;
251 
252   attribute->immutable_ref = 0;
253 
254   if (attribute->name_state->name_id != COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY)
255     {
256       if (!validate_n_components (attribute->name_state, n_components))
257         return NULL;
258       attribute->normalized =
259         attribute->name_state->normalized_default;
260     }
261   else
262     attribute->normalized = FALSE;
263 
264   return _cogl_attribute_object_new (attribute);
265 
266 error:
267   _cogl_attribute_free (attribute);
268   return NULL;
269 }
270 
271 static CoglAttribute *
_cogl_attribute_new_const(CoglContext * context,const char * name,int n_components,int n_columns,CoglBool transpose,const float * value)272 _cogl_attribute_new_const (CoglContext *context,
273                            const char *name,
274                            int n_components,
275                            int n_columns,
276                            CoglBool transpose,
277                            const float *value)
278 {
279   CoglAttribute *attribute = g_slice_new (CoglAttribute);
280 
281   attribute->name_state =
282     g_hash_table_lookup (context->attribute_name_states_hash, name);
283   if (!attribute->name_state)
284     {
285       CoglAttributeNameState *name_state =
286         _cogl_attribute_register_attribute_name (context, name);
287       if (!name_state)
288         goto error;
289       attribute->name_state = name_state;
290     }
291 
292   if (!validate_n_components (attribute->name_state, n_components))
293     goto error;
294 
295   attribute->is_buffered = FALSE;
296   attribute->normalized = FALSE;
297 
298   attribute->d.constant.context = cogl_object_ref (context);
299 
300   attribute->d.constant.boxed.v.array = NULL;
301 
302   if (n_columns == 1)
303     {
304       _cogl_boxed_value_set_float (&attribute->d.constant.boxed,
305                                    n_components,
306                                    1,
307                                    value);
308     }
309   else
310     {
311       /* FIXME: Up until GL[ES] 3 only square matrices were supported
312        * and we don't currently expose non-square matrices in Cogl.
313        */
314       _COGL_RETURN_VAL_IF_FAIL (n_columns == n_components, NULL);
315       _cogl_boxed_value_set_matrix (&attribute->d.constant.boxed,
316                                     n_columns,
317                                     1,
318                                     transpose,
319                                     value);
320     }
321 
322   return _cogl_attribute_object_new (attribute);
323 
324 error:
325   _cogl_attribute_free (attribute);
326   return NULL;
327 }
328 
329 CoglAttribute *
cogl_attribute_new_const_1f(CoglContext * context,const char * name,float value)330 cogl_attribute_new_const_1f (CoglContext *context,
331                              const char *name,
332                              float value)
333 {
334   return _cogl_attribute_new_const (context,
335                                     name,
336                                     1, /* n_components */
337                                     1, /* 1 column vector */
338                                     FALSE, /* no transpose */
339                                     &value);
340 }
341 
342 CoglAttribute *
cogl_attribute_new_const_2fv(CoglContext * context,const char * name,const float * value)343 cogl_attribute_new_const_2fv (CoglContext *context,
344                               const char *name,
345                               const float *value)
346 {
347   return _cogl_attribute_new_const (context,
348                                     name,
349                                     2, /* n_components */
350                                     1, /* 1 column vector */
351                                     FALSE, /* no transpose */
352                                     value);
353 }
354 
355 CoglAttribute *
cogl_attribute_new_const_3fv(CoglContext * context,const char * name,const float * value)356 cogl_attribute_new_const_3fv (CoglContext *context,
357                               const char *name,
358                               const float *value)
359 {
360   return _cogl_attribute_new_const (context,
361                                     name,
362                                     3, /* n_components */
363                                     1, /* 1 column vector */
364                                     FALSE, /* no transpose */
365                                     value);
366 }
367 
368 CoglAttribute *
cogl_attribute_new_const_4fv(CoglContext * context,const char * name,const float * value)369 cogl_attribute_new_const_4fv (CoglContext *context,
370                               const char *name,
371                               const float *value)
372 {
373   return _cogl_attribute_new_const (context,
374                                     name,
375                                     4, /* n_components */
376                                     1, /* 1 column vector */
377                                     FALSE, /* no transpose */
378                                     value);
379 }
380 
381 CoglAttribute *
cogl_attribute_new_const_2f(CoglContext * context,const char * name,float component0,float component1)382 cogl_attribute_new_const_2f (CoglContext *context,
383                              const char *name,
384                              float component0,
385                              float component1)
386 {
387   float vec2[2] = { component0, component1 };
388   return _cogl_attribute_new_const (context,
389                                     name,
390                                     2, /* n_components */
391                                     1, /* 1 column vector */
392                                     FALSE, /* no transpose */
393                                     vec2);
394 }
395 
396 CoglAttribute *
cogl_attribute_new_const_3f(CoglContext * context,const char * name,float component0,float component1,float component2)397 cogl_attribute_new_const_3f (CoglContext *context,
398                              const char *name,
399                              float component0,
400                              float component1,
401                              float component2)
402 {
403   float vec3[3] = { component0, component1, component2 };
404   return _cogl_attribute_new_const (context,
405                                     name,
406                                     3, /* n_components */
407                                     1, /* 1 column vector */
408                                     FALSE, /* no transpose */
409                                     vec3);
410 }
411 
412 CoglAttribute *
cogl_attribute_new_const_4f(CoglContext * context,const char * name,float component0,float component1,float component2,float component3)413 cogl_attribute_new_const_4f (CoglContext *context,
414                              const char *name,
415                              float component0,
416                              float component1,
417                              float component2,
418                              float component3)
419 {
420   float vec4[4] = { component0, component1, component2, component3 };
421   return _cogl_attribute_new_const (context,
422                                     name,
423                                     4, /* n_components */
424                                     1, /* 1 column vector */
425                                     FALSE, /* no transpose */
426                                     vec4);
427 }
428 
429 CoglAttribute *
cogl_attribute_new_const_2x2fv(CoglContext * context,const char * name,const float * matrix2x2,CoglBool transpose)430 cogl_attribute_new_const_2x2fv (CoglContext *context,
431                                 const char *name,
432                                 const float *matrix2x2,
433                                 CoglBool transpose)
434 {
435   return _cogl_attribute_new_const (context,
436                                     name,
437                                     2, /* n_components */
438                                     2, /* 2 column vector */
439                                     FALSE, /* no transpose */
440                                     matrix2x2);
441 }
442 
443 CoglAttribute *
cogl_attribute_new_const_3x3fv(CoglContext * context,const char * name,const float * matrix3x3,CoglBool transpose)444 cogl_attribute_new_const_3x3fv (CoglContext *context,
445                                 const char *name,
446                                 const float *matrix3x3,
447                                 CoglBool transpose)
448 {
449   return _cogl_attribute_new_const (context,
450                                     name,
451                                     3, /* n_components */
452                                     3, /* 3 column vector */
453                                     FALSE, /* no transpose */
454                                     matrix3x3);
455 }
456 
457 CoglAttribute *
cogl_attribute_new_const_4x4fv(CoglContext * context,const char * name,const float * matrix4x4,CoglBool transpose)458 cogl_attribute_new_const_4x4fv (CoglContext *context,
459                                 const char *name,
460                                 const float *matrix4x4,
461                                 CoglBool transpose)
462 {
463   return _cogl_attribute_new_const (context,
464                                     name,
465                                     4, /* n_components */
466                                     4, /* 4 column vector */
467                                     FALSE, /* no transpose */
468                                     matrix4x4);
469 }
470 
471 CoglBool
cogl_attribute_get_normalized(CoglAttribute * attribute)472 cogl_attribute_get_normalized (CoglAttribute *attribute)
473 {
474   _COGL_RETURN_VAL_IF_FAIL (cogl_is_attribute (attribute), FALSE);
475 
476   return attribute->normalized;
477 }
478 
479 static void
warn_about_midscene_changes(void)480 warn_about_midscene_changes (void)
481 {
482   static CoglBool seen = FALSE;
483   if (!seen)
484     {
485       g_warning ("Mid-scene modification of attributes has "
486                  "undefined results\n");
487       seen = TRUE;
488     }
489 }
490 
491 void
cogl_attribute_set_normalized(CoglAttribute * attribute,CoglBool normalized)492 cogl_attribute_set_normalized (CoglAttribute *attribute,
493                                       CoglBool normalized)
494 {
495   _COGL_RETURN_IF_FAIL (cogl_is_attribute (attribute));
496 
497   if (G_UNLIKELY (attribute->immutable_ref))
498     warn_about_midscene_changes ();
499 
500   attribute->normalized = normalized;
501 }
502 
503 CoglAttributeBuffer *
cogl_attribute_get_buffer(CoglAttribute * attribute)504 cogl_attribute_get_buffer (CoglAttribute *attribute)
505 {
506   _COGL_RETURN_VAL_IF_FAIL (cogl_is_attribute (attribute), NULL);
507   _COGL_RETURN_VAL_IF_FAIL (attribute->is_buffered, NULL);
508 
509   return attribute->d.buffered.attribute_buffer;
510 }
511 
512 void
cogl_attribute_set_buffer(CoglAttribute * attribute,CoglAttributeBuffer * attribute_buffer)513 cogl_attribute_set_buffer (CoglAttribute *attribute,
514                            CoglAttributeBuffer *attribute_buffer)
515 {
516   _COGL_RETURN_IF_FAIL (cogl_is_attribute (attribute));
517   _COGL_RETURN_IF_FAIL (attribute->is_buffered);
518 
519   if (G_UNLIKELY (attribute->immutable_ref))
520     warn_about_midscene_changes ();
521 
522   cogl_object_ref (attribute_buffer);
523 
524   cogl_object_unref (attribute->d.buffered.attribute_buffer);
525   attribute->d.buffered.attribute_buffer = attribute_buffer;
526 }
527 
528 CoglAttribute *
_cogl_attribute_immutable_ref(CoglAttribute * attribute)529 _cogl_attribute_immutable_ref (CoglAttribute *attribute)
530 {
531   CoglBuffer *buffer = COGL_BUFFER (attribute->d.buffered.attribute_buffer);
532 
533   _COGL_RETURN_VAL_IF_FAIL (cogl_is_attribute (attribute), NULL);
534 
535   attribute->immutable_ref++;
536   _cogl_buffer_immutable_ref (buffer);
537   return attribute;
538 }
539 
540 void
_cogl_attribute_immutable_unref(CoglAttribute * attribute)541 _cogl_attribute_immutable_unref (CoglAttribute *attribute)
542 {
543   CoglBuffer *buffer = COGL_BUFFER (attribute->d.buffered.attribute_buffer);
544 
545   _COGL_RETURN_IF_FAIL (cogl_is_attribute (attribute));
546   _COGL_RETURN_IF_FAIL (attribute->immutable_ref > 0);
547 
548   attribute->immutable_ref--;
549   _cogl_buffer_immutable_unref (buffer);
550 }
551 
552 static void
_cogl_attribute_free(CoglAttribute * attribute)553 _cogl_attribute_free (CoglAttribute *attribute)
554 {
555   if (attribute->is_buffered)
556     cogl_object_unref (attribute->d.buffered.attribute_buffer);
557   else
558     _cogl_boxed_value_destroy (&attribute->d.constant.boxed);
559 
560   g_slice_free (CoglAttribute, attribute);
561 }
562 
563 static CoglBool
validate_layer_cb(CoglPipeline * pipeline,int layer_index,void * user_data)564 validate_layer_cb (CoglPipeline *pipeline,
565                    int layer_index,
566                    void *user_data)
567 {
568   CoglTexture *texture =
569     cogl_pipeline_get_layer_texture (pipeline, layer_index);
570   CoglFlushLayerState *state = user_data;
571   CoglBool status = TRUE;
572 
573   /* invalid textures will be handled correctly in
574    * _cogl_pipeline_flush_layers_gl_state */
575   if (texture == NULL)
576     goto validated;
577 
578   _cogl_texture_flush_journal_rendering (texture);
579 
580   /* Give the texture a chance to know that we're rendering
581      non-quad shaped primitives. If the texture is in an atlas it
582      will be migrated */
583   _cogl_texture_ensure_non_quad_rendering (texture);
584 
585   /* We need to ensure the mipmaps are ready before deciding
586    * anything else about the texture because the texture storate
587    * could completely change if it needs to be migrated out of the
588    * atlas and will affect how we validate the layer.
589    */
590   _cogl_pipeline_pre_paint_for_layer (pipeline, layer_index);
591 
592   if (!_cogl_texture_can_hardware_repeat (texture))
593     {
594       g_warning ("Disabling layer %d of the current source material, "
595                  "because texturing with the vertex buffer API is not "
596                  "currently supported using sliced textures, or textures "
597                  "with waste\n", layer_index);
598 
599       /* XXX: maybe we can add a mechanism for users to forcibly use
600        * textures with waste where it would be their responsability to use
601        * texture coords in the range [0,1] such that sampling outside isn't
602        * required. We can then use a texture matrix (or a modification of
603        * the users own matrix) to map 1 to the edge of the texture data.
604        *
605        * Potentially, given the same guarantee as above we could also
606        * support a single sliced layer too. We would have to redraw the
607        * vertices once for each layer, each time with a fiddled texture
608        * matrix.
609        */
610       state->fallback_layers |= (1 << state->unit);
611       state->options.flags |= COGL_PIPELINE_FLUSH_FALLBACK_MASK;
612     }
613 
614 validated:
615   state->unit++;
616   return status;
617 }
618 
619 void
_cogl_flush_attributes_state(CoglFramebuffer * framebuffer,CoglPipeline * pipeline,CoglDrawFlags flags,CoglAttribute ** attributes,int n_attributes)620 _cogl_flush_attributes_state (CoglFramebuffer *framebuffer,
621                               CoglPipeline *pipeline,
622                               CoglDrawFlags flags,
623                               CoglAttribute **attributes,
624                               int n_attributes)
625 {
626   CoglContext *ctx = framebuffer->context;
627   CoglFlushLayerState layers_state;
628   CoglPipeline *copy = NULL;
629 
630   if (!(flags & COGL_DRAW_SKIP_JOURNAL_FLUSH))
631     _cogl_journal_flush (framebuffer->journal);
632 
633   layers_state.unit = 0;
634   layers_state.options.flags = 0;
635   layers_state.fallback_layers = 0;
636 
637   if (!(flags & COGL_DRAW_SKIP_PIPELINE_VALIDATION))
638     cogl_pipeline_foreach_layer (pipeline,
639                                  validate_layer_cb,
640                                  &layers_state);
641 
642   /* NB: _cogl_framebuffer_flush_state may disrupt various state (such
643    * as the pipeline state) when flushing the clip stack, so should
644    * always be done first when preparing to draw. We need to do this
645    * before setting up the array pointers because setting up the clip
646    * stack can cause some drawing which would change the array
647    * pointers. */
648   if (!(flags & COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH))
649     _cogl_framebuffer_flush_state (framebuffer,
650                                    framebuffer,
651                                    COGL_FRAMEBUFFER_STATE_ALL);
652 
653   /* In cogl_read_pixels we have a fast-path when reading a single
654    * pixel and the scene is just comprised of simple rectangles still
655    * in the journal. For this optimization to work we need to track
656    * when the framebuffer really does get drawn to. */
657   _cogl_framebuffer_mark_mid_scene (framebuffer);
658   _cogl_framebuffer_mark_clear_clip_dirty (framebuffer);
659 
660   if (G_UNLIKELY (!(flags & COGL_DRAW_SKIP_LEGACY_STATE)) &&
661       G_UNLIKELY (ctx->legacy_state_set) &&
662       _cogl_get_enable_legacy_state ())
663     {
664       copy = cogl_pipeline_copy (pipeline);
665       pipeline = copy;
666       _cogl_pipeline_apply_legacy_state (pipeline);
667     }
668 
669   ctx->driver_vtable->flush_attributes_state (framebuffer,
670                                               pipeline,
671                                               &layers_state,
672                                               flags,
673                                               attributes,
674                                               n_attributes);
675 
676   if (copy)
677     cogl_object_unref (copy);
678 }
679 
680 int
_cogl_attribute_get_n_components(CoglAttribute * attribute)681 _cogl_attribute_get_n_components (CoglAttribute *attribute)
682 {
683   if (attribute->is_buffered)
684     return attribute->d.buffered.n_components;
685   else
686     return attribute->d.constant.boxed.size;
687 }
688