"Initial commit to Gerrit"
[profile/ivi/cogl.git] / cogl / cogl-framebuffer.c
1 /*
2  * Cogl
3  *
4  * An object oriented GL/GLES Abstraction/Utility Layer
5  *
6  * Copyright (C) 2007,2008,2009 Intel Corporation.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20  *
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <string.h>
29
30 #include "cogl-debug.h"
31 #include "cogl-internal.h"
32 #include "cogl-context-private.h"
33 #include "cogl-display-private.h"
34 #include "cogl-renderer-private.h"
35 #include "cogl-object-private.h"
36 #include "cogl-util.h"
37 #include "cogl-texture-private.h"
38 #include "cogl-framebuffer-private.h"
39 #include "cogl-onscreen-template-private.h"
40 #include "cogl-clip-stack.h"
41 #include "cogl-journal-private.h"
42 #include "cogl-winsys-private.h"
43 #include "cogl-pipeline-state-private.h"
44 #include "cogl-matrix-private.h"
45 #include "cogl-primitive-private.h"
46 #include "cogl-offscreen.h"
47 #include "cogl1-context.h"
48 #include "cogl-private.h"
49 #include "cogl-primitives-private.h"
50
51 #ifndef GL_FRAMEBUFFER
52 #define GL_FRAMEBUFFER          0x8D40
53 #endif
54 #ifndef GL_RENDERBUFFER
55 #define GL_RENDERBUFFER         0x8D41
56 #endif
57 #ifndef GL_STENCIL_ATTACHMENT
58 #define GL_STENCIL_ATTACHMENT   0x8D00
59 #endif
60 #ifndef GL_COLOR_ATTACHMENT0
61 #define GL_COLOR_ATTACHMENT0    0x8CE0
62 #endif
63 #ifndef GL_FRAMEBUFFER_COMPLETE
64 #define GL_FRAMEBUFFER_COMPLETE 0x8CD5
65 #endif
66 #ifndef GL_STENCIL_INDEX8
67 #define GL_STENCIL_INDEX8       0x8D48
68 #endif
69 #ifndef GL_DEPTH_STENCIL
70 #define GL_DEPTH_STENCIL        0x84F9
71 #endif
72 #ifndef GL_DEPTH24_STENCIL8
73 #define GL_DEPTH24_STENCIL8     0x88F0
74 #endif
75 #ifndef GL_DEPTH_ATTACHMENT
76 #define GL_DEPTH_ATTACHMENT     0x8D00
77 #endif
78 #ifndef GL_DEPTH_COMPONENT16
79 #define GL_DEPTH_COMPONENT16    0x81A5
80 #endif
81 #ifndef GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE
82 #define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE      0x8212
83 #endif
84 #ifndef GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE
85 #define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE    0x8213
86 #endif
87 #ifndef GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE
88 #define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE     0x8214
89 #endif
90 #ifndef GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE
91 #define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE    0x8215
92 #endif
93 #ifndef GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE
94 #define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE    0x8216
95 #endif
96 #ifndef GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE
97 #define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE  0x8217
98 #endif
99 #ifndef GL_READ_FRAMEBUFFER
100 #define GL_READ_FRAMEBUFFER               0x8CA8
101 #endif
102 #ifndef GL_DRAW_FRAMEBUFFER
103 #define GL_DRAW_FRAMEBUFFER               0x8CA9
104 #endif
105 #ifndef GL_TEXTURE_SAMPLES_IMG
106 #define GL_TEXTURE_SAMPLES_IMG            0x9136
107 #endif
108 #ifndef GL_PACK_INVERT_MESA
109 #define GL_PACK_INVERT_MESA 0x8758
110 #endif
111
112
113 typedef enum {
114   _TRY_DEPTH_STENCIL    = 1L<<0,
115   _TRY_DEPTH24_STENCIL8 = 1L<<1,
116   _TRY_DEPTH            = 1L<<2,
117   _TRY_STENCIL          = 1L<<3
118 } TryFBOFlags;
119
120 typedef struct _CoglFramebufferStackEntry
121 {
122   CoglFramebuffer *draw_buffer;
123   CoglFramebuffer *read_buffer;
124 } CoglFramebufferStackEntry;
125
126 extern CoglObjectClass _cogl_onscreen_class;
127
128 static CoglUserDataKey wire_pipeline_key;
129
130 static void _cogl_offscreen_free (CoglOffscreen *offscreen);
131
132 COGL_OBJECT_DEFINE_WITH_CODE (Offscreen, offscreen,
133                               _cogl_offscreen_class.virt_unref =
134                               _cogl_framebuffer_unref);
135 COGL_OBJECT_DEFINE_DEPRECATED_REF_COUNTING (offscreen);
136
137 /* XXX:
138  * The CoglObject macros don't support any form of inheritance, so for
139  * now we implement the CoglObject support for the CoglFramebuffer
140  * abstract class manually.
141  */
142
143 GQuark
144 cogl_framebuffer_error_quark (void)
145 {
146   return g_quark_from_static_string ("cogl-framebuffer-error-quark");
147 }
148
149 gboolean
150 cogl_is_framebuffer (void *object)
151 {
152   CoglObject *obj = object;
153
154   if (obj == NULL)
155     return FALSE;
156
157   return (obj->klass == &_cogl_onscreen_class ||
158           obj->klass == &_cogl_offscreen_class);
159 }
160
161 void
162 _cogl_framebuffer_init (CoglFramebuffer *framebuffer,
163                         CoglContext *ctx,
164                         CoglFramebufferType type,
165                         CoglPixelFormat format,
166                         int width,
167                         int height)
168 {
169   framebuffer->context = cogl_object_ref (ctx);
170
171   framebuffer->type             = type;
172   framebuffer->width            = width;
173   framebuffer->height           = height;
174   framebuffer->format           = format;
175   framebuffer->viewport_x       = 0;
176   framebuffer->viewport_y       = 0;
177   framebuffer->viewport_width   = width;
178   framebuffer->viewport_height  = height;
179   framebuffer->dither_enabled   = TRUE;
180
181   framebuffer->modelview_stack  = _cogl_matrix_stack_new ();
182   framebuffer->projection_stack = _cogl_matrix_stack_new ();
183
184   framebuffer->dirty_bitmasks   = TRUE;
185
186   framebuffer->color_mask       = COGL_COLOR_MASK_ALL;
187
188   framebuffer->samples_per_pixel = 0;
189
190   /* Initialise the clip stack */
191   _cogl_clip_state_init (&framebuffer->clip_state);
192
193   framebuffer->journal = _cogl_journal_new (framebuffer);
194
195   /* Ensure we know the framebuffer->clear_color* members can't be
196    * referenced for our fast-path read-pixel optimization (see
197    * _cogl_journal_try_read_pixel()) until some region of the
198    * framebuffer is initialized.
199    */
200   framebuffer->clear_clip_dirty = TRUE;
201
202   /* XXX: We have to maintain a central list of all framebuffers
203    * because at times we need to be able to flush all known journals.
204    *
205    * Examples where we need to flush all journals are:
206    * - because journal entries can reference OpenGL texture
207    *   coordinates that may not survive texture-atlas reorganization
208    *   so we need the ability to flush those entries.
209    * - because although we generally advise against modifying
210    *   pipelines after construction we have to handle that possibility
211    *   and since pipelines may be referenced in journal entries we
212    *   need to be able to flush them before allowing the pipelines to
213    *   be changed.
214    *
215    * Note we don't maintain a list of journals and associate
216    * framebuffers with journals by e.g. having a journal->framebuffer
217    * reference since that would introduce a circular reference.
218    *
219    * Note: As a future change to try and remove the need to index all
220    * journals it might be possible to defer resolving of OpenGL
221    * texture coordinates for rectangle primitives until we come to
222    * flush a journal. This would mean for instance that a single
223    * rectangle entry in a journal could later be expanded into
224    * multiple quad primitives to handle sliced textures but would mean
225    * we don't have to worry about retaining references to OpenGL
226    * texture coordinates that may later become invalid.
227    */
228   ctx->framebuffers = g_list_prepend (ctx->framebuffers, framebuffer);
229 }
230
231 void
232 _cogl_framebuffer_free (CoglFramebuffer *framebuffer)
233 {
234   CoglContext *ctx = framebuffer->context;
235
236   _cogl_clip_state_destroy (&framebuffer->clip_state);
237
238   cogl_object_unref (framebuffer->modelview_stack);
239   framebuffer->modelview_stack = NULL;
240
241   cogl_object_unref (framebuffer->projection_stack);
242   framebuffer->projection_stack = NULL;
243
244   cogl_object_unref (framebuffer->journal);
245
246   ctx->framebuffers = g_list_remove (ctx->framebuffers, framebuffer);
247   cogl_object_unref (ctx);
248
249   if (ctx->current_draw_buffer == framebuffer)
250     ctx->current_draw_buffer = NULL;
251   if (ctx->current_read_buffer == framebuffer)
252     ctx->current_read_buffer = NULL;
253 }
254
255 const CoglWinsysVtable *
256 _cogl_framebuffer_get_winsys (CoglFramebuffer *framebuffer)
257 {
258   return framebuffer->context->display->renderer->winsys_vtable;
259 }
260
261 /* This version of cogl_clear can be used internally as an alternative
262  * to avoid flushing the journal or the framebuffer state. This is
263  * needed when doing operations that may be called whiling flushing
264  * the journal */
265 void
266 _cogl_framebuffer_clear_without_flush4f (CoglFramebuffer *framebuffer,
267                                          unsigned long buffers,
268                                          float red,
269                                          float green,
270                                          float blue,
271                                          float alpha)
272 {
273   GLbitfield gl_buffers = 0;
274
275   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
276
277   if (buffers & COGL_BUFFER_BIT_COLOR)
278     {
279       GE( ctx, glClearColor (red, green, blue, alpha) );
280       gl_buffers |= GL_COLOR_BUFFER_BIT;
281
282       if (ctx->current_gl_color_mask != framebuffer->color_mask)
283         {
284           CoglColorMask color_mask = framebuffer->color_mask;
285           GE( ctx, glColorMask (!!(color_mask & COGL_COLOR_MASK_RED),
286                                 !!(color_mask & COGL_COLOR_MASK_GREEN),
287                                 !!(color_mask & COGL_COLOR_MASK_BLUE),
288                                 !!(color_mask & COGL_COLOR_MASK_ALPHA)));
289           ctx->current_gl_color_mask = color_mask;
290           /* Make sure the ColorMask is updated when the next primitive is drawn */
291           ctx->current_pipeline_changes_since_flush |=
292             COGL_PIPELINE_STATE_LOGIC_OPS;
293           ctx->current_pipeline_age--;
294         }
295     }
296
297   if (buffers & COGL_BUFFER_BIT_DEPTH)
298     gl_buffers |= GL_DEPTH_BUFFER_BIT;
299
300   if (buffers & COGL_BUFFER_BIT_STENCIL)
301     gl_buffers |= GL_STENCIL_BUFFER_BIT;
302
303   if (!gl_buffers)
304     {
305       static gboolean shown = FALSE;
306
307       if (!shown)
308         {
309           g_warning ("You should specify at least one auxiliary buffer "
310                      "when calling cogl_clear");
311         }
312
313       return;
314     }
315
316   GE (ctx, glClear (gl_buffers));
317 }
318
319 void
320 _cogl_framebuffer_dirty (CoglFramebuffer *framebuffer)
321 {
322   framebuffer->clear_clip_dirty = TRUE;
323 }
324
325 void
326 cogl_framebuffer_clear4f (CoglFramebuffer *framebuffer,
327                           unsigned long buffers,
328                           float red,
329                           float green,
330                           float blue,
331                           float alpha)
332 {
333   CoglClipStack *clip_stack = _cogl_framebuffer_get_clip_stack (framebuffer);
334   int scissor_x0;
335   int scissor_y0;
336   int scissor_x1;
337   int scissor_y1;
338
339   _cogl_clip_stack_get_bounds (clip_stack,
340                                &scissor_x0, &scissor_y0,
341                                &scissor_x1, &scissor_y1);
342
343   /* NB: the previous clear could have had an arbitrary clip.
344    * NB: everything for the last frame might still be in the journal
345    *     but we can't assume anything about how each entry was
346    *     clipped.
347    * NB: Clutter will scissor its pick renders which would mean all
348    *     journal entries have a common ClipStack entry, but without
349    *     a layering violation Cogl has to explicitly walk the journal
350    *     entries to determine if this is the case.
351    * NB: We have a software only read-pixel optimization in the
352    *     journal that determines the color at a given framebuffer
353    *     coordinate for simple scenes without rendering with the GPU.
354    *     When Clutter is hitting this fast-path we can expect to
355    *     receive calls to clear the framebuffer with an un-flushed
356    *     journal.
357    * NB: To fully support software based picking for Clutter we
358    *     need to be able to reliably detect when the contents of a
359    *     journal can be discarded and when we can skip the call to
360    *     glClear because it matches the previous clear request.
361    */
362
363   /* Note: we don't check for the stencil buffer being cleared here
364    * since there isn't any public cogl api to manipulate the stencil
365    * buffer.
366    *
367    * Note: we check for an exact clip match here because
368    * 1) a smaller clip could mean existing journal entries may
369    *    need to contribute to regions outside the new clear-clip
370    * 2) a larger clip would mean we need to issue a real
371    *    glClear and we only care about cases avoiding a
372    *    glClear.
373    *
374    * Note: Comparing without an epsilon is considered
375    * appropriate here.
376    */
377   if (buffers & COGL_BUFFER_BIT_COLOR &&
378       buffers & COGL_BUFFER_BIT_DEPTH &&
379       !framebuffer->clear_clip_dirty &&
380       framebuffer->clear_color_red == red &&
381       framebuffer->clear_color_green == green &&
382       framebuffer->clear_color_blue == blue &&
383       framebuffer->clear_color_alpha == alpha &&
384       scissor_x0 == framebuffer->clear_clip_x0 &&
385       scissor_y0 == framebuffer->clear_clip_y0 &&
386       scissor_x1 == framebuffer->clear_clip_x1 &&
387       scissor_y1 == framebuffer->clear_clip_y1)
388     {
389       /* NB: We only have to consider the clip state of journal
390        * entries if the current clear is clipped since otherwise we
391        * know every pixel of the framebuffer is affected by the clear
392        * and so all journal entries become redundant and can simply be
393        * discarded.
394        */
395       if (clip_stack)
396         {
397           /*
398            * Note: the function for checking the journal entries is
399            * quite strict. It avoids detailed checking of all entry
400            * clip_stacks by only checking the details of the first
401            * entry and then it only verifies that the remaining
402            * entries share the same clip_stack ancestry. This means
403            * it's possible for some false negatives here but that will
404            * just result in us falling back to a real clear.
405            */
406           if (_cogl_journal_all_entries_within_bounds (framebuffer->journal,
407                                                        scissor_x0, scissor_y0,
408                                                        scissor_x1, scissor_y1))
409             {
410               _cogl_journal_discard (framebuffer->journal);
411               goto cleared;
412             }
413         }
414       else
415         {
416           _cogl_journal_discard (framebuffer->journal);
417           goto cleared;
418         }
419     }
420
421   COGL_NOTE (DRAW, "Clear begin");
422
423   _cogl_framebuffer_flush_journal (framebuffer);
424
425   /* NB: _cogl_framebuffer_flush_state may disrupt various state (such
426    * as the pipeline state) when flushing the clip stack, so should
427    * always be done first when preparing to draw. */
428   _cogl_framebuffer_flush_state (framebuffer, framebuffer,
429                                  COGL_FRAMEBUFFER_STATE_ALL);
430
431   _cogl_framebuffer_clear_without_flush4f (framebuffer, buffers,
432                                            red, green, blue, alpha);
433
434   /* This is a debugging variable used to visually display the quad
435    * batches from the journal. It is reset here to increase the
436    * chances of getting the same colours for each frame during an
437    * animation */
438   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_RECTANGLES)) &&
439       buffers & COGL_BUFFER_BIT_COLOR)
440     {
441       framebuffer->context->journal_rectangles_color = 1;
442     }
443
444   COGL_NOTE (DRAW, "Clear end");
445
446 cleared:
447
448   if (buffers & COGL_BUFFER_BIT_COLOR && buffers & COGL_BUFFER_BIT_DEPTH)
449     {
450       /* For our fast-path for reading back a single pixel of simple
451        * scenes where the whole frame is in the journal we need to
452        * track the cleared color of the framebuffer in case the point
453        * read doesn't intersect any of the journal rectangles. */
454       framebuffer->clear_clip_dirty = FALSE;
455       framebuffer->clear_color_red = red;
456       framebuffer->clear_color_green = green;
457       framebuffer->clear_color_blue = blue;
458       framebuffer->clear_color_alpha = alpha;
459
460       /* NB: A clear may be scissored so we need to track the extents
461        * that the clear is applicable too... */
462       if (clip_stack)
463         {
464           _cogl_clip_stack_get_bounds (clip_stack,
465                                        &framebuffer->clear_clip_x0,
466                                        &framebuffer->clear_clip_y0,
467                                        &framebuffer->clear_clip_x1,
468                                        &framebuffer->clear_clip_y1);
469         }
470       else
471         {
472           /* FIXME: set degenerate clip */
473         }
474     }
475   else
476     _cogl_framebuffer_dirty (framebuffer);
477 }
478
479 /* Note: the 'buffers' and 'color' arguments were switched around on
480  * purpose compared to the original cogl_clear API since it was odd
481  * that you would be expected to specify a color before even
482  * necessarily choosing to clear the color buffer.
483  */
484 void
485 cogl_framebuffer_clear (CoglFramebuffer *framebuffer,
486                         unsigned long buffers,
487                         const CoglColor *color)
488 {
489   cogl_framebuffer_clear4f (framebuffer, buffers,
490                             cogl_color_get_red_float (color),
491                             cogl_color_get_green_float (color),
492                             cogl_color_get_blue_float (color),
493                             cogl_color_get_alpha_float (color));
494 }
495
496 int
497 cogl_framebuffer_get_width (CoglFramebuffer *framebuffer)
498 {
499   return framebuffer->width;
500 }
501
502 int
503 cogl_framebuffer_get_height (CoglFramebuffer *framebuffer)
504 {
505   return framebuffer->height;
506 }
507
508 CoglClipState *
509 _cogl_framebuffer_get_clip_state (CoglFramebuffer *framebuffer)
510 {
511   return &framebuffer->clip_state;
512 }
513
514 CoglClipStack *
515 _cogl_framebuffer_get_clip_stack (CoglFramebuffer *framebuffer)
516 {
517   CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
518
519   return _cogl_clip_state_get_stack (clip_state);
520 }
521
522 void
523 _cogl_framebuffer_set_clip_stack (CoglFramebuffer *framebuffer,
524                                   CoglClipStack *stack)
525 {
526   CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
527
528   _cogl_clip_state_set_stack (clip_state, stack);
529 }
530
531 void
532 cogl_framebuffer_set_viewport (CoglFramebuffer *framebuffer,
533                                float x,
534                                float y,
535                                float width,
536                                float height)
537 {
538   _COGL_RETURN_IF_FAIL (width > 0 && height > 0);
539
540   if (framebuffer->viewport_x == x &&
541       framebuffer->viewport_y == y &&
542       framebuffer->viewport_width == width &&
543       framebuffer->viewport_height == height)
544     return;
545
546   _cogl_framebuffer_flush_journal (framebuffer);
547
548   framebuffer->viewport_x = x;
549   framebuffer->viewport_y = y;
550   framebuffer->viewport_width = width;
551   framebuffer->viewport_height = height;
552
553   if (framebuffer->context->current_draw_buffer == framebuffer)
554     framebuffer->context->current_draw_buffer_changes |=
555       COGL_FRAMEBUFFER_STATE_VIEWPORT;
556 }
557
558 float
559 cogl_framebuffer_get_viewport_x (CoglFramebuffer *framebuffer)
560 {
561   return framebuffer->viewport_x;
562 }
563
564 float
565 cogl_framebuffer_get_viewport_y (CoglFramebuffer *framebuffer)
566 {
567   return framebuffer->viewport_y;
568 }
569
570 float
571 cogl_framebuffer_get_viewport_width (CoglFramebuffer *framebuffer)
572 {
573   return framebuffer->viewport_width;
574 }
575
576 float
577 cogl_framebuffer_get_viewport_height (CoglFramebuffer *framebuffer)
578 {
579   return framebuffer->viewport_height;
580 }
581
582 void
583 cogl_framebuffer_get_viewport4fv (CoglFramebuffer *framebuffer,
584                                   float *viewport)
585 {
586   viewport[0] = framebuffer->viewport_x;
587   viewport[1] = framebuffer->viewport_y;
588   viewport[2] = framebuffer->viewport_width;
589   viewport[3] = framebuffer->viewport_height;
590 }
591
592 CoglMatrixStack *
593 _cogl_framebuffer_get_modelview_stack (CoglFramebuffer *framebuffer)
594 {
595   return framebuffer->modelview_stack;
596 }
597
598 CoglMatrixStack *
599 _cogl_framebuffer_get_projection_stack (CoglFramebuffer *framebuffer)
600 {
601   return framebuffer->projection_stack;
602 }
603
604 void
605 _cogl_framebuffer_add_dependency (CoglFramebuffer *framebuffer,
606                                   CoglFramebuffer *dependency)
607 {
608   GList *l;
609
610   for (l = framebuffer->deps; l; l = l->next)
611     {
612       CoglFramebuffer *existing_dep = l->data;
613       if (existing_dep == dependency)
614         return;
615     }
616
617   /* TODO: generalize the primed-array type structure we e.g. use for
618    * cogl_object_set_user_data or for pipeline children as a way to
619    * avoid quite a lot of mid-scene micro allocations here... */
620   framebuffer->deps =
621     g_list_prepend (framebuffer->deps, cogl_object_ref (dependency));
622 }
623
624 void
625 _cogl_framebuffer_remove_all_dependencies (CoglFramebuffer *framebuffer)
626 {
627   GList *l;
628   for (l = framebuffer->deps; l; l = l->next)
629     cogl_object_unref (l->data);
630   g_list_free (framebuffer->deps);
631   framebuffer->deps = NULL;
632 }
633
634 void
635 _cogl_framebuffer_flush_journal (CoglFramebuffer *framebuffer)
636 {
637   _cogl_journal_flush (framebuffer->journal);
638 }
639
640 void
641 _cogl_framebuffer_flush_dependency_journals (CoglFramebuffer *framebuffer)
642 {
643   GList *l;
644   for (l = framebuffer->deps; l; l = l->next)
645     _cogl_framebuffer_flush_journal (l->data);
646   _cogl_framebuffer_remove_all_dependencies (framebuffer);
647 }
648
649 static inline void
650 _cogl_framebuffer_init_bits (CoglFramebuffer *framebuffer)
651 {
652   CoglContext *ctx = framebuffer->context;
653
654   cogl_framebuffer_allocate (framebuffer, NULL);
655
656   if (G_LIKELY (!framebuffer->dirty_bitmasks))
657     return;
658
659 #ifdef HAVE_COGL_GL
660   if (ctx->driver == COGL_DRIVER_GL &&
661       cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) &&
662       framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN)
663     {
664       GLenum attachment, pname;
665
666       attachment = GL_COLOR_ATTACHMENT0;
667
668       pname = GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE;
669       GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
670                                                       attachment,
671                                                       pname,
672                                                       &framebuffer->red_bits) );
673
674       pname = GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE;
675       GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
676                                                       attachment,
677                                                       pname,
678                                                       &framebuffer->green_bits)
679           );
680
681       pname = GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE;
682       GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
683                                                       attachment,
684                                                       pname,
685                                                       &framebuffer->blue_bits)
686           );
687
688       pname = GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE;
689       GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
690                                                       attachment,
691                                                       pname,
692                                                       &framebuffer->alpha_bits)
693           );
694     }
695   else
696 #endif /* HAVE_COGL_GL */
697     {
698       GE( ctx, glGetIntegerv (GL_RED_BITS,   &framebuffer->red_bits)   );
699       GE( ctx, glGetIntegerv (GL_GREEN_BITS, &framebuffer->green_bits) );
700       GE( ctx, glGetIntegerv (GL_BLUE_BITS,  &framebuffer->blue_bits)  );
701       GE( ctx, glGetIntegerv (GL_ALPHA_BITS, &framebuffer->alpha_bits) );
702     }
703
704
705   COGL_NOTE (OFFSCREEN,
706              "RGBA Bits for framebuffer[%p, %s]: %d, %d, %d, %d",
707              framebuffer,
708              framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN
709                ? "offscreen"
710                : "onscreen",
711              framebuffer->red_bits,
712              framebuffer->blue_bits,
713              framebuffer->green_bits,
714              framebuffer->alpha_bits);
715
716   framebuffer->dirty_bitmasks = FALSE;
717 }
718
719 CoglOffscreen *
720 _cogl_offscreen_new_to_texture_full (CoglTexture *texture,
721                                      CoglOffscreenFlags create_flags,
722                                      unsigned int level)
723 {
724   CoglOffscreen *offscreen;
725   CoglFramebuffer *fb;
726   int level_width;
727   int level_height;
728   int i;
729   CoglHandle ret;
730
731   _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
732
733   if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
734     return COGL_INVALID_HANDLE;
735
736   /* Make texture is a valid texture object */
737   if (!cogl_is_texture (texture))
738     return COGL_INVALID_HANDLE;
739
740   /* The texture must not be sliced */
741   if (cogl_texture_is_sliced (texture))
742     return COGL_INVALID_HANDLE;
743
744   /* Calculate the size of the texture at this mipmap level to ensure
745      that it's a valid level */
746   level_width = cogl_texture_get_width (texture);
747   level_height = cogl_texture_get_height (texture);
748
749   for (i = 0; i < level; i++)
750     {
751       /* If neither dimension can be further divided then the level is
752          invalid */
753       if (level_width == 1 && level_height == 1)
754         {
755           g_warning ("Invalid texture level passed to "
756                      "_cogl_offscreen_new_to_texture_full");
757           return COGL_INVALID_HANDLE;
758         }
759
760       if (level_width > 1)
761         level_width >>= 1;
762       if (level_height > 1)
763         level_height >>= 1;
764     }
765
766   offscreen = g_new0 (CoglOffscreen, 1);
767   offscreen->texture = cogl_object_ref (texture);
768   offscreen->texture_level = level;
769   offscreen->texture_level_width = level_width;
770   offscreen->texture_level_height = level_height;
771   offscreen->create_flags = create_flags;
772
773   fb = COGL_FRAMEBUFFER (offscreen);
774
775   _cogl_framebuffer_init (fb,
776                           ctx,
777                           COGL_FRAMEBUFFER_TYPE_OFFSCREEN,
778                           cogl_texture_get_format (texture),
779                           level_width,
780                           level_height);
781
782   ret = _cogl_offscreen_object_new (offscreen);
783
784   _cogl_texture_associate_framebuffer (texture, fb);
785
786   return ret;
787 }
788
789 CoglOffscreen *
790 cogl_offscreen_new_to_texture (CoglTexture *texture)
791 {
792   return _cogl_offscreen_new_to_texture_full (texture, 0, 0);
793 }
794
795 static void
796 _cogl_offscreen_free (CoglOffscreen *offscreen)
797 {
798   CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (offscreen);
799   CoglContext *ctx = framebuffer->context;
800   GSList *l;
801
802   /* Chain up to parent */
803   _cogl_framebuffer_free (framebuffer);
804
805   for (l = offscreen->renderbuffers; l; l = l->next)
806     {
807       GLuint renderbuffer = GPOINTER_TO_UINT (l->data);
808       GE (ctx, glDeleteRenderbuffers (1, &renderbuffer));
809     }
810   g_slist_free (offscreen->renderbuffers);
811
812   GE (ctx, glDeleteFramebuffers (1, &offscreen->fbo_handle));
813
814   if (offscreen->texture != COGL_INVALID_HANDLE)
815     cogl_object_unref (offscreen->texture);
816
817   g_free (offscreen);
818 }
819
820 static gboolean
821 try_creating_fbo (CoglOffscreen *offscreen,
822                   TryFBOFlags flags)
823 {
824   CoglFramebuffer *fb = COGL_FRAMEBUFFER (offscreen);
825   CoglContext *ctx = fb->context;
826   GLuint gl_depth_stencil_handle;
827   GLuint gl_depth_handle;
828   GLuint gl_stencil_handle;
829   GLuint tex_gl_handle;
830   GLenum tex_gl_target;
831   GLuint fbo_gl_handle;
832   GLenum status;
833   int n_samples;
834   int height;
835   int width;
836
837   if (!cogl_texture_get_gl_texture (offscreen->texture,
838                                     &tex_gl_handle, &tex_gl_target))
839     return FALSE;
840
841   if (tex_gl_target != GL_TEXTURE_2D
842 #ifdef HAVE_COGL_GL
843       && tex_gl_target != GL_TEXTURE_RECTANGLE_ARB
844 #endif
845       )
846     return FALSE;
847
848   if (fb->config.samples_per_pixel)
849     {
850       if (!ctx->glFramebufferTexture2DMultisampleIMG)
851         return FALSE;
852       n_samples = fb->config.samples_per_pixel;
853     }
854   else
855     n_samples = 0;
856
857   width = offscreen->texture_level_width;
858   height = offscreen->texture_level_height;
859
860   /* We are about to generate and bind a new fbo, so we pretend to
861    * change framebuffer state so that the old framebuffer will be
862    * rebound again before drawing. */
863   ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_BIND;
864
865   /* Generate framebuffer */
866   ctx->glGenFramebuffers (1, &fbo_gl_handle);
867   GE (ctx, glBindFramebuffer (GL_FRAMEBUFFER, fbo_gl_handle));
868   offscreen->fbo_handle = fbo_gl_handle;
869
870   if (n_samples)
871     {
872       GE (ctx, glFramebufferTexture2DMultisampleIMG (GL_FRAMEBUFFER,
873                                                      GL_COLOR_ATTACHMENT0,
874                                                      tex_gl_target, tex_gl_handle,
875                                                      n_samples,
876                                                      offscreen->texture_level));
877     }
878   else
879     GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
880                                      tex_gl_target, tex_gl_handle,
881                                      offscreen->texture_level));
882
883   if (flags & (_TRY_DEPTH_STENCIL | _TRY_DEPTH24_STENCIL8))
884     {
885       GLenum format = ((flags & _TRY_DEPTH_STENCIL) ?
886                        GL_DEPTH_STENCIL : GL_DEPTH24_STENCIL8);
887
888       /* Create a renderbuffer for depth and stenciling */
889       GE (ctx, glGenRenderbuffers (1, &gl_depth_stencil_handle));
890       GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_stencil_handle));
891       if (n_samples)
892         GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER,
893                                                       n_samples,
894                                                       format,
895                                                       width, height));
896       else
897         GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, format,
898                                         width, height));
899       GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0));
900       GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
901                                           GL_STENCIL_ATTACHMENT,
902                                           GL_RENDERBUFFER,
903                                           gl_depth_stencil_handle));
904       GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
905                                           GL_DEPTH_ATTACHMENT,
906                                           GL_RENDERBUFFER,
907                                           gl_depth_stencil_handle));
908       offscreen->renderbuffers =
909         g_slist_prepend (offscreen->renderbuffers,
910                          GUINT_TO_POINTER (gl_depth_stencil_handle));
911     }
912
913   if (flags & _TRY_DEPTH)
914     {
915       GE (ctx, glGenRenderbuffers (1, &gl_depth_handle));
916       GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_handle));
917       /* For now we just ask for GL_DEPTH_COMPONENT16 since this is all that's
918        * available under GLES */
919       if (n_samples)
920         GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER,
921                                                       n_samples,
922                                                       GL_DEPTH_COMPONENT16,
923                                                       width, height));
924       else
925         GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
926                                         width, height));
927       GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0));
928       GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
929                                           GL_DEPTH_ATTACHMENT,
930                                           GL_RENDERBUFFER, gl_depth_handle));
931       offscreen->renderbuffers =
932         g_slist_prepend (offscreen->renderbuffers,
933                          GUINT_TO_POINTER (gl_depth_handle));
934     }
935
936   if (flags & _TRY_STENCIL)
937     {
938       GE (ctx, glGenRenderbuffers (1, &gl_stencil_handle));
939       GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_stencil_handle));
940       if (n_samples)
941         GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER,
942                                                       n_samples,
943                                                       GL_STENCIL_INDEX8,
944                                                       width, height));
945       else
946         GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_STENCIL_INDEX8,
947                                         width, height));
948       GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0));
949       GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
950                                           GL_STENCIL_ATTACHMENT,
951                                           GL_RENDERBUFFER, gl_stencil_handle));
952       offscreen->renderbuffers =
953         g_slist_prepend (offscreen->renderbuffers,
954                          GUINT_TO_POINTER (gl_stencil_handle));
955     }
956
957   /* Make sure it's complete */
958   status = ctx->glCheckFramebufferStatus (GL_FRAMEBUFFER);
959
960   if (status != GL_FRAMEBUFFER_COMPLETE)
961     {
962       GSList *l;
963
964       GE (ctx, glDeleteFramebuffers (1, &fbo_gl_handle));
965
966       for (l = offscreen->renderbuffers; l; l = l->next)
967         {
968           GLuint renderbuffer = GPOINTER_TO_UINT (l->data);
969           GE (ctx, glDeleteRenderbuffers (1, &renderbuffer));
970         }
971
972       g_slist_free (offscreen->renderbuffers);
973       offscreen->renderbuffers = NULL;
974
975       return FALSE;
976     }
977
978   /* Update the real number of samples_per_pixel now that we have a
979    * complete framebuffer */
980   if (n_samples)
981     {
982       GLenum attachment = GL_COLOR_ATTACHMENT0;
983       GLenum pname = GL_TEXTURE_SAMPLES_IMG;
984       int texture_samples;
985
986       GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
987                                                       attachment,
988                                                       pname,
989                                                       &texture_samples) );
990       fb->samples_per_pixel = texture_samples;
991     }
992
993   return TRUE;
994 }
995
996 static gboolean
997 _cogl_offscreen_allocate (CoglOffscreen *offscreen,
998                           GError **error)
999 {
1000   CoglFramebuffer *fb = COGL_FRAMEBUFFER (offscreen);
1001   CoglContext *ctx = fb->context;
1002   static TryFBOFlags flags;
1003   static gboolean have_working_flags = FALSE;
1004   gboolean fbo_created;
1005
1006   /* XXX: The framebuffer_object spec isn't clear in defining whether attaching
1007    * a texture as a renderbuffer with mipmap filtering enabled while the
1008    * mipmaps have not been uploaded should result in an incomplete framebuffer
1009    * object. (different drivers make different decisions)
1010    *
1011    * To avoid an error with drivers that do consider this a problem we
1012    * explicitly set non mipmapped filters here. These will later be reset when
1013    * the texture is actually used for rendering according to the filters set on
1014    * the corresponding CoglPipeline.
1015    */
1016   _cogl_texture_set_filters (offscreen->texture, GL_NEAREST, GL_NEAREST);
1017
1018   if ((offscreen->create_flags & COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL))
1019     fbo_created = try_creating_fbo (offscreen, 0);
1020   else
1021     {
1022       if ((have_working_flags &&
1023            try_creating_fbo (offscreen, flags)) ||
1024           ((ctx->private_feature_flags &
1025             COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL) &&
1026            try_creating_fbo (offscreen, flags = _TRY_DEPTH_STENCIL)) ||
1027           ((ctx->private_feature_flags &
1028             COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL) &&
1029            try_creating_fbo (offscreen, flags = _TRY_DEPTH24_STENCIL8)) ||
1030           try_creating_fbo (offscreen, flags = _TRY_DEPTH | _TRY_STENCIL) ||
1031           try_creating_fbo (offscreen, flags = _TRY_STENCIL) ||
1032           try_creating_fbo (offscreen, flags = _TRY_DEPTH) ||
1033           try_creating_fbo (offscreen, flags = 0))
1034         {
1035           /* Record that the last set of flags succeeded so that we can
1036              try that set first next time */
1037           have_working_flags = TRUE;
1038           fbo_created = TRUE;
1039         }
1040       else
1041         fbo_created = FALSE;
1042     }
1043
1044   if (!fbo_created)
1045     {
1046       g_set_error (error, COGL_FRAMEBUFFER_ERROR,
1047                    COGL_FRAMEBUFFER_ERROR_ALLOCATE,
1048                    "Failed to create an OpenGL framebuffer object");
1049       return FALSE;
1050     }
1051
1052   return TRUE;
1053 }
1054
1055 gboolean
1056 cogl_framebuffer_allocate (CoglFramebuffer *framebuffer,
1057                            GError **error)
1058 {
1059   CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
1060   const CoglWinsysVtable *winsys = _cogl_framebuffer_get_winsys (framebuffer);
1061
1062   if (framebuffer->allocated)
1063     return TRUE;
1064
1065   if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
1066     {
1067       if (!winsys->onscreen_init (onscreen, error))
1068         return FALSE;
1069     }
1070   else
1071     {
1072       if (!_cogl_offscreen_allocate (COGL_OFFSCREEN (framebuffer), error))
1073         return FALSE;
1074     }
1075
1076   framebuffer->allocated = TRUE;
1077
1078   return TRUE;
1079 }
1080
1081 static CoglFramebufferStackEntry *
1082 create_stack_entry (CoglFramebuffer *draw_buffer,
1083                     CoglFramebuffer *read_buffer)
1084 {
1085   CoglFramebufferStackEntry *entry = g_slice_new (CoglFramebufferStackEntry);
1086
1087   entry->draw_buffer = draw_buffer;
1088   entry->read_buffer = read_buffer;
1089
1090   return entry;
1091 }
1092
1093 GSList *
1094 _cogl_create_framebuffer_stack (void)
1095 {
1096   CoglFramebufferStackEntry *entry;
1097   GSList *stack = NULL;
1098
1099   entry = create_stack_entry (COGL_INVALID_HANDLE, COGL_INVALID_HANDLE);
1100
1101   return g_slist_prepend (stack, entry);
1102 }
1103
1104 void
1105 _cogl_free_framebuffer_stack (GSList *stack)
1106 {
1107   GSList *l;
1108
1109   for (l = stack; l != NULL; l = l->next)
1110     {
1111       CoglFramebufferStackEntry *entry = l->data;
1112
1113       if (entry->draw_buffer)
1114         cogl_object_unref (entry->draw_buffer);
1115
1116       if (entry->read_buffer)
1117         cogl_object_unref (entry->draw_buffer);
1118
1119       g_slice_free (CoglFramebufferStackEntry, entry);
1120     }
1121   g_slist_free (stack);
1122 }
1123
1124 static void
1125 notify_buffers_changed (CoglFramebuffer *old_draw_buffer,
1126                         CoglFramebuffer *new_draw_buffer,
1127                         CoglFramebuffer *old_read_buffer,
1128                         CoglFramebuffer *new_read_buffer)
1129 {
1130   /* XXX: To support the deprecated cogl_set_draw_buffer API we keep
1131    * track of the last onscreen framebuffer that was set so that it
1132    * can be restored if the COGL_WINDOW_BUFFER enum is used. A
1133    * reference isn't taken to the framebuffer because otherwise we
1134    * would have a circular reference between the context and the
1135    * framebuffer. Instead the pointer is set to NULL in
1136    * _cogl_onscreen_free as a kind of a cheap weak reference */
1137   if (new_draw_buffer &&
1138       new_draw_buffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
1139     new_draw_buffer->context->window_buffer = new_draw_buffer;
1140 }
1141
1142 /* Set the current framebuffer without checking if it's already the
1143  * current framebuffer. This is used by cogl_pop_framebuffer while
1144  * the top of the stack is currently not up to date. */
1145 static void
1146 _cogl_set_framebuffers_real (CoglFramebuffer *draw_buffer,
1147                              CoglFramebuffer *read_buffer)
1148 {
1149   CoglFramebufferStackEntry *entry;
1150
1151   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1152
1153   _COGL_RETURN_IF_FAIL (ctx != NULL);
1154   _COGL_RETURN_IF_FAIL (draw_buffer && read_buffer ?
1155                     draw_buffer->context == read_buffer->context : TRUE);
1156
1157   entry = ctx->framebuffer_stack->data;
1158
1159   notify_buffers_changed (entry->draw_buffer,
1160                           draw_buffer,
1161                           entry->read_buffer,
1162                           read_buffer);
1163
1164   if (draw_buffer)
1165     cogl_object_ref (draw_buffer);
1166   if (entry->draw_buffer)
1167     cogl_object_unref (entry->draw_buffer);
1168
1169   if (read_buffer)
1170     cogl_object_ref (read_buffer);
1171   if (entry->read_buffer)
1172     cogl_object_unref (entry->read_buffer);
1173
1174   entry->draw_buffer = draw_buffer;
1175   entry->read_buffer = read_buffer;
1176 }
1177
1178 static void
1179 _cogl_set_framebuffers (CoglFramebuffer *draw_buffer,
1180                         CoglFramebuffer *read_buffer)
1181 {
1182   CoglFramebuffer *current_draw_buffer;
1183   CoglFramebuffer *current_read_buffer;
1184
1185   _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (draw_buffer));
1186   _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (read_buffer));
1187
1188   current_draw_buffer = cogl_get_draw_framebuffer ();
1189   current_read_buffer = _cogl_get_read_framebuffer ();
1190
1191   if (current_draw_buffer != draw_buffer ||
1192       current_read_buffer != read_buffer)
1193     _cogl_set_framebuffers_real (draw_buffer, read_buffer);
1194 }
1195
1196 void
1197 cogl_set_framebuffer (CoglFramebuffer *framebuffer)
1198 {
1199   _cogl_set_framebuffers (framebuffer, framebuffer);
1200 }
1201
1202 /* XXX: deprecated API */
1203 void
1204 cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle handle)
1205 {
1206   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1207
1208   if (target == COGL_WINDOW_BUFFER)
1209     handle = ctx->window_buffer;
1210
1211   /* This is deprecated public API. The public API doesn't currently
1212      really expose the concept of separate draw and read buffers so
1213      for the time being this actually just sets both buffers */
1214   cogl_set_framebuffer (handle);
1215 }
1216
1217 CoglFramebuffer *
1218 cogl_get_draw_framebuffer (void)
1219 {
1220   CoglFramebufferStackEntry *entry;
1221
1222   _COGL_GET_CONTEXT (ctx, NULL);
1223
1224   g_assert (ctx->framebuffer_stack);
1225
1226   entry = ctx->framebuffer_stack->data;
1227
1228   return entry->draw_buffer;
1229 }
1230
1231 CoglFramebuffer *
1232 _cogl_get_read_framebuffer (void)
1233 {
1234   CoglFramebufferStackEntry *entry;
1235
1236   _COGL_GET_CONTEXT (ctx, NULL);
1237
1238   g_assert (ctx->framebuffer_stack);
1239
1240   entry = ctx->framebuffer_stack->data;
1241
1242   return entry->read_buffer;
1243 }
1244
1245 void
1246 _cogl_push_framebuffers (CoglFramebuffer *draw_buffer,
1247                          CoglFramebuffer *read_buffer)
1248 {
1249   CoglContext *ctx;
1250   CoglFramebuffer *old_draw_buffer, *old_read_buffer;
1251
1252   _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (draw_buffer));
1253   _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (read_buffer));
1254
1255   ctx = draw_buffer->context;
1256   _COGL_RETURN_IF_FAIL (ctx != NULL);
1257   _COGL_RETURN_IF_FAIL (draw_buffer->context == read_buffer->context);
1258
1259   _COGL_RETURN_IF_FAIL (ctx->framebuffer_stack != NULL);
1260
1261   /* Copy the top of the stack so that when we call cogl_set_framebuffer
1262      it will still know what the old framebuffer was */
1263   old_draw_buffer = cogl_get_draw_framebuffer ();
1264   if (old_draw_buffer)
1265     cogl_object_ref (old_draw_buffer);
1266   old_read_buffer = _cogl_get_read_framebuffer ();
1267   if (old_read_buffer)
1268     cogl_object_ref (old_read_buffer);
1269   ctx->framebuffer_stack =
1270     g_slist_prepend (ctx->framebuffer_stack,
1271                      create_stack_entry (old_draw_buffer,
1272                                          old_read_buffer));
1273
1274   _cogl_set_framebuffers (draw_buffer, read_buffer);
1275 }
1276
1277 void
1278 cogl_push_framebuffer (CoglFramebuffer *buffer)
1279 {
1280   _cogl_push_framebuffers (buffer, buffer);
1281 }
1282
1283 /* XXX: deprecated API */
1284 void
1285 cogl_push_draw_buffer (void)
1286 {
1287   cogl_push_framebuffer (cogl_get_draw_framebuffer ());
1288 }
1289
1290 void
1291 cogl_pop_framebuffer (void)
1292 {
1293   CoglFramebufferStackEntry *to_pop;
1294   CoglFramebufferStackEntry *to_restore;
1295
1296   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1297
1298   g_assert (ctx->framebuffer_stack != NULL);
1299   g_assert (ctx->framebuffer_stack->next != NULL);
1300
1301   to_pop = ctx->framebuffer_stack->data;
1302   to_restore = ctx->framebuffer_stack->next->data;
1303
1304   if (to_pop->draw_buffer != to_restore->draw_buffer ||
1305       to_pop->read_buffer != to_restore->read_buffer)
1306     notify_buffers_changed (to_pop->draw_buffer,
1307                             to_restore->draw_buffer,
1308                             to_pop->read_buffer,
1309                             to_restore->read_buffer);
1310
1311   cogl_object_unref (to_pop->draw_buffer);
1312   cogl_object_unref (to_pop->read_buffer);
1313   g_slice_free (CoglFramebufferStackEntry, to_pop);
1314
1315   ctx->framebuffer_stack =
1316     g_slist_delete_link (ctx->framebuffer_stack,
1317                          ctx->framebuffer_stack);
1318 }
1319
1320 /* XXX: deprecated API */
1321 void
1322 cogl_pop_draw_buffer (void)
1323 {
1324   cogl_pop_framebuffer ();
1325 }
1326
1327 static void
1328 bind_gl_framebuffer (CoglContext *ctx,
1329                      GLenum target,
1330                      CoglFramebuffer *framebuffer)
1331 {
1332   if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN)
1333     GE (ctx, glBindFramebuffer (target,
1334                            COGL_OFFSCREEN (framebuffer)->fbo_handle));
1335   else
1336     {
1337       const CoglWinsysVtable *winsys =
1338         _cogl_framebuffer_get_winsys (framebuffer);
1339       winsys->onscreen_bind (COGL_ONSCREEN (framebuffer));
1340       /* glBindFramebuffer is an an extension with OpenGL ES 1.1 */
1341       if (cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
1342         GE (ctx, glBindFramebuffer (target, 0));
1343     }
1344 }
1345
1346 static unsigned long
1347 _cogl_framebuffer_compare_viewport_state (CoglFramebuffer *a,
1348                                           CoglFramebuffer *b)
1349 {
1350   if (a->viewport_x != b->viewport_x ||
1351       a->viewport_y != b->viewport_y ||
1352       a->viewport_width != b->viewport_width ||
1353       a->viewport_height != b->viewport_height ||
1354       /* NB: we render upside down to offscreen framebuffers and that
1355        * can affect how we setup the GL viewport... */
1356       a->type != b->type)
1357     return COGL_FRAMEBUFFER_STATE_VIEWPORT;
1358   else
1359     return 0;
1360 }
1361
1362 static unsigned long
1363 _cogl_framebuffer_compare_clip_state (CoglFramebuffer *a,
1364                                       CoglFramebuffer *b)
1365 {
1366   if (((a->clip_state.stacks == NULL || b->clip_state.stacks == NULL) &&
1367        a->clip_state.stacks != b->clip_state.stacks)
1368       ||
1369       a->clip_state.stacks->data != b->clip_state.stacks->data)
1370     return COGL_FRAMEBUFFER_STATE_CLIP;
1371   else
1372     return 0;
1373 }
1374
1375 static unsigned long
1376 _cogl_framebuffer_compare_dither_state (CoglFramebuffer *a,
1377                                         CoglFramebuffer *b)
1378 {
1379   return a->dither_enabled != b->dither_enabled ?
1380     COGL_FRAMEBUFFER_STATE_DITHER : 0;
1381 }
1382
1383 static unsigned long
1384 _cogl_framebuffer_compare_modelview_state (CoglFramebuffer *a,
1385                                            CoglFramebuffer *b)
1386 {
1387   /* We always want to flush the modelview state. All this does is set
1388      the current modelview stack on the context to the framebuffer's
1389      stack. */
1390   return COGL_FRAMEBUFFER_STATE_MODELVIEW;
1391 }
1392
1393 static unsigned long
1394 _cogl_framebuffer_compare_projection_state (CoglFramebuffer *a,
1395                                             CoglFramebuffer *b)
1396 {
1397   /* We always want to flush the projection state. All this does is
1398      set the current projection stack on the context to the
1399      framebuffer's stack. */
1400   return COGL_FRAMEBUFFER_STATE_PROJECTION;
1401 }
1402
1403 static unsigned long
1404 _cogl_framebuffer_compare_color_mask_state (CoglFramebuffer *a,
1405                                             CoglFramebuffer *b)
1406 {
1407   if (cogl_framebuffer_get_color_mask (a) !=
1408       cogl_framebuffer_get_color_mask (b))
1409     return COGL_FRAMEBUFFER_STATE_COLOR_MASK;
1410   else
1411     return 0;
1412 }
1413
1414 static unsigned long
1415 _cogl_framebuffer_compare_front_face_winding_state (CoglFramebuffer *a,
1416                                                     CoglFramebuffer *b)
1417 {
1418   if (a->type != b->type)
1419     return COGL_FRAMEBUFFER_STATE_FRONT_FACE_WINDING;
1420   else
1421     return 0;
1422 }
1423
1424 static unsigned long
1425 _cogl_framebuffer_compare (CoglFramebuffer *a,
1426                            CoglFramebuffer *b,
1427                            unsigned long state)
1428 {
1429   unsigned long differences = 0;
1430   int bit;
1431
1432   if (state & COGL_FRAMEBUFFER_STATE_BIND)
1433     {
1434       differences |= COGL_FRAMEBUFFER_STATE_BIND;
1435       state &= ~COGL_FRAMEBUFFER_STATE_BIND;
1436     }
1437
1438   COGL_FLAGS_FOREACH_START (&state, 1, bit)
1439     {
1440       /* XXX: We considered having an array of callbacks for each state index
1441        * that we'd call here but decided that this way the compiler is more
1442        * likely going to be able to in-line the comparison functions and use
1443        * the index to jump straight to the required code. */
1444       switch (bit)
1445         {
1446         case COGL_FRAMEBUFFER_STATE_INDEX_VIEWPORT:
1447           differences |=
1448             _cogl_framebuffer_compare_viewport_state (a, b);
1449           break;
1450         case COGL_FRAMEBUFFER_STATE_INDEX_CLIP:
1451           differences |= _cogl_framebuffer_compare_clip_state (a, b);
1452           break;
1453         case COGL_FRAMEBUFFER_STATE_INDEX_DITHER:
1454           differences |= _cogl_framebuffer_compare_dither_state (a, b);
1455           break;
1456         case COGL_FRAMEBUFFER_STATE_INDEX_MODELVIEW:
1457           differences |=
1458             _cogl_framebuffer_compare_modelview_state (a, b);
1459           break;
1460         case COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION:
1461           differences |=
1462             _cogl_framebuffer_compare_projection_state (a, b);
1463           break;
1464         case COGL_FRAMEBUFFER_STATE_INDEX_COLOR_MASK:
1465           differences |=
1466             _cogl_framebuffer_compare_color_mask_state (a, b);
1467           break;
1468         case COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING:
1469           differences |=
1470             _cogl_framebuffer_compare_front_face_winding_state (a, b);
1471           break;
1472         default:
1473           g_warn_if_reached ();
1474         }
1475     }
1476   COGL_FLAGS_FOREACH_END;
1477
1478   return differences;
1479 }
1480
1481 static void
1482 _cogl_framebuffer_flush_viewport_state (CoglFramebuffer *framebuffer)
1483 {
1484   float gl_viewport_y;
1485
1486   g_assert (framebuffer->viewport_width >=0 &&
1487             framebuffer->viewport_height >=0);
1488
1489   /* Convert the Cogl viewport y offset to an OpenGL viewport y offset
1490    * NB: OpenGL defines its window and viewport origins to be bottom
1491    * left, while Cogl defines them to be top left.
1492    * NB: We render upside down to offscreen framebuffers so we don't
1493    * need to convert the y offset in this case. */
1494   if (cogl_is_offscreen (framebuffer))
1495     gl_viewport_y = framebuffer->viewport_y;
1496   else
1497     gl_viewport_y = framebuffer->height -
1498       (framebuffer->viewport_y + framebuffer->viewport_height);
1499
1500   COGL_NOTE (OPENGL, "Calling glViewport(%f, %f, %f, %f)",
1501              framebuffer->viewport_x,
1502              gl_viewport_y,
1503              framebuffer->viewport_width,
1504              framebuffer->viewport_height);
1505
1506   GE (framebuffer->context,
1507       glViewport (framebuffer->viewport_x,
1508                   gl_viewport_y,
1509                   framebuffer->viewport_width,
1510                   framebuffer->viewport_height));
1511 }
1512
1513 static void
1514 _cogl_framebuffer_flush_clip_state (CoglFramebuffer *framebuffer)
1515 {
1516   CoglClipStack *stack = _cogl_clip_state_get_stack (&framebuffer->clip_state);
1517   _cogl_clip_stack_flush (stack, framebuffer);
1518 }
1519
1520 static void
1521 _cogl_framebuffer_flush_dither_state (CoglFramebuffer *framebuffer)
1522 {
1523   CoglContext *ctx = framebuffer->context;
1524
1525   if (ctx->current_gl_dither_enabled != framebuffer->dither_enabled)
1526     {
1527       if (framebuffer->dither_enabled)
1528         GE (ctx, glEnable (GL_DITHER));
1529       else
1530         GE (ctx, glDisable (GL_DITHER));
1531       ctx->current_gl_dither_enabled = framebuffer->dither_enabled;
1532     }
1533 }
1534
1535 static void
1536 _cogl_framebuffer_flush_modelview_state (CoglFramebuffer *framebuffer)
1537 {
1538   _cogl_context_set_current_modelview (framebuffer->context,
1539                                        framebuffer->modelview_stack);
1540 }
1541
1542 static void
1543 _cogl_framebuffer_flush_projection_state (CoglFramebuffer *framebuffer)
1544 {
1545   _cogl_context_set_current_projection (framebuffer->context,
1546                                         framebuffer->projection_stack);
1547 }
1548
1549 static void
1550 _cogl_framebuffer_flush_color_mask_state (CoglFramebuffer *framebuffer)
1551 {
1552   CoglContext *context = framebuffer->context;
1553
1554   /* The color mask state is really owned by a CoglPipeline so to
1555    * ensure the color mask is updated the next time we draw something
1556    * we need to make sure the logic ops for the pipeline are
1557    * re-flushed... */
1558   context->current_pipeline_changes_since_flush |=
1559     COGL_PIPELINE_STATE_LOGIC_OPS;
1560   context->current_pipeline_age--;
1561 }
1562
1563 static void
1564 _cogl_framebuffer_flush_front_face_winding_state (CoglFramebuffer *framebuffer)
1565 {
1566   CoglContext *context = framebuffer->context;
1567   CoglPipelineCullFaceMode mode;
1568
1569   /* NB: The face winding state is actually owned by the current
1570    * CoglPipeline.
1571    *
1572    * If we don't have a current pipeline then we can just assume that
1573    * when we later do flush a pipeline we will check the current
1574    * framebuffer to know how to setup the winding */
1575   if (!context->current_pipeline)
1576     return;
1577
1578   mode = cogl_pipeline_get_cull_face_mode (context->current_pipeline);
1579
1580   /* If the current CoglPipeline has a culling mode that doesn't care
1581    * about the winding we can avoid forcing an update of the state and
1582    * bail out. */
1583   if (mode == COGL_PIPELINE_CULL_FACE_MODE_NONE ||
1584       mode == COGL_PIPELINE_CULL_FACE_MODE_BOTH)
1585     return;
1586
1587   /* Since the winding state is really owned by the current pipeline
1588    * the way we "flush" an updated winding is to dirty the pipeline
1589    * state... */
1590   context->current_pipeline_changes_since_flush |=
1591     COGL_PIPELINE_STATE_CULL_FACE;
1592   context->current_pipeline_age--;
1593 }
1594
1595 void
1596 _cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer,
1597                                CoglFramebuffer *read_buffer,
1598                                CoglFramebufferState state)
1599 {
1600   CoglContext *ctx = draw_buffer->context;
1601   unsigned long differences;
1602   int bit;
1603
1604   /* We can assume that any state that has changed for the current
1605    * framebuffer is different to the currently flushed value. */
1606   differences = ctx->current_draw_buffer_changes;
1607
1608   /* Any state of the current framebuffer that hasn't already been
1609    * flushed is assumed to be unknown so we will always flush that
1610    * state if asked. */
1611   differences |= ~ctx->current_draw_buffer_state_flushed;
1612
1613   /* We only need to consider the state we've been asked to flush */
1614   differences &= state;
1615
1616   if (ctx->current_draw_buffer != draw_buffer)
1617     {
1618       /* If the previous draw buffer is NULL then we'll assume
1619          everything has changed. This can happen if a framebuffer is
1620          destroyed while it is the last flushed draw buffer. In that
1621          case the framebuffer destructor will set
1622          ctx->current_draw_buffer to NULL */
1623       if (ctx->current_draw_buffer == NULL)
1624         differences |= state;
1625       else
1626         /* NB: we only need to compare the state we're being asked to flush
1627          * and we don't need to compare the state we've already decided
1628          * we will definitely flush... */
1629         differences |= _cogl_framebuffer_compare (ctx->current_draw_buffer,
1630                                                   draw_buffer,
1631                                                   state & ~differences);
1632
1633       /* NB: we don't take a reference here, to avoid a circular
1634        * reference. */
1635       ctx->current_draw_buffer = draw_buffer;
1636       ctx->current_draw_buffer_state_flushed = 0;
1637     }
1638
1639   if (ctx->current_read_buffer != read_buffer &&
1640       state & COGL_FRAMEBUFFER_STATE_BIND)
1641     {
1642       differences |= COGL_FRAMEBUFFER_STATE_BIND;
1643       /* NB: we don't take a reference here, to avoid a circular
1644        * reference. */
1645       ctx->current_read_buffer = read_buffer;
1646     }
1647
1648   if (!differences)
1649     return;
1650
1651   /* Lazily ensure the framebuffers have been allocated */
1652   if (G_UNLIKELY (!draw_buffer->allocated))
1653     cogl_framebuffer_allocate (draw_buffer, NULL);
1654   if (G_UNLIKELY (!read_buffer->allocated))
1655     cogl_framebuffer_allocate (read_buffer, NULL);
1656
1657   /* We handle buffer binding separately since the method depends on whether
1658    * we are binding the same buffer for read and write or not unlike all
1659    * other state that only relates to the draw_buffer. */
1660   if (differences & COGL_FRAMEBUFFER_STATE_BIND)
1661     {
1662       if (draw_buffer == read_buffer)
1663         bind_gl_framebuffer (ctx, GL_FRAMEBUFFER, draw_buffer);
1664       else
1665         {
1666           /* NB: Currently we only take advantage of binding separate
1667            * read/write buffers for offscreen framebuffer blit
1668            * purposes.  */
1669           _COGL_RETURN_IF_FAIL (ctx->private_feature_flags &
1670                                 COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT);
1671           _COGL_RETURN_IF_FAIL (draw_buffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN);
1672           _COGL_RETURN_IF_FAIL (read_buffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN);
1673
1674           bind_gl_framebuffer (ctx, GL_DRAW_FRAMEBUFFER, draw_buffer);
1675           bind_gl_framebuffer (ctx, GL_READ_FRAMEBUFFER, read_buffer);
1676         }
1677
1678       differences &= ~COGL_FRAMEBUFFER_STATE_BIND;
1679     }
1680
1681   COGL_FLAGS_FOREACH_START (&differences, 1, bit)
1682     {
1683       /* XXX: We considered having an array of callbacks for each state index
1684        * that we'd call here but decided that this way the compiler is more
1685        * likely going to be able to in-line the flush functions and use the
1686        * index to jump straight to the required code. */
1687       switch (bit)
1688         {
1689         case COGL_FRAMEBUFFER_STATE_INDEX_VIEWPORT:
1690           _cogl_framebuffer_flush_viewport_state (draw_buffer);
1691           break;
1692         case COGL_FRAMEBUFFER_STATE_INDEX_CLIP:
1693           _cogl_framebuffer_flush_clip_state (draw_buffer);
1694           break;
1695         case COGL_FRAMEBUFFER_STATE_INDEX_DITHER:
1696           _cogl_framebuffer_flush_dither_state (draw_buffer);
1697           break;
1698         case COGL_FRAMEBUFFER_STATE_INDEX_MODELVIEW:
1699           _cogl_framebuffer_flush_modelview_state (draw_buffer);
1700           break;
1701         case COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION:
1702           _cogl_framebuffer_flush_projection_state (draw_buffer);
1703           break;
1704         case COGL_FRAMEBUFFER_STATE_INDEX_COLOR_MASK:
1705           _cogl_framebuffer_flush_color_mask_state (draw_buffer);
1706           break;
1707         case COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING:
1708           _cogl_framebuffer_flush_front_face_winding_state (draw_buffer);
1709           break;
1710         default:
1711           g_warn_if_reached ();
1712         }
1713     }
1714   COGL_FLAGS_FOREACH_END;
1715
1716   ctx->current_draw_buffer_state_flushed |= state;
1717   ctx->current_draw_buffer_changes &= ~state;
1718 }
1719
1720 int
1721 cogl_framebuffer_get_red_bits (CoglFramebuffer *framebuffer)
1722 {
1723   _cogl_framebuffer_init_bits (framebuffer);
1724
1725   return framebuffer->red_bits;
1726 }
1727
1728 int
1729 cogl_framebuffer_get_green_bits (CoglFramebuffer *framebuffer)
1730 {
1731   _cogl_framebuffer_init_bits (framebuffer);
1732
1733   return framebuffer->green_bits;
1734 }
1735
1736 int
1737 cogl_framebuffer_get_blue_bits (CoglFramebuffer *framebuffer)
1738 {
1739   _cogl_framebuffer_init_bits (framebuffer);
1740
1741   return framebuffer->blue_bits;
1742 }
1743
1744 int
1745 cogl_framebuffer_get_alpha_bits (CoglFramebuffer *framebuffer)
1746 {
1747   _cogl_framebuffer_init_bits (framebuffer);
1748
1749   return framebuffer->alpha_bits;
1750 }
1751
1752 CoglColorMask
1753 cogl_framebuffer_get_color_mask (CoglFramebuffer *framebuffer)
1754 {
1755   return framebuffer->color_mask;
1756 }
1757
1758 void
1759 cogl_framebuffer_set_color_mask (CoglFramebuffer *framebuffer,
1760                                  CoglColorMask color_mask)
1761 {
1762   /* XXX: Currently color mask changes don't go through the journal */
1763   _cogl_framebuffer_flush_journal (framebuffer);
1764
1765   framebuffer->color_mask = color_mask;
1766
1767   if (framebuffer->context->current_draw_buffer == framebuffer)
1768     framebuffer->context->current_draw_buffer_changes |=
1769       COGL_FRAMEBUFFER_STATE_COLOR_MASK;
1770 }
1771
1772 gboolean
1773 cogl_framebuffer_get_dither_enabled (CoglFramebuffer *framebuffer)
1774 {
1775   return framebuffer->dither_enabled;
1776 }
1777
1778 void
1779 cogl_framebuffer_set_dither_enabled (CoglFramebuffer *framebuffer,
1780                                      gboolean dither_enabled)
1781 {
1782   if (framebuffer->dither_enabled == dither_enabled)
1783     return;
1784
1785   cogl_flush (); /* Currently dithering changes aren't tracked in the journal */
1786   framebuffer->dither_enabled = dither_enabled;
1787
1788   if (framebuffer->context->current_draw_buffer == framebuffer)
1789     framebuffer->context->current_draw_buffer_changes |=
1790       COGL_FRAMEBUFFER_STATE_DITHER;
1791 }
1792
1793 CoglPixelFormat
1794 cogl_framebuffer_get_color_format (CoglFramebuffer *framebuffer)
1795 {
1796   return framebuffer->format;
1797 }
1798
1799 int
1800 cogl_framebuffer_get_samples_per_pixel (CoglFramebuffer *framebuffer)
1801 {
1802   if (framebuffer->allocated)
1803     return framebuffer->samples_per_pixel;
1804   else
1805     return framebuffer->config.samples_per_pixel;
1806 }
1807
1808 void
1809 cogl_framebuffer_set_samples_per_pixel (CoglFramebuffer *framebuffer,
1810                                         int samples_per_pixel)
1811 {
1812   _COGL_RETURN_IF_FAIL (!framebuffer->allocated);
1813
1814   framebuffer->config.samples_per_pixel = samples_per_pixel;
1815 }
1816
1817 void
1818 cogl_framebuffer_resolve_samples (CoglFramebuffer *framebuffer)
1819 {
1820   cogl_framebuffer_resolve_samples_region (framebuffer,
1821                                            0, 0,
1822                                            framebuffer->width,
1823                                            framebuffer->height);
1824
1825   /* TODO: Make this happen implicitly when the resolve texture next gets used
1826    * as a source, either via cogl_texture_get_data(), via cogl_read_pixels() or
1827    * if used as a source for rendering. We would also implicitly resolve if
1828    * necessary before freeing a CoglFramebuffer.
1829    *
1830    * This API should still be kept but it is optional, only necessary
1831    * if the user wants to explicitly control when the resolve happens e.g.
1832    * to ensure it's done in advance of it being used as a source.
1833    *
1834    * Every texture should have a CoglFramebuffer *needs_resolve member
1835    * internally. When the texture gets validated before being used as a source
1836    * we should first check the needs_resolve pointer and if set we'll
1837    * automatically call cogl_framebuffer_resolve_samples ().
1838    *
1839    * Calling cogl_framebuffer_resolve_samples() or
1840    * cogl_framebuffer_resolve_samples_region() should reset the textures
1841    * needs_resolve pointer to NULL.
1842    *
1843    * Rendering anything to a framebuffer will cause the corresponding
1844    * texture's ->needs_resolve pointer to be set.
1845    *
1846    * XXX: Note: we only need to address this TODO item when adding support for
1847    * EXT_framebuffer_multisample because currently we only support hardware
1848    * that resolves implicitly anyway.
1849    */
1850 }
1851
1852 void
1853 cogl_framebuffer_resolve_samples_region (CoglFramebuffer *framebuffer,
1854                                          int x,
1855                                          int y,
1856                                          int width,
1857                                          int height)
1858 {
1859   /* NOP for now since we don't support EXT_framebuffer_multisample yet which
1860    * requires an explicit resolve. */
1861 }
1862
1863 CoglContext *
1864 cogl_framebuffer_get_context (CoglFramebuffer *framebuffer)
1865 {
1866   _COGL_RETURN_VAL_IF_FAIL (framebuffer != NULL, NULL);
1867
1868   return framebuffer->context;
1869 }
1870
1871 static gboolean
1872 _cogl_framebuffer_try_fast_read_pixel (CoglFramebuffer *framebuffer,
1873                                        int x,
1874                                        int y,
1875                                        CoglReadPixelsFlags source,
1876                                        CoglBitmap *bitmap)
1877 {
1878   gboolean found_intersection;
1879   CoglPixelFormat format;
1880
1881   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FAST_READ_PIXEL)))
1882     return FALSE;
1883
1884   if (source != COGL_READ_PIXELS_COLOR_BUFFER)
1885     return FALSE;
1886
1887   format = cogl_bitmap_get_format (bitmap);
1888
1889   if (format != COGL_PIXEL_FORMAT_RGBA_8888_PRE &&
1890       format != COGL_PIXEL_FORMAT_RGBA_8888)
1891     return FALSE;
1892
1893   if (!_cogl_journal_try_read_pixel (framebuffer->journal,
1894                                      x, y, bitmap,
1895                                      &found_intersection))
1896     return FALSE;
1897
1898   /* If we can't determine the color from the primitives in the
1899    * journal then see if we can use the last recorded clear color
1900    */
1901
1902   /* If _cogl_journal_try_read_pixel() failed even though there was an
1903    * intersection of the given point with a primitive in the journal
1904    * then we can't fallback to the framebuffer's last clear color...
1905    * */
1906   if (found_intersection)
1907     return TRUE;
1908
1909   /* If the framebuffer has been rendered too since it was last
1910    * cleared then we can't return the last known clear color. */
1911   if (framebuffer->clear_clip_dirty)
1912     return FALSE;
1913
1914   if (x >= framebuffer->clear_clip_x0 &&
1915       x < framebuffer->clear_clip_x1 &&
1916       y >= framebuffer->clear_clip_y0 &&
1917       y < framebuffer->clear_clip_y1)
1918     {
1919       guint8 *pixel;
1920
1921       /* we currently only care about cases where the premultiplied or
1922        * unpremultipled colors are equivalent... */
1923       if (framebuffer->clear_color_alpha != 1.0)
1924         return FALSE;
1925
1926       pixel = _cogl_bitmap_map (bitmap,
1927                                 COGL_BUFFER_ACCESS_WRITE,
1928                                 COGL_BUFFER_MAP_HINT_DISCARD);
1929       if (pixel == NULL)
1930         return FALSE;
1931
1932       pixel[0] = framebuffer->clear_color_red * 255.0;
1933       pixel[1] = framebuffer->clear_color_green * 255.0;
1934       pixel[2] = framebuffer->clear_color_blue * 255.0;
1935       pixel[3] = framebuffer->clear_color_alpha * 255.0;
1936
1937       _cogl_bitmap_unmap (bitmap);
1938
1939       return TRUE;
1940     }
1941
1942   return FALSE;
1943 }
1944
1945 gboolean
1946 cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
1947                                           int x,
1948                                           int y,
1949                                           CoglReadPixelsFlags source,
1950                                           CoglBitmap *bitmap)
1951 {
1952   CoglContext *ctx;
1953   int framebuffer_height;
1954   CoglPixelFormat format;
1955   CoglPixelFormat required_format;
1956   GLenum gl_intformat;
1957   GLenum gl_format;
1958   GLenum gl_type;
1959   gboolean pack_invert_set;
1960   int width;
1961   int height;
1962
1963   _COGL_RETURN_VAL_IF_FAIL (source == COGL_READ_PIXELS_COLOR_BUFFER, FALSE);
1964   _COGL_RETURN_VAL_IF_FAIL (cogl_is_framebuffer (framebuffer), FALSE);
1965
1966   if (!cogl_framebuffer_allocate (framebuffer, NULL))
1967     return FALSE;
1968
1969   ctx = cogl_framebuffer_get_context (framebuffer);
1970
1971   width = cogl_bitmap_get_width (bitmap);
1972   height = cogl_bitmap_get_height (bitmap);
1973
1974   if (width == 1 && height == 1 && !framebuffer->clear_clip_dirty)
1975     {
1976       /* If everything drawn so far for this frame is still in the
1977        * Journal then if all of the rectangles only have a flat
1978        * opaque color we have a fast-path for reading a single pixel
1979        * that avoids the relatively high cost of flushing primitives
1980        * to be drawn on the GPU (considering how simple the geometry
1981        * is in this case) and then blocking on the long GPU pipelines
1982        * for the result.
1983        */
1984       if (_cogl_framebuffer_try_fast_read_pixel (framebuffer,
1985                                                  x, y, source, bitmap))
1986         return TRUE;
1987     }
1988
1989   /* make sure any batched primitives get emitted to the GL driver
1990    * before issuing our read pixels...
1991    */
1992   _cogl_framebuffer_flush_journal (framebuffer);
1993
1994   _cogl_framebuffer_flush_state (framebuffer,
1995                                  framebuffer,
1996                                  COGL_FRAMEBUFFER_STATE_BIND);
1997
1998   framebuffer_height = cogl_framebuffer_get_height (framebuffer);
1999
2000   /* The y co-ordinate should be given in OpenGL's coordinate system
2001    * so 0 is the bottom row
2002    *
2003    * NB: all offscreen rendering is done upside down so no conversion
2004    * is necissary in this case.
2005    */
2006   if (!cogl_is_offscreen (framebuffer))
2007     y = framebuffer_height - y - height;
2008
2009   format = cogl_bitmap_get_format (bitmap);
2010
2011   required_format = ctx->texture_driver->pixel_format_to_gl (format,
2012                                                              &gl_intformat,
2013                                                              &gl_format,
2014                                                              &gl_type);
2015
2016   /* NB: All offscreen rendering is done upside down so there is no need
2017    * to flip in this case... */
2018   if ((ctx->private_feature_flags & COGL_PRIVATE_FEATURE_MESA_PACK_INVERT) &&
2019       !cogl_is_offscreen (framebuffer))
2020     {
2021       GE (ctx, glPixelStorei (GL_PACK_INVERT_MESA, TRUE));
2022       pack_invert_set = TRUE;
2023     }
2024   else
2025     pack_invert_set = FALSE;
2026
2027   /* Under GLES only GL_RGBA with GL_UNSIGNED_BYTE as well as an
2028      implementation specific format under
2029      GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES and
2030      GL_IMPLEMENTATION_COLOR_READ_TYPE_OES is supported. We could try
2031      to be more clever and check if the requested type matches that
2032      but we would need some reliable functions to convert from GL
2033      types to Cogl types. For now, lets just always read in
2034      GL_RGBA/GL_UNSIGNED_BYTE and convert if necessary. We also need
2035      to use this intermediate buffer if the rowstride has padding
2036      because GLES does not support setting GL_ROW_LENGTH */
2037   if ((ctx->driver != COGL_DRIVER_GL &&
2038        (gl_format != GL_RGBA || gl_type != GL_UNSIGNED_BYTE ||
2039         cogl_bitmap_get_rowstride (bitmap) != 4 * width)) ||
2040       (required_format & ~COGL_PREMULT_BIT) != (format & ~COGL_PREMULT_BIT))
2041     {
2042       CoglBitmap *tmp_bmp;
2043       CoglPixelFormat read_format;
2044       int bpp, rowstride;
2045       guint8 *tmp_data;
2046       int succeeded;
2047
2048       if (ctx->driver == COGL_DRIVER_GL)
2049         read_format = required_format;
2050       else
2051         {
2052           read_format = COGL_PIXEL_FORMAT_RGBA_8888;
2053           gl_format = GL_RGBA;
2054           gl_type = GL_UNSIGNED_BYTE;
2055         }
2056
2057       if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (read_format))
2058         read_format = ((read_format & ~COGL_PREMULT_BIT) |
2059                        (framebuffer->format & COGL_PREMULT_BIT));
2060
2061       tmp_bmp = _cogl_bitmap_new_with_malloc_buffer (ctx,
2062                                                      width, height,
2063                                                      read_format);
2064       bpp = _cogl_pixel_format_get_bytes_per_pixel (read_format);
2065       rowstride = cogl_bitmap_get_rowstride (tmp_bmp);
2066
2067       ctx->texture_driver->prep_gl_for_pixels_download (rowstride, bpp);
2068
2069       tmp_data = _cogl_bitmap_bind (tmp_bmp,
2070                                     COGL_BUFFER_ACCESS_WRITE,
2071                                     COGL_BUFFER_MAP_HINT_DISCARD);
2072
2073       GE( ctx, glReadPixels (x, y, width, height,
2074                              gl_format, gl_type,
2075                              tmp_data) );
2076
2077       _cogl_bitmap_unbind (tmp_bmp);
2078
2079       succeeded = _cogl_bitmap_convert_into_bitmap (tmp_bmp, bitmap);
2080
2081       cogl_object_unref (tmp_bmp);
2082
2083       if (!succeeded)
2084         return FALSE;
2085     }
2086   else
2087     {
2088       CoglBitmap *shared_bmp;
2089       CoglPixelFormat bmp_format;
2090       int bpp, rowstride;
2091       gboolean succeeded = FALSE;
2092       guint8 *pixels;
2093
2094       rowstride = cogl_bitmap_get_rowstride (bitmap);
2095
2096       /* We match the premultiplied state of the target buffer to the
2097        * premultiplied state of the framebuffer so that it will get
2098        * converted to the right format below */
2099       if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (format))
2100         bmp_format = ((format & ~COGL_PREMULT_BIT) |
2101                       (framebuffer->format & COGL_PREMULT_BIT));
2102       else
2103         bmp_format = format;
2104
2105       if (bmp_format != format)
2106         shared_bmp = _cogl_bitmap_new_shared (bitmap,
2107                                               bmp_format,
2108                                               width, height,
2109                                               rowstride);
2110       else
2111         shared_bmp = cogl_object_ref (bitmap);
2112
2113       bpp = _cogl_pixel_format_get_bytes_per_pixel (bmp_format);
2114
2115       ctx->texture_driver->prep_gl_for_pixels_download (rowstride, bpp);
2116
2117       pixels = _cogl_bitmap_bind (shared_bmp,
2118                                   COGL_BUFFER_ACCESS_WRITE,
2119                                   0 /* hints */);
2120
2121       GE( ctx, glReadPixels (x, y,
2122                              width, height,
2123                              gl_format, gl_type,
2124                              pixels) );
2125
2126       _cogl_bitmap_unbind (shared_bmp);
2127
2128       /* Convert to the premult format specified by the caller
2129          in-place. This will do nothing if the premult status is already
2130          correct. */
2131       if (_cogl_bitmap_convert_premult_status (shared_bmp, format))
2132         succeeded = TRUE;
2133
2134       cogl_object_unref (shared_bmp);
2135
2136       if (!succeeded)
2137         return FALSE;
2138     }
2139
2140   /* Currently this function owns the pack_invert state and we don't want this
2141    * to interfere with other Cogl components so all other code can assume that
2142    * we leave the pack_invert state off. */
2143   if (pack_invert_set)
2144     GE (ctx, glPixelStorei (GL_PACK_INVERT_MESA, FALSE));
2145
2146   /* NB: All offscreen rendering is done upside down so there is no need
2147    * to flip in this case... */
2148   if (!cogl_is_offscreen (framebuffer) && !pack_invert_set)
2149     {
2150       guint8 *temprow;
2151       int rowstride;
2152       guint8 *pixels;
2153
2154       rowstride = cogl_bitmap_get_rowstride (bitmap);
2155       pixels = _cogl_bitmap_map (bitmap,
2156                                  COGL_BUFFER_ACCESS_READ |
2157                                  COGL_BUFFER_ACCESS_WRITE,
2158                                  0 /* hints */);
2159
2160       if (pixels == NULL)
2161         return FALSE;
2162
2163       temprow = g_alloca (rowstride * sizeof (guint8));
2164
2165       /* vertically flip the buffer in-place */
2166       for (y = 0; y < height / 2; y++)
2167         {
2168           if (y != height - y - 1) /* skip center row */
2169             {
2170               memcpy (temprow,
2171                       pixels + y * rowstride, rowstride);
2172               memcpy (pixels + y * rowstride,
2173                       pixels + (height - y - 1) * rowstride, rowstride);
2174               memcpy (pixels + (height - y - 1) * rowstride,
2175                       temprow,
2176                       rowstride);
2177             }
2178         }
2179
2180       _cogl_bitmap_unmap (bitmap);
2181     }
2182
2183   return TRUE;
2184 }
2185
2186 gboolean
2187 cogl_framebuffer_read_pixels (CoglFramebuffer *framebuffer,
2188                               int x,
2189                               int y,
2190                               int width,
2191                               int height,
2192                               CoglPixelFormat format,
2193                               guint8 *pixels)
2194 {
2195   int bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
2196   CoglBitmap *bitmap;
2197   gboolean ret;
2198
2199   bitmap = cogl_bitmap_new_for_data (framebuffer->context,
2200                                      width, height,
2201                                      format,
2202                                      bpp * width, /* rowstride */
2203                                      pixels);
2204   ret = cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
2205                                                   x, y,
2206                                                   COGL_READ_PIXELS_COLOR_BUFFER,
2207                                                   bitmap);
2208   cogl_object_unref (bitmap);
2209
2210   return ret;
2211 }
2212
2213 void
2214 _cogl_blit_framebuffer (unsigned int src_x,
2215                         unsigned int src_y,
2216                         unsigned int dst_x,
2217                         unsigned int dst_y,
2218                         unsigned int width,
2219                         unsigned int height)
2220 {
2221   CoglFramebuffer *draw_buffer;
2222   CoglFramebuffer *read_buffer;
2223   CoglContext *ctx;
2224
2225   /* FIXME: this function should take explit src and dst framebuffer
2226    * arguments. */
2227   draw_buffer = cogl_get_draw_framebuffer ();
2228   read_buffer = _cogl_get_read_framebuffer ();
2229   ctx = draw_buffer->context;
2230
2231   _COGL_RETURN_IF_FAIL (ctx->private_feature_flags &
2232                     COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT);
2233
2234   /* We can only support blitting between offscreen buffers because
2235      otherwise we would need to mirror the image and GLES2.0 doesn't
2236      support this */
2237   _COGL_RETURN_IF_FAIL (cogl_is_offscreen (draw_buffer));
2238   _COGL_RETURN_IF_FAIL (cogl_is_offscreen (read_buffer));
2239   /* The buffers must be the same format */
2240   _COGL_RETURN_IF_FAIL (draw_buffer->format == read_buffer->format);
2241
2242   /* Make sure the current framebuffers are bound. We explicitly avoid
2243      flushing the clip state so we can bind our own empty state */
2244   _cogl_framebuffer_flush_state (cogl_get_draw_framebuffer (),
2245                                  _cogl_get_read_framebuffer (),
2246                                  COGL_FRAMEBUFFER_STATE_ALL &
2247                                  ~COGL_FRAMEBUFFER_STATE_CLIP);
2248
2249   /* Flush any empty clip stack because glBlitFramebuffer is affected
2250      by the scissor and we want to hide this feature for the Cogl API
2251      because it's not obvious to an app how the clip state will affect
2252      the scissor */
2253   _cogl_clip_stack_flush (NULL, draw_buffer);
2254
2255   /* XXX: Because we are manually flushing clip state here we need to
2256    * make sure that the clip state gets updated the next time we flush
2257    * framebuffer state by marking the current framebuffer's clip state
2258    * as changed */
2259   ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP;
2260
2261   ctx->glBlitFramebuffer (src_x, src_y,
2262                      src_x + width, src_y + height,
2263                      dst_x, dst_y,
2264                      dst_x + width, dst_y + height,
2265                      GL_COLOR_BUFFER_BIT,
2266                      GL_NEAREST);
2267 }
2268
2269 static void
2270 _cogl_framebuffer_discard_buffers_real (CoglFramebuffer *framebuffer,
2271                                         unsigned long buffers)
2272 {
2273 #ifdef GL_EXT_discard_framebuffer
2274   CoglContext *ctx = framebuffer->context;
2275
2276   if (ctx->glDiscardFramebuffer)
2277     {
2278       GLenum attachments[3];
2279       int i = 0;
2280
2281       if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
2282         {
2283           if (buffers & COGL_BUFFER_BIT_COLOR)
2284             attachments[i++] = GL_COLOR_EXT;
2285           if (buffers & COGL_BUFFER_BIT_DEPTH)
2286             attachments[i++] = GL_DEPTH_EXT;
2287           if (buffers & COGL_BUFFER_BIT_STENCIL)
2288             attachments[i++] = GL_STENCIL_EXT;
2289         }
2290       else
2291         {
2292           if (buffers & COGL_BUFFER_BIT_COLOR)
2293             attachments[i++] = GL_COLOR_ATTACHMENT0;
2294           if (buffers & COGL_BUFFER_BIT_DEPTH)
2295             attachments[i++] = GL_DEPTH_ATTACHMENT;
2296           if (buffers & COGL_BUFFER_BIT_STENCIL)
2297             attachments[i++] = GL_STENCIL_ATTACHMENT;
2298         }
2299
2300       GE (ctx, glDiscardFramebuffer (GL_FRAMEBUFFER, i, attachments));
2301     }
2302 #endif /* GL_EXT_discard_framebuffer */
2303 }
2304
2305 void
2306 cogl_framebuffer_discard_buffers (CoglFramebuffer *framebuffer,
2307                                   unsigned long buffers)
2308 {
2309   _COGL_RETURN_IF_FAIL (buffers & COGL_BUFFER_BIT_COLOR);
2310
2311   _cogl_framebuffer_discard_buffers_real (framebuffer, buffers);
2312 }
2313
2314 void
2315 cogl_framebuffer_finish (CoglFramebuffer *framebuffer)
2316 {
2317   _cogl_framebuffer_flush_journal (framebuffer);
2318   GE (framebuffer->context, glFinish ());
2319 }
2320
2321 void
2322 cogl_framebuffer_push_matrix (CoglFramebuffer *framebuffer)
2323 {
2324   CoglMatrixStack *modelview_stack =
2325     _cogl_framebuffer_get_modelview_stack (framebuffer);
2326   _cogl_matrix_stack_push (modelview_stack);
2327
2328   if (framebuffer->context->current_draw_buffer == framebuffer)
2329     framebuffer->context->current_draw_buffer_changes |=
2330       COGL_FRAMEBUFFER_STATE_MODELVIEW;
2331 }
2332
2333 void
2334 cogl_framebuffer_pop_matrix (CoglFramebuffer *framebuffer)
2335 {
2336   CoglMatrixStack *modelview_stack =
2337     _cogl_framebuffer_get_modelview_stack (framebuffer);
2338   _cogl_matrix_stack_pop (modelview_stack);
2339
2340   if (framebuffer->context->current_draw_buffer == framebuffer)
2341     framebuffer->context->current_draw_buffer_changes |=
2342       COGL_FRAMEBUFFER_STATE_MODELVIEW;
2343 }
2344
2345 void
2346 cogl_framebuffer_identity_matrix (CoglFramebuffer *framebuffer)
2347 {
2348   CoglMatrixStack *modelview_stack =
2349     _cogl_framebuffer_get_modelview_stack (framebuffer);
2350   _cogl_matrix_stack_load_identity (modelview_stack);
2351
2352   if (framebuffer->context->current_draw_buffer == framebuffer)
2353     framebuffer->context->current_draw_buffer_changes |=
2354       COGL_FRAMEBUFFER_STATE_MODELVIEW;
2355 }
2356
2357 void
2358 cogl_framebuffer_scale (CoglFramebuffer *framebuffer,
2359                         float x,
2360                         float y,
2361                         float z)
2362 {
2363   CoglMatrixStack *modelview_stack =
2364     _cogl_framebuffer_get_modelview_stack (framebuffer);
2365   _cogl_matrix_stack_scale (modelview_stack, x, y, z);
2366
2367   if (framebuffer->context->current_draw_buffer == framebuffer)
2368     framebuffer->context->current_draw_buffer_changes |=
2369       COGL_FRAMEBUFFER_STATE_MODELVIEW;
2370 }
2371
2372 void
2373 cogl_framebuffer_translate (CoglFramebuffer *framebuffer,
2374                             float x,
2375                             float y,
2376                             float z)
2377 {
2378   CoglMatrixStack *modelview_stack =
2379     _cogl_framebuffer_get_modelview_stack (framebuffer);
2380   _cogl_matrix_stack_translate (modelview_stack, x, y, z);
2381
2382   if (framebuffer->context->current_draw_buffer == framebuffer)
2383     framebuffer->context->current_draw_buffer_changes |=
2384       COGL_FRAMEBUFFER_STATE_MODELVIEW;
2385 }
2386
2387 void
2388 cogl_framebuffer_rotate (CoglFramebuffer *framebuffer,
2389                          float angle,
2390                          float x,
2391                          float y,
2392                          float z)
2393 {
2394   CoglMatrixStack *modelview_stack =
2395     _cogl_framebuffer_get_modelview_stack (framebuffer);
2396   _cogl_matrix_stack_rotate (modelview_stack, angle, x, y, z);
2397
2398   if (framebuffer->context->current_draw_buffer == framebuffer)
2399     framebuffer->context->current_draw_buffer_changes |=
2400       COGL_FRAMEBUFFER_STATE_MODELVIEW;
2401 }
2402
2403 void
2404 cogl_framebuffer_transform (CoglFramebuffer *framebuffer,
2405                             const CoglMatrix *matrix)
2406 {
2407   CoglMatrixStack *modelview_stack =
2408     _cogl_framebuffer_get_modelview_stack (framebuffer);
2409   _cogl_matrix_stack_multiply (modelview_stack, matrix);
2410
2411   if (framebuffer->context->current_draw_buffer == framebuffer)
2412     framebuffer->context->current_draw_buffer_changes |=
2413       COGL_FRAMEBUFFER_STATE_MODELVIEW;
2414 }
2415
2416 void
2417 cogl_framebuffer_perspective (CoglFramebuffer *framebuffer,
2418                               float fov_y,
2419                               float aspect,
2420                               float z_near,
2421                               float z_far)
2422 {
2423   float ymax = z_near * tanf (fov_y * G_PI / 360.0);
2424
2425   cogl_framebuffer_frustum (framebuffer,
2426                             -ymax * aspect,  /* left */
2427                             ymax * aspect,   /* right */
2428                             -ymax,           /* bottom */
2429                             ymax,            /* top */
2430                             z_near,
2431                             z_far);
2432
2433   if (framebuffer->context->current_draw_buffer == framebuffer)
2434     framebuffer->context->current_draw_buffer_changes |=
2435       COGL_FRAMEBUFFER_STATE_PROJECTION;
2436 }
2437
2438 void
2439 cogl_framebuffer_frustum (CoglFramebuffer *framebuffer,
2440                           float left,
2441                           float right,
2442                           float bottom,
2443                           float top,
2444                           float z_near,
2445                           float z_far)
2446 {
2447   CoglMatrixStack *projection_stack =
2448     _cogl_framebuffer_get_projection_stack (framebuffer);
2449
2450   /* XXX: The projection matrix isn't currently tracked in the journal
2451    * so we need to flush all journaled primitives first... */
2452   _cogl_framebuffer_flush_journal (framebuffer);
2453
2454   _cogl_matrix_stack_load_identity (projection_stack);
2455
2456   _cogl_matrix_stack_frustum (projection_stack,
2457                               left,
2458                               right,
2459                               bottom,
2460                               top,
2461                               z_near,
2462                               z_far);
2463
2464   if (framebuffer->context->current_draw_buffer == framebuffer)
2465     framebuffer->context->current_draw_buffer_changes |=
2466       COGL_FRAMEBUFFER_STATE_PROJECTION;
2467 }
2468
2469 void
2470 cogl_framebuffer_orthographic (CoglFramebuffer *framebuffer,
2471                                float x_1,
2472                                float y_1,
2473                                float x_2,
2474                                float y_2,
2475                                float near,
2476                                float far)
2477 {
2478   CoglMatrix ortho;
2479   CoglMatrixStack *projection_stack =
2480     _cogl_framebuffer_get_projection_stack (framebuffer);
2481
2482   /* XXX: The projection matrix isn't currently tracked in the journal
2483    * so we need to flush all journaled primitives first... */
2484   _cogl_framebuffer_flush_journal (framebuffer);
2485
2486   cogl_matrix_init_identity (&ortho);
2487   cogl_matrix_orthographic (&ortho, x_1, y_1, x_2, y_2, near, far);
2488   _cogl_matrix_stack_set (projection_stack, &ortho);
2489
2490   if (framebuffer->context->current_draw_buffer == framebuffer)
2491     framebuffer->context->current_draw_buffer_changes |=
2492       COGL_FRAMEBUFFER_STATE_PROJECTION;
2493 }
2494
2495 void
2496 _cogl_framebuffer_push_projection (CoglFramebuffer *framebuffer)
2497 {
2498   CoglMatrixStack *projection_stack =
2499     _cogl_framebuffer_get_projection_stack (framebuffer);
2500   _cogl_matrix_stack_push (projection_stack);
2501
2502   if (framebuffer->context->current_draw_buffer == framebuffer)
2503     framebuffer->context->current_draw_buffer_changes |=
2504       COGL_FRAMEBUFFER_STATE_PROJECTION;
2505 }
2506
2507 void
2508 _cogl_framebuffer_pop_projection (CoglFramebuffer *framebuffer)
2509 {
2510   CoglMatrixStack *projection_stack =
2511     _cogl_framebuffer_get_projection_stack (framebuffer);
2512   _cogl_matrix_stack_pop (projection_stack);
2513
2514   if (framebuffer->context->current_draw_buffer == framebuffer)
2515     framebuffer->context->current_draw_buffer_changes |=
2516       COGL_FRAMEBUFFER_STATE_PROJECTION;
2517 }
2518
2519 void
2520 cogl_framebuffer_get_modelview_matrix (CoglFramebuffer *framebuffer,
2521                                        CoglMatrix *matrix)
2522 {
2523   CoglMatrixStack *modelview_stack =
2524     _cogl_framebuffer_get_modelview_stack (framebuffer);
2525   _cogl_matrix_stack_get (modelview_stack, matrix);
2526   _COGL_MATRIX_DEBUG_PRINT (matrix);
2527 }
2528
2529 void
2530 cogl_framebuffer_set_modelview_matrix (CoglFramebuffer *framebuffer,
2531                                        CoglMatrix *matrix)
2532 {
2533   CoglMatrixStack *modelview_stack =
2534     _cogl_framebuffer_get_modelview_stack (framebuffer);
2535   _cogl_matrix_stack_set (modelview_stack, matrix);
2536
2537   if (framebuffer->context->current_draw_buffer == framebuffer)
2538     framebuffer->context->current_draw_buffer_changes |=
2539       COGL_FRAMEBUFFER_STATE_MODELVIEW;
2540
2541   _COGL_MATRIX_DEBUG_PRINT (matrix);
2542 }
2543
2544 void
2545 cogl_framebuffer_get_projection_matrix (CoglFramebuffer *framebuffer,
2546                                         CoglMatrix *matrix)
2547 {
2548   CoglMatrixStack *projection_stack =
2549     _cogl_framebuffer_get_projection_stack (framebuffer);
2550   _cogl_matrix_stack_get (projection_stack, matrix);
2551   _COGL_MATRIX_DEBUG_PRINT (matrix);
2552 }
2553
2554 void
2555 cogl_framebuffer_set_projection_matrix (CoglFramebuffer *framebuffer,
2556                                         CoglMatrix *matrix)
2557 {
2558   CoglMatrixStack *projection_stack =
2559     _cogl_framebuffer_get_projection_stack (framebuffer);
2560
2561   /* XXX: The projection matrix isn't currently tracked in the journal
2562    * so we need to flush all journaled primitives first... */
2563   _cogl_framebuffer_flush_journal (framebuffer);
2564
2565   _cogl_matrix_stack_set (projection_stack, matrix);
2566
2567   if (framebuffer->context->current_draw_buffer == framebuffer)
2568     framebuffer->context->current_draw_buffer_changes |=
2569       COGL_FRAMEBUFFER_STATE_PROJECTION;
2570
2571   _COGL_MATRIX_DEBUG_PRINT (matrix);
2572 }
2573
2574 void
2575 cogl_framebuffer_push_scissor_clip (CoglFramebuffer *framebuffer,
2576                                     int x,
2577                                     int y,
2578                                     int width,
2579                                     int height)
2580 {
2581   CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
2582
2583   clip_state->stacks->data =
2584     _cogl_clip_stack_push_window_rectangle (clip_state->stacks->data,
2585                                             x, y, width, height);
2586
2587   if (framebuffer->context->current_draw_buffer == framebuffer)
2588     framebuffer->context->current_draw_buffer_changes |=
2589       COGL_FRAMEBUFFER_STATE_CLIP;
2590 }
2591
2592 void
2593 cogl_framebuffer_push_rectangle_clip (CoglFramebuffer *framebuffer,
2594                                       float x_1,
2595                                       float y_1,
2596                                       float x_2,
2597                                       float y_2)
2598 {
2599   CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
2600   CoglMatrix modelview_matrix;
2601
2602   cogl_framebuffer_get_modelview_matrix (framebuffer, &modelview_matrix);
2603
2604   clip_state->stacks->data =
2605     _cogl_clip_stack_push_rectangle (clip_state->stacks->data,
2606                                      x_1, y_1, x_2, y_2,
2607                                      &modelview_matrix);
2608
2609   if (framebuffer->context->current_draw_buffer == framebuffer)
2610     framebuffer->context->current_draw_buffer_changes |=
2611       COGL_FRAMEBUFFER_STATE_CLIP;
2612 }
2613
2614 void
2615 cogl_framebuffer_push_path_clip (CoglFramebuffer *framebuffer,
2616                                  CoglPath *path)
2617 {
2618   CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
2619   CoglMatrix modelview_matrix;
2620
2621   cogl_framebuffer_get_modelview_matrix (framebuffer, &modelview_matrix);
2622
2623   clip_state->stacks->data =
2624     _cogl_clip_stack_push_from_path (clip_state->stacks->data,
2625                                      path,
2626                                      &modelview_matrix);
2627
2628   if (framebuffer->context->current_draw_buffer == framebuffer)
2629     framebuffer->context->current_draw_buffer_changes |=
2630       COGL_FRAMEBUFFER_STATE_CLIP;
2631 }
2632
2633 void
2634 cogl_framebuffer_push_primitive_clip (CoglFramebuffer *framebuffer,
2635                                       CoglPrimitive *primitive,
2636                                       float bounds_x1,
2637                                       float bounds_y1,
2638                                       float bounds_x2,
2639                                       float bounds_y2)
2640 {
2641   CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
2642   CoglMatrix modelview_matrix;
2643
2644   cogl_get_modelview_matrix (&modelview_matrix);
2645
2646   clip_state->stacks->data =
2647     _cogl_clip_stack_push_primitive (clip_state->stacks->data,
2648                                      primitive,
2649                                      bounds_x1, bounds_y1,
2650                                      bounds_x2, bounds_y2,
2651                                      &modelview_matrix);
2652
2653   if (framebuffer->context->current_draw_buffer == framebuffer)
2654     framebuffer->context->current_draw_buffer_changes |=
2655       COGL_FRAMEBUFFER_STATE_CLIP;
2656 }
2657
2658 void
2659 cogl_framebuffer_pop_clip (CoglFramebuffer *framebuffer)
2660 {
2661   CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
2662
2663   clip_state->stacks->data = _cogl_clip_stack_pop (clip_state->stacks->data);
2664
2665   if (framebuffer->context->current_draw_buffer == framebuffer)
2666     framebuffer->context->current_draw_buffer_changes |=
2667       COGL_FRAMEBUFFER_STATE_CLIP;
2668 }
2669
2670 void
2671 _cogl_framebuffer_save_clip_stack (CoglFramebuffer *framebuffer)
2672 {
2673   CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
2674   _cogl_clip_state_save_clip_stack (clip_state);
2675
2676   if (framebuffer->context->current_draw_buffer == framebuffer)
2677     framebuffer->context->current_draw_buffer_changes |=
2678       COGL_FRAMEBUFFER_STATE_CLIP;
2679 }
2680
2681 void
2682 _cogl_framebuffer_restore_clip_stack (CoglFramebuffer *framebuffer)
2683 {
2684   CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
2685   _cogl_clip_state_restore_clip_stack (clip_state);
2686
2687   if (framebuffer->context->current_draw_buffer == framebuffer)
2688     framebuffer->context->current_draw_buffer_changes |=
2689       COGL_FRAMEBUFFER_STATE_CLIP;
2690 }
2691
2692 void
2693 _cogl_framebuffer_unref (CoglFramebuffer *framebuffer)
2694 {
2695   /* The journal holds a reference to the framebuffer whenever it is
2696      non-empty. Therefore if the journal is non-empty and we will have
2697      exactly one reference then we know the journal is the only thing
2698      keeping the framebuffer alive. In that case we want to flush the
2699      journal and let the framebuffer die. It is fine at this point if
2700      flushing the journal causes something else to take a reference to
2701      it and it comes back to life */
2702   if (framebuffer->journal->entries->len > 0)
2703     {
2704       unsigned int ref_count = ((CoglObject *) framebuffer)->ref_count;
2705
2706       /* There should be at least two references - the one we are
2707          about to drop and the one held by the journal */
2708       if (ref_count < 2)
2709         g_warning ("Inconsistent ref count on a framebuffer with journal "
2710                    "entries.");
2711
2712       if (ref_count == 2)
2713         _cogl_framebuffer_flush_journal (framebuffer);
2714     }
2715
2716   /* Chain-up */
2717   _cogl_object_default_unref (framebuffer);
2718 }
2719
2720 #ifdef COGL_ENABLE_DEBUG
2721 static int
2722 get_index (void *indices,
2723            CoglIndicesType type,
2724            int _index)
2725 {
2726   if (!indices)
2727     return _index;
2728
2729   switch (type)
2730     {
2731     case COGL_INDICES_TYPE_UNSIGNED_BYTE:
2732       return ((guint8 *)indices)[_index];
2733     case COGL_INDICES_TYPE_UNSIGNED_SHORT:
2734       return ((guint16 *)indices)[_index];
2735     case COGL_INDICES_TYPE_UNSIGNED_INT:
2736       return ((guint32 *)indices)[_index];
2737     }
2738
2739   g_return_val_if_reached (0);
2740 }
2741
2742 static void
2743 add_line (guint32 *line_indices,
2744           int base,
2745           void *user_indices,
2746           CoglIndicesType user_indices_type,
2747           int index0,
2748           int index1,
2749           int *pos)
2750 {
2751   index0 = get_index (user_indices, user_indices_type, index0);
2752   index1 = get_index (user_indices, user_indices_type, index1);
2753
2754   line_indices[(*pos)++] = base + index0;
2755   line_indices[(*pos)++] = base + index1;
2756 }
2757
2758 static int
2759 get_line_count (CoglVerticesMode mode, int n_vertices)
2760 {
2761   if (mode == COGL_VERTICES_MODE_TRIANGLES &&
2762       (n_vertices % 3) == 0)
2763     {
2764       return n_vertices;
2765     }
2766   else if (mode == COGL_VERTICES_MODE_TRIANGLE_FAN &&
2767            n_vertices >= 3)
2768     {
2769       return 2 * n_vertices - 3;
2770     }
2771   else if (mode == COGL_VERTICES_MODE_TRIANGLE_STRIP &&
2772            n_vertices >= 3)
2773     {
2774       return 2 * n_vertices - 3;
2775     }
2776     /* In the journal we are a bit sneaky and actually use GL_QUADS
2777      * which isn't actually a valid CoglVerticesMode! */
2778 #ifdef HAVE_COGL_GL
2779   else if (mode == GL_QUADS && (n_vertices % 4) == 0)
2780     {
2781       return n_vertices;
2782     }
2783 #endif
2784
2785   g_return_val_if_reached (0);
2786 }
2787
2788 static CoglIndices *
2789 get_wire_line_indices (CoglContext *ctx,
2790                        CoglVerticesMode mode,
2791                        int first_vertex,
2792                        int n_vertices_in,
2793                        CoglIndices *user_indices,
2794                        int *n_indices)
2795 {
2796   int n_lines;
2797   guint32 *line_indices;
2798   CoglIndexBuffer *index_buffer;
2799   void *indices;
2800   CoglIndicesType indices_type;
2801   int base = first_vertex;
2802   int pos;
2803   int i;
2804   CoglIndices *ret;
2805
2806   if (user_indices)
2807     {
2808       index_buffer = cogl_indices_get_buffer (user_indices);
2809       indices = cogl_buffer_map (COGL_BUFFER (index_buffer),
2810                                  COGL_BUFFER_ACCESS_READ, 0);
2811       indices_type = cogl_indices_get_type (user_indices);
2812     }
2813   else
2814     {
2815       index_buffer = NULL;
2816       indices = NULL;
2817       indices_type = COGL_INDICES_TYPE_UNSIGNED_BYTE;
2818     }
2819
2820   n_lines = get_line_count (mode, n_vertices_in);
2821
2822   /* Note: we are using COGL_INDICES_TYPE_UNSIGNED_INT so 4 bytes per index. */
2823   line_indices = g_malloc (4 * n_lines * 2);
2824
2825   pos = 0;
2826
2827   if (mode == COGL_VERTICES_MODE_TRIANGLES &&
2828       (n_vertices_in % 3) == 0)
2829     {
2830       for (i = 0; i < n_vertices_in; i += 3)
2831         {
2832           add_line (line_indices, base, indices, indices_type, i,   i+1, &pos);
2833           add_line (line_indices, base, indices, indices_type, i+1, i+2, &pos);
2834           add_line (line_indices, base, indices, indices_type, i+2, i,   &pos);
2835         }
2836     }
2837   else if (mode == COGL_VERTICES_MODE_TRIANGLE_FAN &&
2838            n_vertices_in >= 3)
2839     {
2840       add_line (line_indices, base, indices, indices_type, 0, 1, &pos);
2841       add_line (line_indices, base, indices, indices_type, 1, 2, &pos);
2842       add_line (line_indices, base, indices, indices_type, 0, 2, &pos);
2843
2844       for (i = 3; i < n_vertices_in; i++)
2845         {
2846           add_line (line_indices, base, indices, indices_type, i - 1, i, &pos);
2847           add_line (line_indices, base, indices, indices_type, 0,     i, &pos);
2848         }
2849     }
2850   else if (mode == COGL_VERTICES_MODE_TRIANGLE_STRIP &&
2851            n_vertices_in >= 3)
2852     {
2853       add_line (line_indices, base, indices, indices_type, 0, 1, &pos);
2854       add_line (line_indices, base, indices, indices_type, 1, 2, &pos);
2855       add_line (line_indices, base, indices, indices_type, 0, 2, &pos);
2856
2857       for (i = 3; i < n_vertices_in; i++)
2858         {
2859           add_line (line_indices, base, indices, indices_type, i - 1, i, &pos);
2860           add_line (line_indices, base, indices, indices_type, i - 2, i, &pos);
2861         }
2862     }
2863     /* In the journal we are a bit sneaky and actually use GL_QUADS
2864      * which isn't actually a valid CoglVerticesMode! */
2865 #ifdef HAVE_COGL_GL
2866   else if (mode == GL_QUADS && (n_vertices_in % 4) == 0)
2867     {
2868       for (i = 0; i < n_vertices_in; i += 4)
2869         {
2870           add_line (line_indices,
2871                     base, indices, indices_type, i,     i + 1, &pos);
2872           add_line (line_indices,
2873                     base, indices, indices_type, i + 1, i + 2, &pos);
2874           add_line (line_indices,
2875                     base, indices, indices_type, i + 2, i + 3, &pos);
2876           add_line (line_indices,
2877                     base, indices, indices_type, i + 3, i,     &pos);
2878         }
2879     }
2880 #endif
2881
2882   if (user_indices)
2883     cogl_buffer_unmap (COGL_BUFFER (index_buffer));
2884
2885   *n_indices = n_lines * 2;
2886
2887   ret = cogl_indices_new (ctx,
2888                           COGL_INDICES_TYPE_UNSIGNED_INT,
2889                           line_indices,
2890                           *n_indices);
2891
2892   g_free (line_indices);
2893
2894   return ret;
2895 }
2896
2897 static gboolean
2898 remove_layer_cb (CoglPipeline *pipeline,
2899                  int layer_index,
2900                  void *user_data)
2901 {
2902   cogl_pipeline_remove_layer (pipeline, layer_index);
2903   return TRUE;
2904 }
2905
2906 static void
2907 pipeline_destroyed_cb (CoglPipeline *weak_pipeline, void *user_data)
2908 {
2909   CoglPipeline *original_pipeline = user_data;
2910
2911   /* XXX: I think we probably need to provide a custom unref function for
2912    * CoglPipeline because it's possible that we will reach this callback
2913    * because original_pipeline is being freed which means cogl_object_unref
2914    * will have already freed any associated user data.
2915    *
2916    * Setting more user data here will *probably* succeed but that may allocate
2917    * a new user-data array which could be leaked.
2918    *
2919    * Potentially we could have a _cogl_object_free_user_data function so
2920    * that a custom unref function could be written that can destroy weak
2921    * pipeline children before removing user data.
2922    */
2923   cogl_object_set_user_data (COGL_OBJECT (original_pipeline),
2924                              &wire_pipeline_key, NULL, NULL);
2925
2926   cogl_object_unref (weak_pipeline);
2927 }
2928
2929 static void
2930 draw_wireframe (CoglContext *ctx,
2931                 CoglFramebuffer *framebuffer,
2932                 CoglPipeline *pipeline,
2933                 CoglVerticesMode mode,
2934                 int first_vertex,
2935                 int n_vertices,
2936                 CoglAttribute **attributes,
2937                 int n_attributes,
2938                 CoglIndices *indices)
2939 {
2940   CoglIndices *wire_indices;
2941   CoglPipeline *wire_pipeline;
2942   int n_indices;
2943
2944   wire_indices = get_wire_line_indices (ctx,
2945                                         mode,
2946                                         first_vertex,
2947                                         n_vertices,
2948                                         indices,
2949                                         &n_indices);
2950
2951   wire_pipeline = cogl_object_get_user_data (COGL_OBJECT (pipeline),
2952                                              &wire_pipeline_key);
2953
2954   if (!wire_pipeline)
2955     {
2956       wire_pipeline =
2957         _cogl_pipeline_weak_copy (pipeline, pipeline_destroyed_cb, NULL);
2958
2959       cogl_object_set_user_data (COGL_OBJECT (pipeline),
2960                                  &wire_pipeline_key, wire_pipeline,
2961                                  NULL);
2962
2963       /* If we have glsl then the pipeline may have an associated
2964        * vertex program and since we'd like to see the results of the
2965        * vertex program in the wireframe we just add a final clobber
2966        * of the wire color leaving the rest of the state untouched. */
2967       if (cogl_has_feature (framebuffer->context, COGL_FEATURE_ID_GLSL))
2968         {
2969           CoglSnippet *snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
2970                                                    NULL,
2971                                                    NULL);
2972           cogl_snippet_set_replace (snippet,
2973                                     "cogl_color_out = "
2974                                       "vec4 (0.0, 1.0, 0.0, 1.0);\n");
2975
2976           cogl_pipeline_add_snippet (wire_pipeline, snippet);
2977           cogl_object_unref (snippet);
2978         }
2979       else
2980         {
2981           cogl_pipeline_foreach_layer (wire_pipeline, remove_layer_cb, NULL);
2982           cogl_pipeline_set_color4f (wire_pipeline, 0, 1, 0, 1);
2983         }
2984     }
2985
2986   /* temporarily disable the wireframe to avoid recursion! */
2987   COGL_DEBUG_CLEAR_FLAG (COGL_DEBUG_WIREFRAME);
2988   _cogl_framebuffer_draw_indexed_attributes (
2989                                            framebuffer,
2990                                            wire_pipeline,
2991                                            COGL_VERTICES_MODE_LINES,
2992                                            0,
2993                                            n_indices,
2994                                            wire_indices,
2995                                            attributes,
2996                                            n_attributes,
2997                                            COGL_DRAW_SKIP_JOURNAL_FLUSH |
2998                                            COGL_DRAW_SKIP_PIPELINE_VALIDATION |
2999                                            COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH |
3000                                            COGL_DRAW_SKIP_LEGACY_STATE);
3001   COGL_DEBUG_SET_FLAG (COGL_DEBUG_WIREFRAME);
3002
3003   cogl_object_unref (wire_indices);
3004 }
3005 #endif
3006
3007 /* This can be called directly by the CoglJournal to draw attributes
3008  * skipping the implicit journal flush, the framebuffer flush and
3009  * pipeline validation. */
3010 void
3011 _cogl_framebuffer_draw_attributes (CoglFramebuffer *framebuffer,
3012                                    CoglPipeline *pipeline,
3013                                    CoglVerticesMode mode,
3014                                    int first_vertex,
3015                                    int n_vertices,
3016                                    CoglAttribute **attributes,
3017                                    int n_attributes,
3018                                    CoglDrawFlags flags)
3019 {
3020 #ifdef COGL_ENABLE_DEBUG
3021   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WIREFRAME)))
3022     draw_wireframe (framebuffer->context,
3023                     framebuffer, pipeline,
3024                     mode, first_vertex, n_vertices,
3025                     attributes, n_attributes, NULL);
3026   else
3027 #endif
3028     {
3029       _cogl_flush_attributes_state (framebuffer, pipeline, flags,
3030                                     attributes, n_attributes);
3031
3032       GE (framebuffer->context,
3033           glDrawArrays ((GLenum)mode, first_vertex, n_vertices));
3034     }
3035 }
3036
3037 void
3038 cogl_framebuffer_draw_attributes (CoglFramebuffer *framebuffer,
3039                                   CoglPipeline *pipeline,
3040                                   CoglVerticesMode mode,
3041                                   int first_vertex,
3042                                   int n_vertices,
3043                                   CoglAttribute **attributes,
3044                                   int n_attributes)
3045 {
3046   _cogl_framebuffer_draw_attributes (framebuffer,
3047                                      pipeline,
3048                                      mode,
3049                                      first_vertex,
3050                                      n_vertices,
3051                                      attributes, n_attributes,
3052                                      COGL_DRAW_SKIP_LEGACY_STATE);
3053 }
3054
3055 void
3056 cogl_framebuffer_vdraw_attributes (CoglFramebuffer *framebuffer,
3057                                    CoglPipeline *pipeline,
3058                                    CoglVerticesMode mode,
3059                                    int first_vertex,
3060                                    int n_vertices,
3061                                    ...)
3062 {
3063   va_list ap;
3064   int n_attributes;
3065   CoglAttribute *attribute;
3066   CoglAttribute **attributes;
3067   int i;
3068
3069   va_start (ap, n_vertices);
3070   for (n_attributes = 0; va_arg (ap, CoglAttribute *); n_attributes++)
3071     ;
3072   va_end (ap);
3073
3074   attributes = g_alloca (sizeof (CoglAttribute *) * n_attributes);
3075
3076   va_start (ap, n_vertices);
3077   for (i = 0; (attribute = va_arg (ap, CoglAttribute *)); i++)
3078     attributes[i] = attribute;
3079   va_end (ap);
3080
3081   _cogl_framebuffer_draw_attributes (framebuffer,
3082                                      pipeline,
3083                                      mode, first_vertex, n_vertices,
3084                                      attributes, n_attributes,
3085                                      COGL_DRAW_SKIP_LEGACY_STATE);
3086 }
3087
3088 static size_t
3089 sizeof_index_type (CoglIndicesType type)
3090 {
3091   switch (type)
3092     {
3093     case COGL_INDICES_TYPE_UNSIGNED_BYTE:
3094       return 1;
3095     case COGL_INDICES_TYPE_UNSIGNED_SHORT:
3096       return 2;
3097     case COGL_INDICES_TYPE_UNSIGNED_INT:
3098       return 4;
3099     }
3100   g_return_val_if_reached (0);
3101 }
3102
3103 void
3104 _cogl_framebuffer_draw_indexed_attributes (CoglFramebuffer *framebuffer,
3105                                            CoglPipeline *pipeline,
3106                                            CoglVerticesMode mode,
3107                                            int first_vertex,
3108                                            int n_vertices,
3109                                            CoglIndices *indices,
3110                                            CoglAttribute **attributes,
3111                                            int n_attributes,
3112                                            CoglDrawFlags flags)
3113 {
3114 #ifdef COGL_ENABLE_DEBUG
3115   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WIREFRAME)))
3116     draw_wireframe (framebuffer->context,
3117                     framebuffer, pipeline,
3118                     mode, first_vertex, n_vertices,
3119                     attributes, n_attributes, indices);
3120   else
3121 #endif
3122     {
3123       CoglBuffer *buffer;
3124       guint8 *base;
3125       size_t buffer_offset;
3126       size_t index_size;
3127       GLenum indices_gl_type = 0;
3128
3129       _cogl_flush_attributes_state (framebuffer, pipeline, flags,
3130                                     attributes, n_attributes);
3131
3132       buffer = COGL_BUFFER (cogl_indices_get_buffer (indices));
3133       base = _cogl_buffer_bind (buffer, COGL_BUFFER_BIND_TARGET_INDEX_BUFFER);
3134       buffer_offset = cogl_indices_get_offset (indices);
3135       index_size = sizeof_index_type (cogl_indices_get_type (indices));
3136
3137       switch (cogl_indices_get_type (indices))
3138         {
3139         case COGL_INDICES_TYPE_UNSIGNED_BYTE:
3140           indices_gl_type = GL_UNSIGNED_BYTE;
3141           break;
3142         case COGL_INDICES_TYPE_UNSIGNED_SHORT:
3143           indices_gl_type = GL_UNSIGNED_SHORT;
3144           break;
3145         case COGL_INDICES_TYPE_UNSIGNED_INT:
3146           indices_gl_type = GL_UNSIGNED_INT;
3147           break;
3148         }
3149
3150       GE (framebuffer->context,
3151           glDrawElements ((GLenum)mode,
3152                           n_vertices,
3153                           indices_gl_type,
3154                           base + buffer_offset + index_size * first_vertex));
3155
3156       _cogl_buffer_unbind (buffer);
3157     }
3158 }
3159
3160 void
3161 cogl_framebuffer_draw_indexed_attributes (CoglFramebuffer *framebuffer,
3162                                           CoglPipeline *pipeline,
3163                                           CoglVerticesMode mode,
3164                                           int first_vertex,
3165                                           int n_vertices,
3166                                           CoglIndices *indices,
3167                                           CoglAttribute **attributes,
3168                                           int n_attributes)
3169 {
3170   _cogl_framebuffer_draw_indexed_attributes (framebuffer,
3171                                              pipeline,
3172                                              mode, first_vertex,
3173                                              n_vertices, indices,
3174                                              attributes, n_attributes,
3175                                              COGL_DRAW_SKIP_LEGACY_STATE);
3176 }
3177
3178 void
3179 cogl_framebuffer_vdraw_indexed_attributes (CoglFramebuffer *framebuffer,
3180                                            CoglPipeline *pipeline,
3181                                            CoglVerticesMode mode,
3182                                            int first_vertex,
3183                                            int n_vertices,
3184                                            CoglIndices *indices,
3185                                            ...)
3186 {
3187   va_list ap;
3188   int n_attributes;
3189   CoglAttribute **attributes;
3190   int i;
3191   CoglAttribute *attribute;
3192
3193   va_start (ap, indices);
3194   for (n_attributes = 0; va_arg (ap, CoglAttribute *); n_attributes++)
3195     ;
3196   va_end (ap);
3197
3198   attributes = g_alloca (sizeof (CoglAttribute *) * n_attributes);
3199
3200   va_start (ap, indices);
3201   for (i = 0; (attribute = va_arg (ap, CoglAttribute *)); i++)
3202     attributes[i] = attribute;
3203   va_end (ap);
3204
3205   _cogl_framebuffer_draw_indexed_attributes (framebuffer,
3206                                              pipeline,
3207                                              mode,
3208                                              first_vertex,
3209                                              n_vertices,
3210                                              indices,
3211                                              attributes,
3212                                              n_attributes,
3213                                              COGL_DRAW_SKIP_LEGACY_STATE);
3214 }
3215
3216 void
3217 _cogl_framebuffer_draw_primitive (CoglFramebuffer *framebuffer,
3218                                   CoglPipeline *pipeline,
3219                                   CoglPrimitive *primitive,
3220                                   CoglDrawFlags flags)
3221 {
3222   if (primitive->indices)
3223     _cogl_framebuffer_draw_indexed_attributes (framebuffer,
3224                                                pipeline,
3225                                                primitive->mode,
3226                                                primitive->first_vertex,
3227                                                primitive->n_vertices,
3228                                                primitive->indices,
3229                                                primitive->attributes,
3230                                                primitive->n_attributes,
3231                                                flags);
3232   else
3233     _cogl_framebuffer_draw_attributes (framebuffer,
3234                                        pipeline,
3235                                        primitive->mode,
3236                                        primitive->first_vertex,
3237                                        primitive->n_vertices,
3238                                        primitive->attributes,
3239                                        primitive->n_attributes,
3240                                        flags);
3241 }
3242
3243 void
3244 cogl_framebuffer_draw_primitive (CoglFramebuffer *framebuffer,
3245                                  CoglPipeline *pipeline,
3246                                  CoglPrimitive *primitive)
3247 {
3248   _cogl_framebuffer_draw_primitive (framebuffer, pipeline, primitive,
3249                                     COGL_DRAW_SKIP_LEGACY_STATE);
3250 }
3251
3252 void
3253 cogl_framebuffer_draw_rectangle (CoglFramebuffer *framebuffer,
3254                                  CoglPipeline *pipeline,
3255                                  float x_1,
3256                                  float y_1,
3257                                  float x_2,
3258                                  float y_2)
3259 {
3260   const float position[4] = {x_1, y_1, x_2, y_2};
3261   CoglMultiTexturedRect rect;
3262
3263   /* XXX: All the _*_rectangle* APIs normalize their input into an array of
3264    * _CoglMultiTexturedRect rectangles and pass these on to our work horse;
3265    * _cogl_framebuffer_draw_multitextured_rectangles.
3266    */
3267
3268   rect.position = position;
3269   rect.tex_coords = NULL;
3270   rect.tex_coords_len = 0;
3271
3272   _cogl_framebuffer_draw_multitextured_rectangles (framebuffer,
3273                                                    pipeline,
3274                                                    &rect,
3275                                                    1,
3276                                                    TRUE);
3277 }
3278
3279 void
3280 cogl_framebuffer_draw_textured_rectangle (CoglFramebuffer *framebuffer,
3281                                           CoglPipeline *pipeline,
3282                                           float x_1,
3283                                           float y_1,
3284                                           float x_2,
3285                                           float y_2,
3286                                           float s_1,
3287                                           float t_1,
3288                                           float s_2,
3289                                           float t_2)
3290 {
3291   const float position[4] = {x_1, y_1, x_2, y_2};
3292   const float tex_coords[4] = {s_1, t_1, s_2, t_2};
3293   CoglMultiTexturedRect rect;
3294
3295   /* XXX: All the _*_rectangle* APIs normalize their input into an array of
3296    * CoglMultiTexturedRect rectangles and pass these on to our work horse;
3297    * _cogl_framebuffer_draw_multitextured_rectangles.
3298    */
3299
3300   rect.position = position;
3301   rect.tex_coords = tex_coords;
3302   rect.tex_coords_len = 4;
3303
3304   _cogl_framebuffer_draw_multitextured_rectangles (framebuffer,
3305                                                    pipeline,
3306                                                    &rect,
3307                                                    1,
3308                                                    TRUE);
3309 }
3310
3311 void
3312 cogl_framebuffer_draw_multitextured_rectangle (CoglFramebuffer *framebuffer,
3313                                                CoglPipeline *pipeline,
3314                                                float x_1,
3315                                                float y_1,
3316                                                float x_2,
3317                                                float y_2,
3318                                                const float *tex_coords,
3319                                                int tex_coords_len)
3320 {
3321   const float position[4] = {x_1, y_1, x_2, y_2};
3322   CoglMultiTexturedRect rect;
3323
3324   /* XXX: All the _*_rectangle* APIs normalize their input into an array of
3325    * CoglMultiTexturedRect rectangles and pass these on to our work horse;
3326    * _cogl_framebuffer_draw_multitextured_rectangles.
3327    */
3328
3329   rect.position = position;
3330   rect.tex_coords = tex_coords;
3331   rect.tex_coords_len = tex_coords_len;
3332
3333   _cogl_framebuffer_draw_multitextured_rectangles (framebuffer,
3334                                                    pipeline,
3335                                                    &rect,
3336                                                    1,
3337                                                    TRUE);
3338 }
3339
3340 void
3341 cogl_framebuffer_draw_rectangles (CoglFramebuffer *framebuffer,
3342                                   CoglPipeline *pipeline,
3343                                   const float *coordinates,
3344                                   unsigned int n_rectangles)
3345 {
3346   CoglMultiTexturedRect *rects;
3347   int i;
3348
3349   /* XXX: All the _*_rectangle* APIs normalize their input into an array of
3350    * CoglMultiTexturedRect rectangles and pass these on to our work horse;
3351    * _cogl_framebuffer_draw_multitextured_rectangles.
3352    */
3353
3354   rects = g_alloca (n_rectangles * sizeof (CoglMultiTexturedRect));
3355
3356   for (i = 0; i < n_rectangles; i++)
3357     {
3358       rects[i].position = &coordinates[i * 4];
3359       rects[i].tex_coords = NULL;
3360       rects[i].tex_coords_len = 0;
3361     }
3362
3363   _cogl_framebuffer_draw_multitextured_rectangles (framebuffer,
3364                                                    pipeline,
3365                                                    rects,
3366                                                    n_rectangles,
3367                                                    TRUE);
3368 }
3369
3370 void
3371 cogl_framebuffer_draw_textured_rectangles (CoglFramebuffer *framebuffer,
3372                                            CoglPipeline *pipeline,
3373                                            const float *coordinates,
3374                                            unsigned int n_rectangles)
3375 {
3376   CoglMultiTexturedRect *rects;
3377   int i;
3378
3379   /* XXX: All the _*_rectangle* APIs normalize their input into an array of
3380    * _CoglMultiTexturedRect rectangles and pass these on to our work horse;
3381    * _cogl_framebuffer_draw_multitextured_rectangles.
3382    */
3383
3384   rects = g_alloca (n_rectangles * sizeof (CoglMultiTexturedRect));
3385
3386   for (i = 0; i < n_rectangles; i++)
3387     {
3388       rects[i].position = &coordinates[i * 8];
3389       rects[i].tex_coords = &coordinates[i * 8 + 4];
3390       rects[i].tex_coords_len = 4;
3391     }
3392
3393   _cogl_framebuffer_draw_multitextured_rectangles (framebuffer,
3394                                                    pipeline,
3395                                                    rects,
3396                                                    n_rectangles,
3397                                                    TRUE);
3398 }