4 * An object oriented GL/GLES Abstraction/Utility Layer
6 * Copyright (C) 2007,2008,2009 Intel Corporation.
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.
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.
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/>.
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"
51 #ifndef GL_FRAMEBUFFER
52 #define GL_FRAMEBUFFER 0x8D40
54 #ifndef GL_RENDERBUFFER
55 #define GL_RENDERBUFFER 0x8D41
57 #ifndef GL_STENCIL_ATTACHMENT
58 #define GL_STENCIL_ATTACHMENT 0x8D00
60 #ifndef GL_COLOR_ATTACHMENT0
61 #define GL_COLOR_ATTACHMENT0 0x8CE0
63 #ifndef GL_FRAMEBUFFER_COMPLETE
64 #define GL_FRAMEBUFFER_COMPLETE 0x8CD5
66 #ifndef GL_STENCIL_INDEX8
67 #define GL_STENCIL_INDEX8 0x8D48
69 #ifndef GL_DEPTH_STENCIL
70 #define GL_DEPTH_STENCIL 0x84F9
72 #ifndef GL_DEPTH24_STENCIL8
73 #define GL_DEPTH24_STENCIL8 0x88F0
75 #ifndef GL_DEPTH_ATTACHMENT
76 #define GL_DEPTH_ATTACHMENT 0x8D00
78 #ifndef GL_DEPTH_COMPONENT16
79 #define GL_DEPTH_COMPONENT16 0x81A5
81 #ifndef GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE
82 #define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212
84 #ifndef GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE
85 #define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213
87 #ifndef GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE
88 #define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214
90 #ifndef GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE
91 #define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215
93 #ifndef GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE
94 #define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216
96 #ifndef GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE
97 #define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217
99 #ifndef GL_READ_FRAMEBUFFER
100 #define GL_READ_FRAMEBUFFER 0x8CA8
102 #ifndef GL_DRAW_FRAMEBUFFER
103 #define GL_DRAW_FRAMEBUFFER 0x8CA9
105 #ifndef GL_TEXTURE_SAMPLES_IMG
106 #define GL_TEXTURE_SAMPLES_IMG 0x9136
108 #ifndef GL_PACK_INVERT_MESA
109 #define GL_PACK_INVERT_MESA 0x8758
114 _TRY_DEPTH_STENCIL = 1L<<0,
115 _TRY_DEPTH24_STENCIL8 = 1L<<1,
120 typedef struct _CoglFramebufferStackEntry
122 CoglFramebuffer *draw_buffer;
123 CoglFramebuffer *read_buffer;
124 } CoglFramebufferStackEntry;
126 extern CoglObjectClass _cogl_onscreen_class;
128 static CoglUserDataKey wire_pipeline_key;
130 static void _cogl_offscreen_free (CoglOffscreen *offscreen);
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);
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.
144 cogl_framebuffer_error_quark (void)
146 return g_quark_from_static_string ("cogl-framebuffer-error-quark");
150 cogl_is_framebuffer (void *object)
152 CoglObject *obj = object;
157 return (obj->klass == &_cogl_onscreen_class ||
158 obj->klass == &_cogl_offscreen_class);
162 _cogl_framebuffer_init (CoglFramebuffer *framebuffer,
164 CoglFramebufferType type,
165 CoglPixelFormat format,
169 framebuffer->context = cogl_object_ref (ctx);
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;
181 framebuffer->modelview_stack = _cogl_matrix_stack_new ();
182 framebuffer->projection_stack = _cogl_matrix_stack_new ();
184 framebuffer->dirty_bitmasks = TRUE;
186 framebuffer->color_mask = COGL_COLOR_MASK_ALL;
188 framebuffer->samples_per_pixel = 0;
190 /* Initialise the clip stack */
191 _cogl_clip_state_init (&framebuffer->clip_state);
193 framebuffer->journal = _cogl_journal_new (framebuffer);
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.
200 framebuffer->clear_clip_dirty = TRUE;
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.
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
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.
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.
228 ctx->framebuffers = g_list_prepend (ctx->framebuffers, framebuffer);
232 _cogl_framebuffer_free (CoglFramebuffer *framebuffer)
234 CoglContext *ctx = framebuffer->context;
236 _cogl_clip_state_destroy (&framebuffer->clip_state);
238 cogl_object_unref (framebuffer->modelview_stack);
239 framebuffer->modelview_stack = NULL;
241 cogl_object_unref (framebuffer->projection_stack);
242 framebuffer->projection_stack = NULL;
244 cogl_object_unref (framebuffer->journal);
246 ctx->framebuffers = g_list_remove (ctx->framebuffers, framebuffer);
247 cogl_object_unref (ctx);
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;
255 const CoglWinsysVtable *
256 _cogl_framebuffer_get_winsys (CoglFramebuffer *framebuffer)
258 return framebuffer->context->display->renderer->winsys_vtable;
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
266 _cogl_framebuffer_clear_without_flush4f (CoglFramebuffer *framebuffer,
267 unsigned long buffers,
273 GLbitfield gl_buffers = 0;
275 _COGL_GET_CONTEXT (ctx, NO_RETVAL);
277 if (buffers & COGL_BUFFER_BIT_COLOR)
279 GE( ctx, glClearColor (red, green, blue, alpha) );
280 gl_buffers |= GL_COLOR_BUFFER_BIT;
282 if (ctx->current_gl_color_mask != framebuffer->color_mask)
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--;
297 if (buffers & COGL_BUFFER_BIT_DEPTH)
298 gl_buffers |= GL_DEPTH_BUFFER_BIT;
300 if (buffers & COGL_BUFFER_BIT_STENCIL)
301 gl_buffers |= GL_STENCIL_BUFFER_BIT;
305 static gboolean shown = FALSE;
309 g_warning ("You should specify at least one auxiliary buffer "
310 "when calling cogl_clear");
316 GE (ctx, glClear (gl_buffers));
320 _cogl_framebuffer_dirty (CoglFramebuffer *framebuffer)
322 framebuffer->clear_clip_dirty = TRUE;
326 cogl_framebuffer_clear4f (CoglFramebuffer *framebuffer,
327 unsigned long buffers,
333 CoglClipStack *clip_stack = _cogl_framebuffer_get_clip_stack (framebuffer);
339 _cogl_clip_stack_get_bounds (clip_stack,
340 &scissor_x0, &scissor_y0,
341 &scissor_x1, &scissor_y1);
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
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
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.
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
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
374 * Note: Comparing without an epsilon is considered
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)
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
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.
406 if (_cogl_journal_all_entries_within_bounds (framebuffer->journal,
407 scissor_x0, scissor_y0,
408 scissor_x1, scissor_y1))
410 _cogl_journal_discard (framebuffer->journal);
416 _cogl_journal_discard (framebuffer->journal);
421 COGL_NOTE (DRAW, "Clear begin");
423 _cogl_framebuffer_flush_journal (framebuffer);
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);
431 _cogl_framebuffer_clear_without_flush4f (framebuffer, buffers,
432 red, green, blue, alpha);
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
438 if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_RECTANGLES)) &&
439 buffers & COGL_BUFFER_BIT_COLOR)
441 framebuffer->context->journal_rectangles_color = 1;
444 COGL_NOTE (DRAW, "Clear end");
448 if (buffers & COGL_BUFFER_BIT_COLOR && buffers & COGL_BUFFER_BIT_DEPTH)
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;
460 /* NB: A clear may be scissored so we need to track the extents
461 * that the clear is applicable too... */
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);
472 /* FIXME: set degenerate clip */
476 _cogl_framebuffer_dirty (framebuffer);
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.
485 cogl_framebuffer_clear (CoglFramebuffer *framebuffer,
486 unsigned long buffers,
487 const CoglColor *color)
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));
497 cogl_framebuffer_get_width (CoglFramebuffer *framebuffer)
499 return framebuffer->width;
503 cogl_framebuffer_get_height (CoglFramebuffer *framebuffer)
505 return framebuffer->height;
509 _cogl_framebuffer_get_clip_state (CoglFramebuffer *framebuffer)
511 return &framebuffer->clip_state;
515 _cogl_framebuffer_get_clip_stack (CoglFramebuffer *framebuffer)
517 CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
519 return _cogl_clip_state_get_stack (clip_state);
523 _cogl_framebuffer_set_clip_stack (CoglFramebuffer *framebuffer,
524 CoglClipStack *stack)
526 CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
528 _cogl_clip_state_set_stack (clip_state, stack);
532 cogl_framebuffer_set_viewport (CoglFramebuffer *framebuffer,
538 _COGL_RETURN_IF_FAIL (width > 0 && height > 0);
540 if (framebuffer->viewport_x == x &&
541 framebuffer->viewport_y == y &&
542 framebuffer->viewport_width == width &&
543 framebuffer->viewport_height == height)
546 _cogl_framebuffer_flush_journal (framebuffer);
548 framebuffer->viewport_x = x;
549 framebuffer->viewport_y = y;
550 framebuffer->viewport_width = width;
551 framebuffer->viewport_height = height;
553 if (framebuffer->context->current_draw_buffer == framebuffer)
554 framebuffer->context->current_draw_buffer_changes |=
555 COGL_FRAMEBUFFER_STATE_VIEWPORT;
559 cogl_framebuffer_get_viewport_x (CoglFramebuffer *framebuffer)
561 return framebuffer->viewport_x;
565 cogl_framebuffer_get_viewport_y (CoglFramebuffer *framebuffer)
567 return framebuffer->viewport_y;
571 cogl_framebuffer_get_viewport_width (CoglFramebuffer *framebuffer)
573 return framebuffer->viewport_width;
577 cogl_framebuffer_get_viewport_height (CoglFramebuffer *framebuffer)
579 return framebuffer->viewport_height;
583 cogl_framebuffer_get_viewport4fv (CoglFramebuffer *framebuffer,
586 viewport[0] = framebuffer->viewport_x;
587 viewport[1] = framebuffer->viewport_y;
588 viewport[2] = framebuffer->viewport_width;
589 viewport[3] = framebuffer->viewport_height;
593 _cogl_framebuffer_get_modelview_stack (CoglFramebuffer *framebuffer)
595 return framebuffer->modelview_stack;
599 _cogl_framebuffer_get_projection_stack (CoglFramebuffer *framebuffer)
601 return framebuffer->projection_stack;
605 _cogl_framebuffer_add_dependency (CoglFramebuffer *framebuffer,
606 CoglFramebuffer *dependency)
610 for (l = framebuffer->deps; l; l = l->next)
612 CoglFramebuffer *existing_dep = l->data;
613 if (existing_dep == dependency)
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... */
621 g_list_prepend (framebuffer->deps, cogl_object_ref (dependency));
625 _cogl_framebuffer_remove_all_dependencies (CoglFramebuffer *framebuffer)
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;
635 _cogl_framebuffer_flush_journal (CoglFramebuffer *framebuffer)
637 _cogl_journal_flush (framebuffer->journal);
641 _cogl_framebuffer_flush_dependency_journals (CoglFramebuffer *framebuffer)
644 for (l = framebuffer->deps; l; l = l->next)
645 _cogl_framebuffer_flush_journal (l->data);
646 _cogl_framebuffer_remove_all_dependencies (framebuffer);
650 _cogl_framebuffer_init_bits (CoglFramebuffer *framebuffer)
652 CoglContext *ctx = framebuffer->context;
654 cogl_framebuffer_allocate (framebuffer, NULL);
656 if (G_LIKELY (!framebuffer->dirty_bitmasks))
660 if (ctx->driver == COGL_DRIVER_GL &&
661 cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) &&
662 framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN)
664 GLenum attachment, pname;
666 attachment = GL_COLOR_ATTACHMENT0;
668 pname = GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE;
669 GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
672 &framebuffer->red_bits) );
674 pname = GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE;
675 GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
678 &framebuffer->green_bits)
681 pname = GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE;
682 GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
685 &framebuffer->blue_bits)
688 pname = GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE;
689 GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
692 &framebuffer->alpha_bits)
696 #endif /* HAVE_COGL_GL */
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) );
705 COGL_NOTE (OFFSCREEN,
706 "RGBA Bits for framebuffer[%p, %s]: %d, %d, %d, %d",
708 framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN
711 framebuffer->red_bits,
712 framebuffer->blue_bits,
713 framebuffer->green_bits,
714 framebuffer->alpha_bits);
716 framebuffer->dirty_bitmasks = FALSE;
720 _cogl_offscreen_new_to_texture_full (CoglTexture *texture,
721 CoglOffscreenFlags create_flags,
724 CoglOffscreen *offscreen;
731 _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
733 if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
734 return COGL_INVALID_HANDLE;
736 /* Make texture is a valid texture object */
737 if (!cogl_is_texture (texture))
738 return COGL_INVALID_HANDLE;
740 /* The texture must not be sliced */
741 if (cogl_texture_is_sliced (texture))
742 return COGL_INVALID_HANDLE;
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);
749 for (i = 0; i < level; i++)
751 /* If neither dimension can be further divided then the level is
753 if (level_width == 1 && level_height == 1)
755 g_warning ("Invalid texture level passed to "
756 "_cogl_offscreen_new_to_texture_full");
757 return COGL_INVALID_HANDLE;
762 if (level_height > 1)
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;
773 fb = COGL_FRAMEBUFFER (offscreen);
775 _cogl_framebuffer_init (fb,
777 COGL_FRAMEBUFFER_TYPE_OFFSCREEN,
778 cogl_texture_get_format (texture),
782 ret = _cogl_offscreen_object_new (offscreen);
784 _cogl_texture_associate_framebuffer (texture, fb);
790 cogl_offscreen_new_to_texture (CoglTexture *texture)
792 return _cogl_offscreen_new_to_texture_full (texture, 0, 0);
796 _cogl_offscreen_free (CoglOffscreen *offscreen)
798 CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (offscreen);
799 CoglContext *ctx = framebuffer->context;
802 /* Chain up to parent */
803 _cogl_framebuffer_free (framebuffer);
805 for (l = offscreen->renderbuffers; l; l = l->next)
807 GLuint renderbuffer = GPOINTER_TO_UINT (l->data);
808 GE (ctx, glDeleteRenderbuffers (1, &renderbuffer));
810 g_slist_free (offscreen->renderbuffers);
812 GE (ctx, glDeleteFramebuffers (1, &offscreen->fbo_handle));
814 if (offscreen->texture != COGL_INVALID_HANDLE)
815 cogl_object_unref (offscreen->texture);
821 try_creating_fbo (CoglOffscreen *offscreen,
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;
837 if (!cogl_texture_get_gl_texture (offscreen->texture,
838 &tex_gl_handle, &tex_gl_target))
841 if (tex_gl_target != GL_TEXTURE_2D
843 && tex_gl_target != GL_TEXTURE_RECTANGLE_ARB
848 if (fb->config.samples_per_pixel)
850 if (!ctx->glFramebufferTexture2DMultisampleIMG)
852 n_samples = fb->config.samples_per_pixel;
857 width = offscreen->texture_level_width;
858 height = offscreen->texture_level_height;
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;
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;
872 GE (ctx, glFramebufferTexture2DMultisampleIMG (GL_FRAMEBUFFER,
873 GL_COLOR_ATTACHMENT0,
874 tex_gl_target, tex_gl_handle,
876 offscreen->texture_level));
879 GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
880 tex_gl_target, tex_gl_handle,
881 offscreen->texture_level));
883 if (flags & (_TRY_DEPTH_STENCIL | _TRY_DEPTH24_STENCIL8))
885 GLenum format = ((flags & _TRY_DEPTH_STENCIL) ?
886 GL_DEPTH_STENCIL : GL_DEPTH24_STENCIL8);
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));
892 GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER,
897 GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, format,
899 GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0));
900 GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
901 GL_STENCIL_ATTACHMENT,
903 gl_depth_stencil_handle));
904 GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
907 gl_depth_stencil_handle));
908 offscreen->renderbuffers =
909 g_slist_prepend (offscreen->renderbuffers,
910 GUINT_TO_POINTER (gl_depth_stencil_handle));
913 if (flags & _TRY_DEPTH)
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 */
920 GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER,
922 GL_DEPTH_COMPONENT16,
925 GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
927 GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0));
928 GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
930 GL_RENDERBUFFER, gl_depth_handle));
931 offscreen->renderbuffers =
932 g_slist_prepend (offscreen->renderbuffers,
933 GUINT_TO_POINTER (gl_depth_handle));
936 if (flags & _TRY_STENCIL)
938 GE (ctx, glGenRenderbuffers (1, &gl_stencil_handle));
939 GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_stencil_handle));
941 GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER,
946 GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_STENCIL_INDEX8,
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));
957 /* Make sure it's complete */
958 status = ctx->glCheckFramebufferStatus (GL_FRAMEBUFFER);
960 if (status != GL_FRAMEBUFFER_COMPLETE)
964 GE (ctx, glDeleteFramebuffers (1, &fbo_gl_handle));
966 for (l = offscreen->renderbuffers; l; l = l->next)
968 GLuint renderbuffer = GPOINTER_TO_UINT (l->data);
969 GE (ctx, glDeleteRenderbuffers (1, &renderbuffer));
972 g_slist_free (offscreen->renderbuffers);
973 offscreen->renderbuffers = NULL;
978 /* Update the real number of samples_per_pixel now that we have a
979 * complete framebuffer */
982 GLenum attachment = GL_COLOR_ATTACHMENT0;
983 GLenum pname = GL_TEXTURE_SAMPLES_IMG;
986 GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
990 fb->samples_per_pixel = texture_samples;
997 _cogl_offscreen_allocate (CoglOffscreen *offscreen,
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;
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)
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.
1016 _cogl_texture_set_filters (offscreen->texture, GL_NEAREST, GL_NEAREST);
1018 if ((offscreen->create_flags & COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL))
1019 fbo_created = try_creating_fbo (offscreen, 0);
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))
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;
1041 fbo_created = FALSE;
1046 g_set_error (error, COGL_FRAMEBUFFER_ERROR,
1047 COGL_FRAMEBUFFER_ERROR_ALLOCATE,
1048 "Failed to create an OpenGL framebuffer object");
1056 cogl_framebuffer_allocate (CoglFramebuffer *framebuffer,
1059 CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
1060 const CoglWinsysVtable *winsys = _cogl_framebuffer_get_winsys (framebuffer);
1062 if (framebuffer->allocated)
1065 if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
1067 if (!winsys->onscreen_init (onscreen, error))
1072 if (!_cogl_offscreen_allocate (COGL_OFFSCREEN (framebuffer), error))
1076 framebuffer->allocated = TRUE;
1081 static CoglFramebufferStackEntry *
1082 create_stack_entry (CoglFramebuffer *draw_buffer,
1083 CoglFramebuffer *read_buffer)
1085 CoglFramebufferStackEntry *entry = g_slice_new (CoglFramebufferStackEntry);
1087 entry->draw_buffer = draw_buffer;
1088 entry->read_buffer = read_buffer;
1094 _cogl_create_framebuffer_stack (void)
1096 CoglFramebufferStackEntry *entry;
1097 GSList *stack = NULL;
1099 entry = create_stack_entry (COGL_INVALID_HANDLE, COGL_INVALID_HANDLE);
1101 return g_slist_prepend (stack, entry);
1105 _cogl_free_framebuffer_stack (GSList *stack)
1109 for (l = stack; l != NULL; l = l->next)
1111 CoglFramebufferStackEntry *entry = l->data;
1113 if (entry->draw_buffer)
1114 cogl_object_unref (entry->draw_buffer);
1116 if (entry->read_buffer)
1117 cogl_object_unref (entry->draw_buffer);
1119 g_slice_free (CoglFramebufferStackEntry, entry);
1121 g_slist_free (stack);
1125 notify_buffers_changed (CoglFramebuffer *old_draw_buffer,
1126 CoglFramebuffer *new_draw_buffer,
1127 CoglFramebuffer *old_read_buffer,
1128 CoglFramebuffer *new_read_buffer)
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;
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. */
1146 _cogl_set_framebuffers_real (CoglFramebuffer *draw_buffer,
1147 CoglFramebuffer *read_buffer)
1149 CoglFramebufferStackEntry *entry;
1151 _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1153 _COGL_RETURN_IF_FAIL (ctx != NULL);
1154 _COGL_RETURN_IF_FAIL (draw_buffer && read_buffer ?
1155 draw_buffer->context == read_buffer->context : TRUE);
1157 entry = ctx->framebuffer_stack->data;
1159 notify_buffers_changed (entry->draw_buffer,
1165 cogl_object_ref (draw_buffer);
1166 if (entry->draw_buffer)
1167 cogl_object_unref (entry->draw_buffer);
1170 cogl_object_ref (read_buffer);
1171 if (entry->read_buffer)
1172 cogl_object_unref (entry->read_buffer);
1174 entry->draw_buffer = draw_buffer;
1175 entry->read_buffer = read_buffer;
1179 _cogl_set_framebuffers (CoglFramebuffer *draw_buffer,
1180 CoglFramebuffer *read_buffer)
1182 CoglFramebuffer *current_draw_buffer;
1183 CoglFramebuffer *current_read_buffer;
1185 _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (draw_buffer));
1186 _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (read_buffer));
1188 current_draw_buffer = cogl_get_draw_framebuffer ();
1189 current_read_buffer = _cogl_get_read_framebuffer ();
1191 if (current_draw_buffer != draw_buffer ||
1192 current_read_buffer != read_buffer)
1193 _cogl_set_framebuffers_real (draw_buffer, read_buffer);
1197 cogl_set_framebuffer (CoglFramebuffer *framebuffer)
1199 _cogl_set_framebuffers (framebuffer, framebuffer);
1202 /* XXX: deprecated API */
1204 cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle handle)
1206 _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1208 if (target == COGL_WINDOW_BUFFER)
1209 handle = ctx->window_buffer;
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);
1218 cogl_get_draw_framebuffer (void)
1220 CoglFramebufferStackEntry *entry;
1222 _COGL_GET_CONTEXT (ctx, NULL);
1224 g_assert (ctx->framebuffer_stack);
1226 entry = ctx->framebuffer_stack->data;
1228 return entry->draw_buffer;
1232 _cogl_get_read_framebuffer (void)
1234 CoglFramebufferStackEntry *entry;
1236 _COGL_GET_CONTEXT (ctx, NULL);
1238 g_assert (ctx->framebuffer_stack);
1240 entry = ctx->framebuffer_stack->data;
1242 return entry->read_buffer;
1246 _cogl_push_framebuffers (CoglFramebuffer *draw_buffer,
1247 CoglFramebuffer *read_buffer)
1250 CoglFramebuffer *old_draw_buffer, *old_read_buffer;
1252 _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (draw_buffer));
1253 _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (read_buffer));
1255 ctx = draw_buffer->context;
1256 _COGL_RETURN_IF_FAIL (ctx != NULL);
1257 _COGL_RETURN_IF_FAIL (draw_buffer->context == read_buffer->context);
1259 _COGL_RETURN_IF_FAIL (ctx->framebuffer_stack != NULL);
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,
1274 _cogl_set_framebuffers (draw_buffer, read_buffer);
1278 cogl_push_framebuffer (CoglFramebuffer *buffer)
1280 _cogl_push_framebuffers (buffer, buffer);
1283 /* XXX: deprecated API */
1285 cogl_push_draw_buffer (void)
1287 cogl_push_framebuffer (cogl_get_draw_framebuffer ());
1291 cogl_pop_framebuffer (void)
1293 CoglFramebufferStackEntry *to_pop;
1294 CoglFramebufferStackEntry *to_restore;
1296 _COGL_GET_CONTEXT (ctx, NO_RETVAL);
1298 g_assert (ctx->framebuffer_stack != NULL);
1299 g_assert (ctx->framebuffer_stack->next != NULL);
1301 to_pop = ctx->framebuffer_stack->data;
1302 to_restore = ctx->framebuffer_stack->next->data;
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);
1311 cogl_object_unref (to_pop->draw_buffer);
1312 cogl_object_unref (to_pop->read_buffer);
1313 g_slice_free (CoglFramebufferStackEntry, to_pop);
1315 ctx->framebuffer_stack =
1316 g_slist_delete_link (ctx->framebuffer_stack,
1317 ctx->framebuffer_stack);
1320 /* XXX: deprecated API */
1322 cogl_pop_draw_buffer (void)
1324 cogl_pop_framebuffer ();
1328 bind_gl_framebuffer (CoglContext *ctx,
1330 CoglFramebuffer *framebuffer)
1332 if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN)
1333 GE (ctx, glBindFramebuffer (target,
1334 COGL_OFFSCREEN (framebuffer)->fbo_handle));
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));
1346 static unsigned long
1347 _cogl_framebuffer_compare_viewport_state (CoglFramebuffer *a,
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... */
1357 return COGL_FRAMEBUFFER_STATE_VIEWPORT;
1362 static unsigned long
1363 _cogl_framebuffer_compare_clip_state (CoglFramebuffer *a,
1366 if (((a->clip_state.stacks == NULL || b->clip_state.stacks == NULL) &&
1367 a->clip_state.stacks != b->clip_state.stacks)
1369 a->clip_state.stacks->data != b->clip_state.stacks->data)
1370 return COGL_FRAMEBUFFER_STATE_CLIP;
1375 static unsigned long
1376 _cogl_framebuffer_compare_dither_state (CoglFramebuffer *a,
1379 return a->dither_enabled != b->dither_enabled ?
1380 COGL_FRAMEBUFFER_STATE_DITHER : 0;
1383 static unsigned long
1384 _cogl_framebuffer_compare_modelview_state (CoglFramebuffer *a,
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
1390 return COGL_FRAMEBUFFER_STATE_MODELVIEW;
1393 static unsigned long
1394 _cogl_framebuffer_compare_projection_state (CoglFramebuffer *a,
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;
1403 static unsigned long
1404 _cogl_framebuffer_compare_color_mask_state (CoglFramebuffer *a,
1407 if (cogl_framebuffer_get_color_mask (a) !=
1408 cogl_framebuffer_get_color_mask (b))
1409 return COGL_FRAMEBUFFER_STATE_COLOR_MASK;
1414 static unsigned long
1415 _cogl_framebuffer_compare_front_face_winding_state (CoglFramebuffer *a,
1418 if (a->type != b->type)
1419 return COGL_FRAMEBUFFER_STATE_FRONT_FACE_WINDING;
1424 static unsigned long
1425 _cogl_framebuffer_compare (CoglFramebuffer *a,
1427 unsigned long state)
1429 unsigned long differences = 0;
1432 if (state & COGL_FRAMEBUFFER_STATE_BIND)
1434 differences |= COGL_FRAMEBUFFER_STATE_BIND;
1435 state &= ~COGL_FRAMEBUFFER_STATE_BIND;
1438 COGL_FLAGS_FOREACH_START (&state, 1, bit)
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. */
1446 case COGL_FRAMEBUFFER_STATE_INDEX_VIEWPORT:
1448 _cogl_framebuffer_compare_viewport_state (a, b);
1450 case COGL_FRAMEBUFFER_STATE_INDEX_CLIP:
1451 differences |= _cogl_framebuffer_compare_clip_state (a, b);
1453 case COGL_FRAMEBUFFER_STATE_INDEX_DITHER:
1454 differences |= _cogl_framebuffer_compare_dither_state (a, b);
1456 case COGL_FRAMEBUFFER_STATE_INDEX_MODELVIEW:
1458 _cogl_framebuffer_compare_modelview_state (a, b);
1460 case COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION:
1462 _cogl_framebuffer_compare_projection_state (a, b);
1464 case COGL_FRAMEBUFFER_STATE_INDEX_COLOR_MASK:
1466 _cogl_framebuffer_compare_color_mask_state (a, b);
1468 case COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING:
1470 _cogl_framebuffer_compare_front_face_winding_state (a, b);
1473 g_warn_if_reached ();
1476 COGL_FLAGS_FOREACH_END;
1482 _cogl_framebuffer_flush_viewport_state (CoglFramebuffer *framebuffer)
1484 float gl_viewport_y;
1486 g_assert (framebuffer->viewport_width >=0 &&
1487 framebuffer->viewport_height >=0);
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;
1497 gl_viewport_y = framebuffer->height -
1498 (framebuffer->viewport_y + framebuffer->viewport_height);
1500 COGL_NOTE (OPENGL, "Calling glViewport(%f, %f, %f, %f)",
1501 framebuffer->viewport_x,
1503 framebuffer->viewport_width,
1504 framebuffer->viewport_height);
1506 GE (framebuffer->context,
1507 glViewport (framebuffer->viewport_x,
1509 framebuffer->viewport_width,
1510 framebuffer->viewport_height));
1514 _cogl_framebuffer_flush_clip_state (CoglFramebuffer *framebuffer)
1516 CoglClipStack *stack = _cogl_clip_state_get_stack (&framebuffer->clip_state);
1517 _cogl_clip_stack_flush (stack, framebuffer);
1521 _cogl_framebuffer_flush_dither_state (CoglFramebuffer *framebuffer)
1523 CoglContext *ctx = framebuffer->context;
1525 if (ctx->current_gl_dither_enabled != framebuffer->dither_enabled)
1527 if (framebuffer->dither_enabled)
1528 GE (ctx, glEnable (GL_DITHER));
1530 GE (ctx, glDisable (GL_DITHER));
1531 ctx->current_gl_dither_enabled = framebuffer->dither_enabled;
1536 _cogl_framebuffer_flush_modelview_state (CoglFramebuffer *framebuffer)
1538 _cogl_context_set_current_modelview (framebuffer->context,
1539 framebuffer->modelview_stack);
1543 _cogl_framebuffer_flush_projection_state (CoglFramebuffer *framebuffer)
1545 _cogl_context_set_current_projection (framebuffer->context,
1546 framebuffer->projection_stack);
1550 _cogl_framebuffer_flush_color_mask_state (CoglFramebuffer *framebuffer)
1552 CoglContext *context = framebuffer->context;
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
1558 context->current_pipeline_changes_since_flush |=
1559 COGL_PIPELINE_STATE_LOGIC_OPS;
1560 context->current_pipeline_age--;
1564 _cogl_framebuffer_flush_front_face_winding_state (CoglFramebuffer *framebuffer)
1566 CoglContext *context = framebuffer->context;
1567 CoglPipelineCullFaceMode mode;
1569 /* NB: The face winding state is actually owned by the current
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)
1578 mode = cogl_pipeline_get_cull_face_mode (context->current_pipeline);
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
1583 if (mode == COGL_PIPELINE_CULL_FACE_MODE_NONE ||
1584 mode == COGL_PIPELINE_CULL_FACE_MODE_BOTH)
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
1590 context->current_pipeline_changes_since_flush |=
1591 COGL_PIPELINE_STATE_CULL_FACE;
1592 context->current_pipeline_age--;
1596 _cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer,
1597 CoglFramebuffer *read_buffer,
1598 CoglFramebufferState state)
1600 CoglContext *ctx = draw_buffer->context;
1601 unsigned long differences;
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;
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;
1613 /* We only need to consider the state we've been asked to flush */
1614 differences &= state;
1616 if (ctx->current_draw_buffer != draw_buffer)
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;
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,
1631 state & ~differences);
1633 /* NB: we don't take a reference here, to avoid a circular
1635 ctx->current_draw_buffer = draw_buffer;
1636 ctx->current_draw_buffer_state_flushed = 0;
1639 if (ctx->current_read_buffer != read_buffer &&
1640 state & COGL_FRAMEBUFFER_STATE_BIND)
1642 differences |= COGL_FRAMEBUFFER_STATE_BIND;
1643 /* NB: we don't take a reference here, to avoid a circular
1645 ctx->current_read_buffer = read_buffer;
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);
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)
1662 if (draw_buffer == read_buffer)
1663 bind_gl_framebuffer (ctx, GL_FRAMEBUFFER, draw_buffer);
1666 /* NB: Currently we only take advantage of binding separate
1667 * read/write buffers for offscreen framebuffer blit
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);
1674 bind_gl_framebuffer (ctx, GL_DRAW_FRAMEBUFFER, draw_buffer);
1675 bind_gl_framebuffer (ctx, GL_READ_FRAMEBUFFER, read_buffer);
1678 differences &= ~COGL_FRAMEBUFFER_STATE_BIND;
1681 COGL_FLAGS_FOREACH_START (&differences, 1, bit)
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. */
1689 case COGL_FRAMEBUFFER_STATE_INDEX_VIEWPORT:
1690 _cogl_framebuffer_flush_viewport_state (draw_buffer);
1692 case COGL_FRAMEBUFFER_STATE_INDEX_CLIP:
1693 _cogl_framebuffer_flush_clip_state (draw_buffer);
1695 case COGL_FRAMEBUFFER_STATE_INDEX_DITHER:
1696 _cogl_framebuffer_flush_dither_state (draw_buffer);
1698 case COGL_FRAMEBUFFER_STATE_INDEX_MODELVIEW:
1699 _cogl_framebuffer_flush_modelview_state (draw_buffer);
1701 case COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION:
1702 _cogl_framebuffer_flush_projection_state (draw_buffer);
1704 case COGL_FRAMEBUFFER_STATE_INDEX_COLOR_MASK:
1705 _cogl_framebuffer_flush_color_mask_state (draw_buffer);
1707 case COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING:
1708 _cogl_framebuffer_flush_front_face_winding_state (draw_buffer);
1711 g_warn_if_reached ();
1714 COGL_FLAGS_FOREACH_END;
1716 ctx->current_draw_buffer_state_flushed |= state;
1717 ctx->current_draw_buffer_changes &= ~state;
1721 cogl_framebuffer_get_red_bits (CoglFramebuffer *framebuffer)
1723 _cogl_framebuffer_init_bits (framebuffer);
1725 return framebuffer->red_bits;
1729 cogl_framebuffer_get_green_bits (CoglFramebuffer *framebuffer)
1731 _cogl_framebuffer_init_bits (framebuffer);
1733 return framebuffer->green_bits;
1737 cogl_framebuffer_get_blue_bits (CoglFramebuffer *framebuffer)
1739 _cogl_framebuffer_init_bits (framebuffer);
1741 return framebuffer->blue_bits;
1745 cogl_framebuffer_get_alpha_bits (CoglFramebuffer *framebuffer)
1747 _cogl_framebuffer_init_bits (framebuffer);
1749 return framebuffer->alpha_bits;
1753 cogl_framebuffer_get_color_mask (CoglFramebuffer *framebuffer)
1755 return framebuffer->color_mask;
1759 cogl_framebuffer_set_color_mask (CoglFramebuffer *framebuffer,
1760 CoglColorMask color_mask)
1762 /* XXX: Currently color mask changes don't go through the journal */
1763 _cogl_framebuffer_flush_journal (framebuffer);
1765 framebuffer->color_mask = color_mask;
1767 if (framebuffer->context->current_draw_buffer == framebuffer)
1768 framebuffer->context->current_draw_buffer_changes |=
1769 COGL_FRAMEBUFFER_STATE_COLOR_MASK;
1773 cogl_framebuffer_get_dither_enabled (CoglFramebuffer *framebuffer)
1775 return framebuffer->dither_enabled;
1779 cogl_framebuffer_set_dither_enabled (CoglFramebuffer *framebuffer,
1780 gboolean dither_enabled)
1782 if (framebuffer->dither_enabled == dither_enabled)
1785 cogl_flush (); /* Currently dithering changes aren't tracked in the journal */
1786 framebuffer->dither_enabled = dither_enabled;
1788 if (framebuffer->context->current_draw_buffer == framebuffer)
1789 framebuffer->context->current_draw_buffer_changes |=
1790 COGL_FRAMEBUFFER_STATE_DITHER;
1794 cogl_framebuffer_get_color_format (CoglFramebuffer *framebuffer)
1796 return framebuffer->format;
1800 cogl_framebuffer_get_samples_per_pixel (CoglFramebuffer *framebuffer)
1802 if (framebuffer->allocated)
1803 return framebuffer->samples_per_pixel;
1805 return framebuffer->config.samples_per_pixel;
1809 cogl_framebuffer_set_samples_per_pixel (CoglFramebuffer *framebuffer,
1810 int samples_per_pixel)
1812 _COGL_RETURN_IF_FAIL (!framebuffer->allocated);
1814 framebuffer->config.samples_per_pixel = samples_per_pixel;
1818 cogl_framebuffer_resolve_samples (CoglFramebuffer *framebuffer)
1820 cogl_framebuffer_resolve_samples_region (framebuffer,
1823 framebuffer->height);
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.
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.
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 ().
1839 * Calling cogl_framebuffer_resolve_samples() or
1840 * cogl_framebuffer_resolve_samples_region() should reset the textures
1841 * needs_resolve pointer to NULL.
1843 * Rendering anything to a framebuffer will cause the corresponding
1844 * texture's ->needs_resolve pointer to be set.
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.
1853 cogl_framebuffer_resolve_samples_region (CoglFramebuffer *framebuffer,
1859 /* NOP for now since we don't support EXT_framebuffer_multisample yet which
1860 * requires an explicit resolve. */
1864 cogl_framebuffer_get_context (CoglFramebuffer *framebuffer)
1866 _COGL_RETURN_VAL_IF_FAIL (framebuffer != NULL, NULL);
1868 return framebuffer->context;
1872 _cogl_framebuffer_try_fast_read_pixel (CoglFramebuffer *framebuffer,
1875 CoglReadPixelsFlags source,
1878 gboolean found_intersection;
1879 CoglPixelFormat format;
1881 if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FAST_READ_PIXEL)))
1884 if (source != COGL_READ_PIXELS_COLOR_BUFFER)
1887 format = cogl_bitmap_get_format (bitmap);
1889 if (format != COGL_PIXEL_FORMAT_RGBA_8888_PRE &&
1890 format != COGL_PIXEL_FORMAT_RGBA_8888)
1893 if (!_cogl_journal_try_read_pixel (framebuffer->journal,
1895 &found_intersection))
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
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...
1906 if (found_intersection)
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)
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)
1921 /* we currently only care about cases where the premultiplied or
1922 * unpremultipled colors are equivalent... */
1923 if (framebuffer->clear_color_alpha != 1.0)
1926 pixel = _cogl_bitmap_map (bitmap,
1927 COGL_BUFFER_ACCESS_WRITE,
1928 COGL_BUFFER_MAP_HINT_DISCARD);
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;
1937 _cogl_bitmap_unmap (bitmap);
1946 cogl_framebuffer_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
1949 CoglReadPixelsFlags source,
1953 int framebuffer_height;
1954 CoglPixelFormat format;
1955 CoglPixelFormat required_format;
1956 GLenum gl_intformat;
1959 gboolean pack_invert_set;
1963 _COGL_RETURN_VAL_IF_FAIL (source == COGL_READ_PIXELS_COLOR_BUFFER, FALSE);
1964 _COGL_RETURN_VAL_IF_FAIL (cogl_is_framebuffer (framebuffer), FALSE);
1966 if (!cogl_framebuffer_allocate (framebuffer, NULL))
1969 ctx = cogl_framebuffer_get_context (framebuffer);
1971 width = cogl_bitmap_get_width (bitmap);
1972 height = cogl_bitmap_get_height (bitmap);
1974 if (width == 1 && height == 1 && !framebuffer->clear_clip_dirty)
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
1984 if (_cogl_framebuffer_try_fast_read_pixel (framebuffer,
1985 x, y, source, bitmap))
1989 /* make sure any batched primitives get emitted to the GL driver
1990 * before issuing our read pixels...
1992 _cogl_framebuffer_flush_journal (framebuffer);
1994 _cogl_framebuffer_flush_state (framebuffer,
1996 COGL_FRAMEBUFFER_STATE_BIND);
1998 framebuffer_height = cogl_framebuffer_get_height (framebuffer);
2000 /* The y co-ordinate should be given in OpenGL's coordinate system
2001 * so 0 is the bottom row
2003 * NB: all offscreen rendering is done upside down so no conversion
2004 * is necissary in this case.
2006 if (!cogl_is_offscreen (framebuffer))
2007 y = framebuffer_height - y - height;
2009 format = cogl_bitmap_get_format (bitmap);
2011 required_format = ctx->texture_driver->pixel_format_to_gl (format,
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))
2021 GE (ctx, glPixelStorei (GL_PACK_INVERT_MESA, TRUE));
2022 pack_invert_set = TRUE;
2025 pack_invert_set = FALSE;
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))
2042 CoglBitmap *tmp_bmp;
2043 CoglPixelFormat read_format;
2048 if (ctx->driver == COGL_DRIVER_GL)
2049 read_format = required_format;
2052 read_format = COGL_PIXEL_FORMAT_RGBA_8888;
2053 gl_format = GL_RGBA;
2054 gl_type = GL_UNSIGNED_BYTE;
2057 if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (read_format))
2058 read_format = ((read_format & ~COGL_PREMULT_BIT) |
2059 (framebuffer->format & COGL_PREMULT_BIT));
2061 tmp_bmp = _cogl_bitmap_new_with_malloc_buffer (ctx,
2064 bpp = _cogl_pixel_format_get_bytes_per_pixel (read_format);
2065 rowstride = cogl_bitmap_get_rowstride (tmp_bmp);
2067 ctx->texture_driver->prep_gl_for_pixels_download (rowstride, bpp);
2069 tmp_data = _cogl_bitmap_bind (tmp_bmp,
2070 COGL_BUFFER_ACCESS_WRITE,
2071 COGL_BUFFER_MAP_HINT_DISCARD);
2073 GE( ctx, glReadPixels (x, y, width, height,
2077 _cogl_bitmap_unbind (tmp_bmp);
2079 succeeded = _cogl_bitmap_convert_into_bitmap (tmp_bmp, bitmap);
2081 cogl_object_unref (tmp_bmp);
2088 CoglBitmap *shared_bmp;
2089 CoglPixelFormat bmp_format;
2091 gboolean succeeded = FALSE;
2094 rowstride = cogl_bitmap_get_rowstride (bitmap);
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));
2103 bmp_format = format;
2105 if (bmp_format != format)
2106 shared_bmp = _cogl_bitmap_new_shared (bitmap,
2111 shared_bmp = cogl_object_ref (bitmap);
2113 bpp = _cogl_pixel_format_get_bytes_per_pixel (bmp_format);
2115 ctx->texture_driver->prep_gl_for_pixels_download (rowstride, bpp);
2117 pixels = _cogl_bitmap_bind (shared_bmp,
2118 COGL_BUFFER_ACCESS_WRITE,
2121 GE( ctx, glReadPixels (x, y,
2126 _cogl_bitmap_unbind (shared_bmp);
2128 /* Convert to the premult format specified by the caller
2129 in-place. This will do nothing if the premult status is already
2131 if (_cogl_bitmap_convert_premult_status (shared_bmp, format))
2134 cogl_object_unref (shared_bmp);
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));
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)
2154 rowstride = cogl_bitmap_get_rowstride (bitmap);
2155 pixels = _cogl_bitmap_map (bitmap,
2156 COGL_BUFFER_ACCESS_READ |
2157 COGL_BUFFER_ACCESS_WRITE,
2163 temprow = g_alloca (rowstride * sizeof (guint8));
2165 /* vertically flip the buffer in-place */
2166 for (y = 0; y < height / 2; y++)
2168 if (y != height - y - 1) /* skip center row */
2171 pixels + y * rowstride, rowstride);
2172 memcpy (pixels + y * rowstride,
2173 pixels + (height - y - 1) * rowstride, rowstride);
2174 memcpy (pixels + (height - y - 1) * rowstride,
2180 _cogl_bitmap_unmap (bitmap);
2187 cogl_framebuffer_read_pixels (CoglFramebuffer *framebuffer,
2192 CoglPixelFormat format,
2195 int bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
2199 bitmap = cogl_bitmap_new_for_data (framebuffer->context,
2202 bpp * width, /* rowstride */
2204 ret = cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
2206 COGL_READ_PIXELS_COLOR_BUFFER,
2208 cogl_object_unref (bitmap);
2214 _cogl_blit_framebuffer (unsigned int src_x,
2219 unsigned int height)
2221 CoglFramebuffer *draw_buffer;
2222 CoglFramebuffer *read_buffer;
2225 /* FIXME: this function should take explit src and dst framebuffer
2227 draw_buffer = cogl_get_draw_framebuffer ();
2228 read_buffer = _cogl_get_read_framebuffer ();
2229 ctx = draw_buffer->context;
2231 _COGL_RETURN_IF_FAIL (ctx->private_feature_flags &
2232 COGL_PRIVATE_FEATURE_OFFSCREEN_BLIT);
2234 /* We can only support blitting between offscreen buffers because
2235 otherwise we would need to mirror the image and GLES2.0 doesn't
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);
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);
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
2253 _cogl_clip_stack_flush (NULL, draw_buffer);
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
2259 ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP;
2261 ctx->glBlitFramebuffer (src_x, src_y,
2262 src_x + width, src_y + height,
2264 dst_x + width, dst_y + height,
2265 GL_COLOR_BUFFER_BIT,
2270 _cogl_framebuffer_discard_buffers_real (CoglFramebuffer *framebuffer,
2271 unsigned long buffers)
2273 #ifdef GL_EXT_discard_framebuffer
2274 CoglContext *ctx = framebuffer->context;
2276 if (ctx->glDiscardFramebuffer)
2278 GLenum attachments[3];
2281 if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN)
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;
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;
2300 GE (ctx, glDiscardFramebuffer (GL_FRAMEBUFFER, i, attachments));
2302 #endif /* GL_EXT_discard_framebuffer */
2306 cogl_framebuffer_discard_buffers (CoglFramebuffer *framebuffer,
2307 unsigned long buffers)
2309 _COGL_RETURN_IF_FAIL (buffers & COGL_BUFFER_BIT_COLOR);
2311 _cogl_framebuffer_discard_buffers_real (framebuffer, buffers);
2315 cogl_framebuffer_finish (CoglFramebuffer *framebuffer)
2317 _cogl_framebuffer_flush_journal (framebuffer);
2318 GE (framebuffer->context, glFinish ());
2322 cogl_framebuffer_push_matrix (CoglFramebuffer *framebuffer)
2324 CoglMatrixStack *modelview_stack =
2325 _cogl_framebuffer_get_modelview_stack (framebuffer);
2326 _cogl_matrix_stack_push (modelview_stack);
2328 if (framebuffer->context->current_draw_buffer == framebuffer)
2329 framebuffer->context->current_draw_buffer_changes |=
2330 COGL_FRAMEBUFFER_STATE_MODELVIEW;
2334 cogl_framebuffer_pop_matrix (CoglFramebuffer *framebuffer)
2336 CoglMatrixStack *modelview_stack =
2337 _cogl_framebuffer_get_modelview_stack (framebuffer);
2338 _cogl_matrix_stack_pop (modelview_stack);
2340 if (framebuffer->context->current_draw_buffer == framebuffer)
2341 framebuffer->context->current_draw_buffer_changes |=
2342 COGL_FRAMEBUFFER_STATE_MODELVIEW;
2346 cogl_framebuffer_identity_matrix (CoglFramebuffer *framebuffer)
2348 CoglMatrixStack *modelview_stack =
2349 _cogl_framebuffer_get_modelview_stack (framebuffer);
2350 _cogl_matrix_stack_load_identity (modelview_stack);
2352 if (framebuffer->context->current_draw_buffer == framebuffer)
2353 framebuffer->context->current_draw_buffer_changes |=
2354 COGL_FRAMEBUFFER_STATE_MODELVIEW;
2358 cogl_framebuffer_scale (CoglFramebuffer *framebuffer,
2363 CoglMatrixStack *modelview_stack =
2364 _cogl_framebuffer_get_modelview_stack (framebuffer);
2365 _cogl_matrix_stack_scale (modelview_stack, x, y, z);
2367 if (framebuffer->context->current_draw_buffer == framebuffer)
2368 framebuffer->context->current_draw_buffer_changes |=
2369 COGL_FRAMEBUFFER_STATE_MODELVIEW;
2373 cogl_framebuffer_translate (CoglFramebuffer *framebuffer,
2378 CoglMatrixStack *modelview_stack =
2379 _cogl_framebuffer_get_modelview_stack (framebuffer);
2380 _cogl_matrix_stack_translate (modelview_stack, x, y, z);
2382 if (framebuffer->context->current_draw_buffer == framebuffer)
2383 framebuffer->context->current_draw_buffer_changes |=
2384 COGL_FRAMEBUFFER_STATE_MODELVIEW;
2388 cogl_framebuffer_rotate (CoglFramebuffer *framebuffer,
2394 CoglMatrixStack *modelview_stack =
2395 _cogl_framebuffer_get_modelview_stack (framebuffer);
2396 _cogl_matrix_stack_rotate (modelview_stack, angle, x, y, z);
2398 if (framebuffer->context->current_draw_buffer == framebuffer)
2399 framebuffer->context->current_draw_buffer_changes |=
2400 COGL_FRAMEBUFFER_STATE_MODELVIEW;
2404 cogl_framebuffer_transform (CoglFramebuffer *framebuffer,
2405 const CoglMatrix *matrix)
2407 CoglMatrixStack *modelview_stack =
2408 _cogl_framebuffer_get_modelview_stack (framebuffer);
2409 _cogl_matrix_stack_multiply (modelview_stack, matrix);
2411 if (framebuffer->context->current_draw_buffer == framebuffer)
2412 framebuffer->context->current_draw_buffer_changes |=
2413 COGL_FRAMEBUFFER_STATE_MODELVIEW;
2417 cogl_framebuffer_perspective (CoglFramebuffer *framebuffer,
2423 float ymax = z_near * tanf (fov_y * G_PI / 360.0);
2425 cogl_framebuffer_frustum (framebuffer,
2426 -ymax * aspect, /* left */
2427 ymax * aspect, /* right */
2433 if (framebuffer->context->current_draw_buffer == framebuffer)
2434 framebuffer->context->current_draw_buffer_changes |=
2435 COGL_FRAMEBUFFER_STATE_PROJECTION;
2439 cogl_framebuffer_frustum (CoglFramebuffer *framebuffer,
2447 CoglMatrixStack *projection_stack =
2448 _cogl_framebuffer_get_projection_stack (framebuffer);
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);
2454 _cogl_matrix_stack_load_identity (projection_stack);
2456 _cogl_matrix_stack_frustum (projection_stack,
2464 if (framebuffer->context->current_draw_buffer == framebuffer)
2465 framebuffer->context->current_draw_buffer_changes |=
2466 COGL_FRAMEBUFFER_STATE_PROJECTION;
2470 cogl_framebuffer_orthographic (CoglFramebuffer *framebuffer,
2479 CoglMatrixStack *projection_stack =
2480 _cogl_framebuffer_get_projection_stack (framebuffer);
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);
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);
2490 if (framebuffer->context->current_draw_buffer == framebuffer)
2491 framebuffer->context->current_draw_buffer_changes |=
2492 COGL_FRAMEBUFFER_STATE_PROJECTION;
2496 _cogl_framebuffer_push_projection (CoglFramebuffer *framebuffer)
2498 CoglMatrixStack *projection_stack =
2499 _cogl_framebuffer_get_projection_stack (framebuffer);
2500 _cogl_matrix_stack_push (projection_stack);
2502 if (framebuffer->context->current_draw_buffer == framebuffer)
2503 framebuffer->context->current_draw_buffer_changes |=
2504 COGL_FRAMEBUFFER_STATE_PROJECTION;
2508 _cogl_framebuffer_pop_projection (CoglFramebuffer *framebuffer)
2510 CoglMatrixStack *projection_stack =
2511 _cogl_framebuffer_get_projection_stack (framebuffer);
2512 _cogl_matrix_stack_pop (projection_stack);
2514 if (framebuffer->context->current_draw_buffer == framebuffer)
2515 framebuffer->context->current_draw_buffer_changes |=
2516 COGL_FRAMEBUFFER_STATE_PROJECTION;
2520 cogl_framebuffer_get_modelview_matrix (CoglFramebuffer *framebuffer,
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);
2530 cogl_framebuffer_set_modelview_matrix (CoglFramebuffer *framebuffer,
2533 CoglMatrixStack *modelview_stack =
2534 _cogl_framebuffer_get_modelview_stack (framebuffer);
2535 _cogl_matrix_stack_set (modelview_stack, matrix);
2537 if (framebuffer->context->current_draw_buffer == framebuffer)
2538 framebuffer->context->current_draw_buffer_changes |=
2539 COGL_FRAMEBUFFER_STATE_MODELVIEW;
2541 _COGL_MATRIX_DEBUG_PRINT (matrix);
2545 cogl_framebuffer_get_projection_matrix (CoglFramebuffer *framebuffer,
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);
2555 cogl_framebuffer_set_projection_matrix (CoglFramebuffer *framebuffer,
2558 CoglMatrixStack *projection_stack =
2559 _cogl_framebuffer_get_projection_stack (framebuffer);
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);
2565 _cogl_matrix_stack_set (projection_stack, matrix);
2567 if (framebuffer->context->current_draw_buffer == framebuffer)
2568 framebuffer->context->current_draw_buffer_changes |=
2569 COGL_FRAMEBUFFER_STATE_PROJECTION;
2571 _COGL_MATRIX_DEBUG_PRINT (matrix);
2575 cogl_framebuffer_push_scissor_clip (CoglFramebuffer *framebuffer,
2581 CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
2583 clip_state->stacks->data =
2584 _cogl_clip_stack_push_window_rectangle (clip_state->stacks->data,
2585 x, y, width, height);
2587 if (framebuffer->context->current_draw_buffer == framebuffer)
2588 framebuffer->context->current_draw_buffer_changes |=
2589 COGL_FRAMEBUFFER_STATE_CLIP;
2593 cogl_framebuffer_push_rectangle_clip (CoglFramebuffer *framebuffer,
2599 CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
2600 CoglMatrix modelview_matrix;
2602 cogl_framebuffer_get_modelview_matrix (framebuffer, &modelview_matrix);
2604 clip_state->stacks->data =
2605 _cogl_clip_stack_push_rectangle (clip_state->stacks->data,
2609 if (framebuffer->context->current_draw_buffer == framebuffer)
2610 framebuffer->context->current_draw_buffer_changes |=
2611 COGL_FRAMEBUFFER_STATE_CLIP;
2615 cogl_framebuffer_push_path_clip (CoglFramebuffer *framebuffer,
2618 CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
2619 CoglMatrix modelview_matrix;
2621 cogl_framebuffer_get_modelview_matrix (framebuffer, &modelview_matrix);
2623 clip_state->stacks->data =
2624 _cogl_clip_stack_push_from_path (clip_state->stacks->data,
2628 if (framebuffer->context->current_draw_buffer == framebuffer)
2629 framebuffer->context->current_draw_buffer_changes |=
2630 COGL_FRAMEBUFFER_STATE_CLIP;
2634 cogl_framebuffer_push_primitive_clip (CoglFramebuffer *framebuffer,
2635 CoglPrimitive *primitive,
2641 CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
2642 CoglMatrix modelview_matrix;
2644 cogl_get_modelview_matrix (&modelview_matrix);
2646 clip_state->stacks->data =
2647 _cogl_clip_stack_push_primitive (clip_state->stacks->data,
2649 bounds_x1, bounds_y1,
2650 bounds_x2, bounds_y2,
2653 if (framebuffer->context->current_draw_buffer == framebuffer)
2654 framebuffer->context->current_draw_buffer_changes |=
2655 COGL_FRAMEBUFFER_STATE_CLIP;
2659 cogl_framebuffer_pop_clip (CoglFramebuffer *framebuffer)
2661 CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
2663 clip_state->stacks->data = _cogl_clip_stack_pop (clip_state->stacks->data);
2665 if (framebuffer->context->current_draw_buffer == framebuffer)
2666 framebuffer->context->current_draw_buffer_changes |=
2667 COGL_FRAMEBUFFER_STATE_CLIP;
2671 _cogl_framebuffer_save_clip_stack (CoglFramebuffer *framebuffer)
2673 CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
2674 _cogl_clip_state_save_clip_stack (clip_state);
2676 if (framebuffer->context->current_draw_buffer == framebuffer)
2677 framebuffer->context->current_draw_buffer_changes |=
2678 COGL_FRAMEBUFFER_STATE_CLIP;
2682 _cogl_framebuffer_restore_clip_stack (CoglFramebuffer *framebuffer)
2684 CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
2685 _cogl_clip_state_restore_clip_stack (clip_state);
2687 if (framebuffer->context->current_draw_buffer == framebuffer)
2688 framebuffer->context->current_draw_buffer_changes |=
2689 COGL_FRAMEBUFFER_STATE_CLIP;
2693 _cogl_framebuffer_unref (CoglFramebuffer *framebuffer)
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)
2704 unsigned int ref_count = ((CoglObject *) framebuffer)->ref_count;
2706 /* There should be at least two references - the one we are
2707 about to drop and the one held by the journal */
2709 g_warning ("Inconsistent ref count on a framebuffer with journal "
2713 _cogl_framebuffer_flush_journal (framebuffer);
2717 _cogl_object_default_unref (framebuffer);
2720 #ifdef COGL_ENABLE_DEBUG
2722 get_index (void *indices,
2723 CoglIndicesType type,
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];
2739 g_return_val_if_reached (0);
2743 add_line (guint32 *line_indices,
2746 CoglIndicesType user_indices_type,
2751 index0 = get_index (user_indices, user_indices_type, index0);
2752 index1 = get_index (user_indices, user_indices_type, index1);
2754 line_indices[(*pos)++] = base + index0;
2755 line_indices[(*pos)++] = base + index1;
2759 get_line_count (CoglVerticesMode mode, int n_vertices)
2761 if (mode == COGL_VERTICES_MODE_TRIANGLES &&
2762 (n_vertices % 3) == 0)
2766 else if (mode == COGL_VERTICES_MODE_TRIANGLE_FAN &&
2769 return 2 * n_vertices - 3;
2771 else if (mode == COGL_VERTICES_MODE_TRIANGLE_STRIP &&
2774 return 2 * n_vertices - 3;
2776 /* In the journal we are a bit sneaky and actually use GL_QUADS
2777 * which isn't actually a valid CoglVerticesMode! */
2779 else if (mode == GL_QUADS && (n_vertices % 4) == 0)
2785 g_return_val_if_reached (0);
2788 static CoglIndices *
2789 get_wire_line_indices (CoglContext *ctx,
2790 CoglVerticesMode mode,
2793 CoglIndices *user_indices,
2797 guint32 *line_indices;
2798 CoglIndexBuffer *index_buffer;
2800 CoglIndicesType indices_type;
2801 int base = first_vertex;
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);
2815 index_buffer = NULL;
2817 indices_type = COGL_INDICES_TYPE_UNSIGNED_BYTE;
2820 n_lines = get_line_count (mode, n_vertices_in);
2822 /* Note: we are using COGL_INDICES_TYPE_UNSIGNED_INT so 4 bytes per index. */
2823 line_indices = g_malloc (4 * n_lines * 2);
2827 if (mode == COGL_VERTICES_MODE_TRIANGLES &&
2828 (n_vertices_in % 3) == 0)
2830 for (i = 0; i < n_vertices_in; i += 3)
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);
2837 else if (mode == COGL_VERTICES_MODE_TRIANGLE_FAN &&
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);
2844 for (i = 3; i < n_vertices_in; i++)
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);
2850 else if (mode == COGL_VERTICES_MODE_TRIANGLE_STRIP &&
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);
2857 for (i = 3; i < n_vertices_in; i++)
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);
2863 /* In the journal we are a bit sneaky and actually use GL_QUADS
2864 * which isn't actually a valid CoglVerticesMode! */
2866 else if (mode == GL_QUADS && (n_vertices_in % 4) == 0)
2868 for (i = 0; i < n_vertices_in; i += 4)
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);
2883 cogl_buffer_unmap (COGL_BUFFER (index_buffer));
2885 *n_indices = n_lines * 2;
2887 ret = cogl_indices_new (ctx,
2888 COGL_INDICES_TYPE_UNSIGNED_INT,
2892 g_free (line_indices);
2898 remove_layer_cb (CoglPipeline *pipeline,
2902 cogl_pipeline_remove_layer (pipeline, layer_index);
2907 pipeline_destroyed_cb (CoglPipeline *weak_pipeline, void *user_data)
2909 CoglPipeline *original_pipeline = user_data;
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.
2916 * Setting more user data here will *probably* succeed but that may allocate
2917 * a new user-data array which could be leaked.
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.
2923 cogl_object_set_user_data (COGL_OBJECT (original_pipeline),
2924 &wire_pipeline_key, NULL, NULL);
2926 cogl_object_unref (weak_pipeline);
2930 draw_wireframe (CoglContext *ctx,
2931 CoglFramebuffer *framebuffer,
2932 CoglPipeline *pipeline,
2933 CoglVerticesMode mode,
2936 CoglAttribute **attributes,
2938 CoglIndices *indices)
2940 CoglIndices *wire_indices;
2941 CoglPipeline *wire_pipeline;
2944 wire_indices = get_wire_line_indices (ctx,
2951 wire_pipeline = cogl_object_get_user_data (COGL_OBJECT (pipeline),
2952 &wire_pipeline_key);
2957 _cogl_pipeline_weak_copy (pipeline, pipeline_destroyed_cb, NULL);
2959 cogl_object_set_user_data (COGL_OBJECT (pipeline),
2960 &wire_pipeline_key, wire_pipeline,
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))
2969 CoglSnippet *snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
2972 cogl_snippet_set_replace (snippet,
2974 "vec4 (0.0, 1.0, 0.0, 1.0);\n");
2976 cogl_pipeline_add_snippet (wire_pipeline, snippet);
2977 cogl_object_unref (snippet);
2981 cogl_pipeline_foreach_layer (wire_pipeline, remove_layer_cb, NULL);
2982 cogl_pipeline_set_color4f (wire_pipeline, 0, 1, 0, 1);
2986 /* temporarily disable the wireframe to avoid recursion! */
2987 COGL_DEBUG_CLEAR_FLAG (COGL_DEBUG_WIREFRAME);
2988 _cogl_framebuffer_draw_indexed_attributes (
2991 COGL_VERTICES_MODE_LINES,
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);
3003 cogl_object_unref (wire_indices);
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. */
3011 _cogl_framebuffer_draw_attributes (CoglFramebuffer *framebuffer,
3012 CoglPipeline *pipeline,
3013 CoglVerticesMode mode,
3016 CoglAttribute **attributes,
3018 CoglDrawFlags flags)
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);
3029 _cogl_flush_attributes_state (framebuffer, pipeline, flags,
3030 attributes, n_attributes);
3032 GE (framebuffer->context,
3033 glDrawArrays ((GLenum)mode, first_vertex, n_vertices));
3038 cogl_framebuffer_draw_attributes (CoglFramebuffer *framebuffer,
3039 CoglPipeline *pipeline,
3040 CoglVerticesMode mode,
3043 CoglAttribute **attributes,
3046 _cogl_framebuffer_draw_attributes (framebuffer,
3051 attributes, n_attributes,
3052 COGL_DRAW_SKIP_LEGACY_STATE);
3056 cogl_framebuffer_vdraw_attributes (CoglFramebuffer *framebuffer,
3057 CoglPipeline *pipeline,
3058 CoglVerticesMode mode,
3065 CoglAttribute *attribute;
3066 CoglAttribute **attributes;
3069 va_start (ap, n_vertices);
3070 for (n_attributes = 0; va_arg (ap, CoglAttribute *); n_attributes++)
3074 attributes = g_alloca (sizeof (CoglAttribute *) * n_attributes);
3076 va_start (ap, n_vertices);
3077 for (i = 0; (attribute = va_arg (ap, CoglAttribute *)); i++)
3078 attributes[i] = attribute;
3081 _cogl_framebuffer_draw_attributes (framebuffer,
3083 mode, first_vertex, n_vertices,
3084 attributes, n_attributes,
3085 COGL_DRAW_SKIP_LEGACY_STATE);
3089 sizeof_index_type (CoglIndicesType type)
3093 case COGL_INDICES_TYPE_UNSIGNED_BYTE:
3095 case COGL_INDICES_TYPE_UNSIGNED_SHORT:
3097 case COGL_INDICES_TYPE_UNSIGNED_INT:
3100 g_return_val_if_reached (0);
3104 _cogl_framebuffer_draw_indexed_attributes (CoglFramebuffer *framebuffer,
3105 CoglPipeline *pipeline,
3106 CoglVerticesMode mode,
3109 CoglIndices *indices,
3110 CoglAttribute **attributes,
3112 CoglDrawFlags flags)
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);
3125 size_t buffer_offset;
3127 GLenum indices_gl_type = 0;
3129 _cogl_flush_attributes_state (framebuffer, pipeline, flags,
3130 attributes, n_attributes);
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));
3137 switch (cogl_indices_get_type (indices))
3139 case COGL_INDICES_TYPE_UNSIGNED_BYTE:
3140 indices_gl_type = GL_UNSIGNED_BYTE;
3142 case COGL_INDICES_TYPE_UNSIGNED_SHORT:
3143 indices_gl_type = GL_UNSIGNED_SHORT;
3145 case COGL_INDICES_TYPE_UNSIGNED_INT:
3146 indices_gl_type = GL_UNSIGNED_INT;
3150 GE (framebuffer->context,
3151 glDrawElements ((GLenum)mode,
3154 base + buffer_offset + index_size * first_vertex));
3156 _cogl_buffer_unbind (buffer);
3161 cogl_framebuffer_draw_indexed_attributes (CoglFramebuffer *framebuffer,
3162 CoglPipeline *pipeline,
3163 CoglVerticesMode mode,
3166 CoglIndices *indices,
3167 CoglAttribute **attributes,
3170 _cogl_framebuffer_draw_indexed_attributes (framebuffer,
3173 n_vertices, indices,
3174 attributes, n_attributes,
3175 COGL_DRAW_SKIP_LEGACY_STATE);
3179 cogl_framebuffer_vdraw_indexed_attributes (CoglFramebuffer *framebuffer,
3180 CoglPipeline *pipeline,
3181 CoglVerticesMode mode,
3184 CoglIndices *indices,
3189 CoglAttribute **attributes;
3191 CoglAttribute *attribute;
3193 va_start (ap, indices);
3194 for (n_attributes = 0; va_arg (ap, CoglAttribute *); n_attributes++)
3198 attributes = g_alloca (sizeof (CoglAttribute *) * n_attributes);
3200 va_start (ap, indices);
3201 for (i = 0; (attribute = va_arg (ap, CoglAttribute *)); i++)
3202 attributes[i] = attribute;
3205 _cogl_framebuffer_draw_indexed_attributes (framebuffer,
3213 COGL_DRAW_SKIP_LEGACY_STATE);
3217 _cogl_framebuffer_draw_primitive (CoglFramebuffer *framebuffer,
3218 CoglPipeline *pipeline,
3219 CoglPrimitive *primitive,
3220 CoglDrawFlags flags)
3222 if (primitive->indices)
3223 _cogl_framebuffer_draw_indexed_attributes (framebuffer,
3226 primitive->first_vertex,
3227 primitive->n_vertices,
3229 primitive->attributes,
3230 primitive->n_attributes,
3233 _cogl_framebuffer_draw_attributes (framebuffer,
3236 primitive->first_vertex,
3237 primitive->n_vertices,
3238 primitive->attributes,
3239 primitive->n_attributes,
3244 cogl_framebuffer_draw_primitive (CoglFramebuffer *framebuffer,
3245 CoglPipeline *pipeline,
3246 CoglPrimitive *primitive)
3248 _cogl_framebuffer_draw_primitive (framebuffer, pipeline, primitive,
3249 COGL_DRAW_SKIP_LEGACY_STATE);
3253 cogl_framebuffer_draw_rectangle (CoglFramebuffer *framebuffer,
3254 CoglPipeline *pipeline,
3260 const float position[4] = {x_1, y_1, x_2, y_2};
3261 CoglMultiTexturedRect rect;
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.
3268 rect.position = position;
3269 rect.tex_coords = NULL;
3270 rect.tex_coords_len = 0;
3272 _cogl_framebuffer_draw_multitextured_rectangles (framebuffer,
3280 cogl_framebuffer_draw_textured_rectangle (CoglFramebuffer *framebuffer,
3281 CoglPipeline *pipeline,
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;
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.
3300 rect.position = position;
3301 rect.tex_coords = tex_coords;
3302 rect.tex_coords_len = 4;
3304 _cogl_framebuffer_draw_multitextured_rectangles (framebuffer,
3312 cogl_framebuffer_draw_multitextured_rectangle (CoglFramebuffer *framebuffer,
3313 CoglPipeline *pipeline,
3318 const float *tex_coords,
3321 const float position[4] = {x_1, y_1, x_2, y_2};
3322 CoglMultiTexturedRect rect;
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.
3329 rect.position = position;
3330 rect.tex_coords = tex_coords;
3331 rect.tex_coords_len = tex_coords_len;
3333 _cogl_framebuffer_draw_multitextured_rectangles (framebuffer,
3341 cogl_framebuffer_draw_rectangles (CoglFramebuffer *framebuffer,
3342 CoglPipeline *pipeline,
3343 const float *coordinates,
3344 unsigned int n_rectangles)
3346 CoglMultiTexturedRect *rects;
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.
3354 rects = g_alloca (n_rectangles * sizeof (CoglMultiTexturedRect));
3356 for (i = 0; i < n_rectangles; i++)
3358 rects[i].position = &coordinates[i * 4];
3359 rects[i].tex_coords = NULL;
3360 rects[i].tex_coords_len = 0;
3363 _cogl_framebuffer_draw_multitextured_rectangles (framebuffer,
3371 cogl_framebuffer_draw_textured_rectangles (CoglFramebuffer *framebuffer,
3372 CoglPipeline *pipeline,
3373 const float *coordinates,
3374 unsigned int n_rectangles)
3376 CoglMultiTexturedRect *rects;
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.
3384 rects = g_alloca (n_rectangles * sizeof (CoglMultiTexturedRect));
3386 for (i = 0; i < n_rectangles; i++)
3388 rects[i].position = &coordinates[i * 8];
3389 rects[i].tex_coords = &coordinates[i * 8 + 4];
3390 rects[i].tex_coords_len = 4;
3393 _cogl_framebuffer_draw_multitextured_rectangles (framebuffer,