[draw-buffers] First pass at overhauling Cogl's framebuffer management
authorRobert Bragg <robert@linux.intel.com>
Fri, 25 Sep 2009 13:34:34 +0000 (14:34 +0100)
committerRobert Bragg <robert@linux.intel.com>
Tue, 3 Nov 2009 17:23:03 +0000 (17:23 +0000)
Cogl's support for offscreen rendering was originally written just to support
the clutter_texture_new_from_actor API and due to lack of documentation and
several confusing - non orthogonal - side effects of using the API it wasn't
really possible to use directly.

This commit does a number of things:
- It removes {gl,gles}/cogl-fbo.{c,h} and adds shared cogl-draw-buffer.{c,h}
  files instead which should be easier to maintain.
- internally CoglFbo objects are now called CoglDrawBuffers. A
  CoglDrawBuffer is an abstract base class that is inherited from to
  implement CoglOnscreen and CoglOffscreen draw buffers.  CoglOffscreen draw
  buffers will initially be used to support the
  cogl_offscreen_new_to_texture API, and CoglOnscreen draw buffers will
  start to be used internally to represent windows as we aim to migrate some
  of Clutter's backend code to Cogl.
- It makes draw buffer objects the owners of the following state:
  - viewport
  - projection matrix stack
  - modelview matrix stack
  - clip state
(This means when you switch between draw buffers you will automatically be
 switching to their associated viewport, matrix and clip state)

Aside from hopefully making cogl_offscreen_new_to_texture be more useful
short term by having simpler and well defined semantics for
cogl_set_draw_buffer, as mentioned above this is the first step for a couple
of other things:
- Its a step toward moving ownership for windows down from Clutter backends
  into Cogl, by (internally at least) introducing the CoglOnscreen draw
  buffer.  Note: the plan is that cogl_set_draw_buffer will accept on or
  offscreen draw buffer handles, and the "target" argument will become
  redundant since we will instead query the type of the given draw buffer
  handle.
- Because we have a common type for on and offscreen framebuffers we can
  provide a unified API for framebuffer management. Things like:
  - blitting between buffers
  - managing ancillary buffers (e.g. attaching depth and stencil buffers)
  - size requisition
  - clearing

31 files changed:
clutter/clutter-main.c
clutter/cogl/cogl/Makefile.am
clutter/cogl/cogl/cogl-clip-stack.c
clutter/cogl/cogl/cogl-clip-stack.h
clutter/cogl/cogl/cogl-context.c
clutter/cogl/cogl/cogl-context.h
clutter/cogl/cogl/cogl-draw-buffer-private.h [new file with mode: 0644]
clutter/cogl/cogl/cogl-draw-buffer.c [new file with mode: 0644]
clutter/cogl/cogl/cogl-journal.c
clutter/cogl/cogl/cogl-primitives.c
clutter/cogl/cogl/cogl-texture.c
clutter/cogl/cogl/cogl-vertex-buffer.c
clutter/cogl/cogl/cogl.c
clutter/cogl/cogl/cogl.h.in
clutter/cogl/cogl/driver/gl/Makefile.am
clutter/cogl/cogl/driver/gl/cogl-context-driver.c
clutter/cogl/cogl/driver/gl/cogl-context-driver.h
clutter/cogl/cogl/driver/gl/cogl-defines.h.in
clutter/cogl/cogl/driver/gl/cogl-fbo.c [deleted file]
clutter/cogl/cogl/driver/gl/cogl-fbo.h [deleted file]
clutter/cogl/cogl/driver/gl/cogl-primitives.c
clutter/cogl/cogl/driver/gl/cogl-texture-driver.c
clutter/cogl/cogl/driver/gl/cogl.c
clutter/cogl/cogl/driver/gles/Makefile.am
clutter/cogl/cogl/driver/gles/cogl-context-driver.c
clutter/cogl/cogl/driver/gles/cogl-context-driver.h
clutter/cogl/cogl/driver/gles/cogl-defines.h.in
clutter/cogl/cogl/driver/gles/cogl-fbo.c [deleted file]
clutter/cogl/cogl/driver/gles/cogl-fbo.h [deleted file]
clutter/cogl/cogl/driver/gles/cogl-primitives.c
clutter/cogl/cogl/driver/gles/cogl.c

index f62d6bd..8559da5 100644 (file)
@@ -1338,6 +1338,8 @@ clutter_init_real (GError **error)
   /* Now we can safely assume we have a valid GL context and can
    * start issueing cogl commands
   */
+  /* - will call to backend and cogl */
+  _clutter_feature_init ();
 
   /*
    * Resolution requires display to be open, so can only be queried after
@@ -1374,9 +1376,6 @@ clutter_init_real (GError **error)
   /* Initiate event collection */
   _clutter_backend_init_events (ctx->backend);
 
-  /* finally features - will call to backend and cogl */
-  _clutter_feature_init ();
-
   clutter_is_initialized = TRUE;
   ctx->is_initialized = TRUE;
 
index 81c5186..8988f8d 100644 (file)
@@ -120,6 +120,8 @@ libclutter_cogl_la_SOURCES =                                \
        $(srcdir)/cogl-spans.c                          \
        $(srcdir)/cogl-journal-private.h                \
        $(srcdir)/cogl-journal.c                        \
+       $(srcdir)/cogl-draw-buffer-private.h            \
+       $(srcdir)/cogl-draw-buffer.c                    \
        $(BUILT_SOURCES)                                \
        $(NULL)
 
index a0dc3bc..8cf59d1 100644 (file)
@@ -34,6 +34,7 @@
 #include "cogl-primitives.h"
 #include "cogl-context.h"
 #include "cogl-internal.h"
+#include "cogl-draw-buffer-private.h"
 
 /* These are defined in the particular backend (float in GL vs fixed
    in GL ES) */
@@ -119,15 +120,24 @@ cogl_clip_push_window_rect (float x_offset,
                            float width,
                            float height)
 {
-  CoglClipStackEntryWindowRect *entry;
+  CoglHandle draw_buffer;
+  CoglClipStackState *clip_state;
   CoglClipStack *stack;
-  float v[4];
+  CoglClipStackEntryWindowRect *entry;
+  float viewport_height;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  stack = (CoglClipStack *) ctx->clip.stacks->data;
+  /* We don't log clip stack changes in the journal so we must flush
+   * it before making modifications */
+  _cogl_journal_flush ();
 
-  cogl_get_viewport (v);
+  draw_buffer = _cogl_get_draw_buffer ();
+  clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer);
+
+  stack = clip_state->stacks->data;
+
+  viewport_height = _cogl_draw_buffer_get_viewport_height (draw_buffer);
 
   entry = g_slice_new (CoglClipStackEntryWindowRect);
 
@@ -135,14 +145,14 @@ cogl_clip_push_window_rect (float x_offset,
    * with (0,0) at bottom left. */
   entry->type = COGL_CLIP_STACK_WINDOW_RECT;
   entry->x0 = x_offset;
-  entry->y0 = v[3] - y_offset - height;
+  entry->y0 = viewport_height - y_offset - height;
   entry->x1 = x_offset + width;
-  entry->y1 = v[3] - y_offset;
+  entry->y1 = viewport_height - y_offset;
 
   /* Store it in the stack */
   stack->stack_top = g_list_prepend (stack->stack_top, entry);
 
-  ctx->clip.stack_dirty = TRUE;
+  clip_state->stack_dirty = TRUE;
 }
 
 /* Scale from OpenGL <-1,1> coordinates system to window coordinates
@@ -214,17 +224,26 @@ cogl_clip_push (float x_offset,
                float width,
                float height)
 {
-  CoglClipStackEntryRect *entry;
+  CoglHandle draw_buffer;
+  CoglClipStackState *clip_state;
   CoglClipStack *stack;
+  CoglClipStackEntryRect *entry;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
+  /* We don't log clip stack changes in the journal so we must flush
+   * it before making modifications */
+  _cogl_journal_flush ();
+
   /* Try and catch window space rectangles so we can redirect to
    * cogl_clip_push_window_rect which will use scissoring. */
   if (try_pushing_rect_as_window_rect (x_offset, y_offset, width, height))
     return;
 
-  stack = (CoglClipStack *) ctx->clip.stacks->data;
+  draw_buffer = _cogl_get_draw_buffer ();
+  clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer);
+
+  stack = clip_state->stacks->data;
 
   entry = g_slice_new (CoglClipStackEntryRect);
 
@@ -240,18 +259,27 @@ cogl_clip_push (float x_offset,
   /* Store it in the stack */
   stack->stack_top = g_list_prepend (stack->stack_top, entry);
 
-  ctx->clip.stack_dirty = TRUE;
+  clip_state->stack_dirty = TRUE;
 }
 
 void
 cogl_clip_push_from_path_preserve (void)
 {
-  CoglClipStackEntryPath *entry;
+  CoglHandle draw_buffer;
+  CoglClipStackState *clip_state;
   CoglClipStack *stack;
+  CoglClipStackEntryPath *entry;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  stack = (CoglClipStack *) ctx->clip.stacks->data;
+  /* We don't log clip stack changes in the journal so we must flush
+   * it before making modifications */
+  _cogl_journal_flush ();
+
+  draw_buffer = _cogl_get_draw_buffer ();
+  clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer);
+
+  stack = clip_state->stacks->data;
 
   entry = g_malloc (sizeof (CoglClipStackEntryPath)
                     + sizeof (CoglPathNode) * (ctx->path_nodes->len - 1));
@@ -268,7 +296,7 @@ cogl_clip_push_from_path_preserve (void)
   /* Store it in the stack */
   stack->stack_top = g_list_prepend (stack->stack_top, entry);
 
-  ctx->clip.stack_dirty = TRUE;
+  clip_state->stack_dirty = TRUE;
 }
 
 void
@@ -279,16 +307,18 @@ cogl_clip_push_from_path (void)
   cogl_path_new ();
 }
 
-void
-cogl_clip_pop (void)
+static void
+_cogl_clip_pop_real (CoglClipStackState *clip_state)
 {
-  gpointer entry;
   CoglClipStack *stack;
+  gpointer entry;
   CoglClipStackEntryType type;
 
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+  /* We don't log clip stack changes in the journal so we must flush
+   * it before making modifications */
+  _cogl_journal_flush ();
 
-  stack = (CoglClipStack *) ctx->clip.stacks->data;
+  stack = clip_state->stacks->data;
 
   g_return_if_fail (stack->stack_top != NULL);
 
@@ -306,35 +336,57 @@ cogl_clip_pop (void)
   stack->stack_top = g_list_delete_link (stack->stack_top,
                                          stack->stack_top);
 
-  ctx->clip.stack_dirty = TRUE;
+  clip_state->stack_dirty = TRUE;
+}
+
+void
+cogl_clip_pop (void)
+{
+  CoglHandle draw_buffer;
+  CoglClipStackState *clip_state;
+
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  draw_buffer = _cogl_get_draw_buffer ();
+  clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer);
+
+  _cogl_clip_pop_real (clip_state);
 }
 
 void
-_cogl_clip_stack_rebuild (void)
+_cogl_flush_clip_state (CoglClipStackState *clip_state)
 {
-  int has_clip_planes = cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES);
+  CoglClipStack *stack;
+  int has_clip_planes;
   gboolean using_clip_planes = FALSE;
   gboolean using_stencil_buffer = FALSE;
   GList *node;
-  CoglClipStack *stack;
   gint scissor_x0 = 0;
   gint scissor_y0 = 0;
   gint scissor_x1 = G_MAXINT;
   gint scissor_y1 = G_MAXINT;
-  CoglMatrixStack *modelview_stack;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+  CoglMatrixStack *modelview_stack =
+    _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
 
-  modelview_stack = ctx->modelview_stack;
+  if (!clip_state->stack_dirty)
+    return;
 
   /* The current primitive journal does not support tracking changes to the
    * clip stack...  */
   _cogl_journal_flush ();
 
-  stack = (CoglClipStack *) ctx->clip.stacks->data;
+  /* XXX: the handling of clipping is quite complex. It may involve use of
+   * the Cogl Journal or other Cogl APIs which may end up recursively
+   * wanting to ensure the clip state is flushed. We need to ensure we
+   * don't recurse infinitely...
+   */
+  clip_state->stack_dirty = FALSE;
+
+  has_clip_planes = cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES);
+
+  stack = clip_state->stacks->data;
 
-  ctx->clip.stack_dirty = FALSE;
-  ctx->clip.stencil_used = FALSE;
+  clip_state->stencil_used = FALSE;
 
   _cogl_disable_clip_planes ();
   _cogl_disable_stencil_buffer ();
@@ -433,74 +485,111 @@ _cogl_clip_stack_rebuild (void)
                      scissor_y1 - scissor_y0));
     }
 
-  ctx->clip.stencil_used = using_stencil_buffer;
+  clip_state->stencil_used = using_stencil_buffer;
 }
 
+/* XXX: This should never have been made public API! */
 void
 cogl_clip_ensure (void)
 {
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+  CoglClipStackState *clip_state;
 
-  if (ctx->clip.stack_dirty)
-    _cogl_clip_stack_rebuild ();
+  clip_state = _cogl_draw_buffer_get_clip_state (_cogl_get_draw_buffer ());
+  _cogl_flush_clip_state (clip_state);
 }
 
-void
-cogl_clip_stack_save (void)
+static void
+_cogl_clip_stack_save_real (CoglClipStackState *clip_state)
 {
   CoglClipStack *stack;
 
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+  /* We don't log clip stack changes in the journal so we must flush
+   * it before making modifications */
+  _cogl_journal_flush ();
 
   stack = g_slice_new (CoglClipStack);
   stack->stack_top = NULL;
 
-  ctx->clip.stacks = g_slist_prepend (ctx->clip.stacks, stack);
-
-  ctx->clip.stack_dirty = TRUE;
+  clip_state->stacks = g_slist_prepend (clip_state->stacks, stack);
+  clip_state->stack_dirty = TRUE;
 }
 
 void
-cogl_clip_stack_restore (void)
+cogl_clip_stack_save (void)
 {
-  CoglClipStack *stack;
+  CoglHandle draw_buffer;
+  CoglClipStackState *clip_state;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  g_return_if_fail (ctx->clip.stacks != NULL);
+  draw_buffer = _cogl_get_draw_buffer ();
+  clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer);
+
+  _cogl_clip_stack_save_real (clip_state);
+}
+
+static void
+_cogl_clip_stack_restore_real (CoglClipStackState *clip_state)
+{
+  CoglClipStack *stack;
+
+  g_return_if_fail (clip_state->stacks != NULL);
 
-  stack = (CoglClipStack *) ctx->clip.stacks->data;
+  /* We don't log clip stack changes in the journal so we must flush
+   * it before making modifications */
+  _cogl_journal_flush ();
+
+  stack = clip_state->stacks->data;
 
   /* Empty the current stack */
   while (stack->stack_top)
-    cogl_clip_pop ();
+    _cogl_clip_pop_real (clip_state);
 
   /* Revert to an old stack */
   g_slice_free (CoglClipStack, stack);
-  ctx->clip.stacks = g_slist_delete_link (ctx->clip.stacks,
-                                          ctx->clip.stacks);
+  clip_state->stacks = g_slist_delete_link (clip_state->stacks,
+                                            clip_state->stacks);
 
-  ctx->clip.stack_dirty = TRUE;
+  clip_state->stack_dirty = TRUE;
 }
 
 void
-_cogl_clip_stack_state_init (void)
+cogl_clip_stack_restore (void)
 {
+  CoglHandle draw_buffer;
+  CoglClipStackState *clip_state;
+
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  ctx->clip.stacks = NULL;
-  ctx->clip.stack_dirty = TRUE;
+  draw_buffer = _cogl_get_draw_buffer ();
+  clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer);
 
-  /* Add an intial stack */
-  cogl_clip_stack_save ();
+  _cogl_clip_stack_restore_real (clip_state);
 }
 
 void
-_cogl_clip_stack_state_destroy (void)
+_cogl_clip_stack_state_init (CoglClipStackState *clip_state)
 {
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
+  clip_state->stacks = NULL;
+  clip_state->stack_dirty = TRUE;
+
+  /* Add an intial stack */
+  _cogl_clip_stack_save_real (clip_state);
+}
+
+void
+_cogl_clip_stack_state_destroy (CoglClipStackState *clip_state)
+{
   /* Destroy all of the stacks */
-  while (ctx->clip.stacks)
-    cogl_clip_stack_restore ();
+  while (clip_state->stacks)
+    _cogl_clip_stack_restore_real (clip_state);
 }
+
+void
+_cogl_clip_stack_state_dirty (CoglClipStackState *clip_state)
+{
+  clip_state->stack_dirty = TRUE;
+}
+
index 324097b..0ca041e 100644 (file)
@@ -35,9 +35,10 @@ struct _CoglClipStackState
   gboolean stencil_used;
 };
 
-void _cogl_clip_stack_state_init (void);
-void _cogl_clip_stack_state_destroy (void);
-void _cogl_clip_stack_rebuild (void);
-void _cogl_clip_stack_merge (void);
+void _cogl_clip_stack_state_init (CoglClipStackState *state);
+void _cogl_clip_stack_state_destroy (CoglClipStackState *state);
+void _cogl_clip_stack_state_dirty (CoglClipStackState *state);
+
+void _cogl_flush_clip_state (CoglClipStackState *clip_state);
 
 #endif /* __COGL_CLIP_STACK_H */
index 6cbc7b7..8005aaf 100644 (file)
@@ -32,6 +32,7 @@
 #include "cogl-journal-private.h"
 #include "cogl-texture-private.h"
 #include "cogl-material-private.h"
+#include "cogl-draw-buffer-private.h"
 
 #include <string.h>
 
@@ -46,7 +47,7 @@ cogl_create_context (void)
 {
   GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 };
   gulong  enable_flags = 0;
-  CoglDrawBufferState *draw_buffer;
+  CoglHandle window_buffer;
 
   if (_context != NULL)
     return FALSE;
@@ -66,8 +67,6 @@ cogl_create_context (void)
   _context->indirect = gl_is_indirect;
 
   _context->flushed_matrix_mode = COGL_MATRIX_MODELVIEW;
-  _context->modelview_stack = _cogl_matrix_stack_new ();
-  _context->projection_stack = _cogl_matrix_stack_new ();
   _context->texture_units = NULL;
 
   _context->default_material = cogl_material_new ();
@@ -87,11 +86,14 @@ cogl_create_context (void)
                                           sizeof (CoglLayerInfo));
   _context->n_texcoord_arrays_enabled = 0;
 
-  draw_buffer = g_slice_new0 (CoglDrawBufferState);
-  draw_buffer->target = COGL_WINDOW_BUFFER;
-  draw_buffer->offscreen = COGL_INVALID_HANDLE;
-  _context->draw_buffer_stack =
-    g_slist_prepend (NULL, draw_buffer);
+  _context->draw_buffer_stack = _cogl_create_draw_buffer_stack ();
+  window_buffer = _cogl_onscreen_new ();
+  /* XXX: When setting up the window buffer, cogl_set_draw_buffer
+   * assumes that the handle can be found in ctx->window_buffer */
+  _context->window_buffer = window_buffer;
+  cogl_set_draw_buffer (COGL_WINDOW_BUFFER, 0/* ignored */);
+  _context->dirty_bound_framebuffer = TRUE;
+  _context->dirty_viewport = TRUE;
 
   _context->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode));
   _context->last_path = 0;
@@ -99,20 +101,16 @@ cogl_create_context (void)
 
   _context->in_begin_gl_block = FALSE;
 
-  _context->viewport_width = 0;
-  _context->viewport_height = 0;
-
   _context->quad_indices_byte = COGL_INVALID_HANDLE;
   _context->quad_indices_short = COGL_INVALID_HANDLE;
   _context->quad_indices_short_len = 0;
 
   _context->texture_download_material = COGL_INVALID_HANDLE;
 
-  /* Initialise the clip stack */
-  _cogl_clip_stack_state_init ();
-
   /* Initialise the driver specific state */
+  /* TODO: combine these two into one function */
   _cogl_create_context_driver (_context);
+  _cogl_features_init ();
 
   /* Create default textures used for fall backs */
   _context->default_gl_texture_2d_tex =
@@ -146,16 +144,14 @@ cogl_create_context (void)
 void
 _cogl_destroy_context ()
 {
+
   if (_context == NULL)
     return;
 
-  _cogl_clip_stack_state_destroy ();
-
-  _cogl_matrix_stack_destroy (_context->modelview_stack);
-  _cogl_matrix_stack_destroy (_context->projection_stack);
-
   _cogl_destroy_texture_units ();
 
+  _cogl_free_draw_buffer_stack (_context->draw_buffer_stack);
+
   if (_context->path_nodes)
     g_array_free (_context->path_nodes, TRUE);
 
index cf8e3ad..67e33cc 100644 (file)
@@ -40,12 +40,6 @@ typedef struct
 
 typedef struct
 {
-  CoglBufferTarget target;
-  CoglHandle offscreen;
-} CoglDrawBufferState;
-
-typedef struct
-{
   /* Features cache */
   CoglFeatureFlags  feature_flags;
   gboolean          features_cached;
@@ -60,9 +54,6 @@ typedef struct
 
   /* Client-side matrix stack or NULL if none */
   CoglMatrixMode    flushed_matrix_mode;
-  CoglMatrixStack  *projection_stack;
-  CoglMatrixStack  *modelview_stack;
-
   GList            *texture_units;
 
   /* Cache of inverse projection matrix */
@@ -91,11 +82,11 @@ typedef struct
   GArray           *current_layers;
   guint             n_texcoord_arrays_enabled;
 
-  /* Framebuffer objects */
+  /* Draw Buffers */
   GSList           *draw_buffer_stack;
-
-  /* Clip stack */
-  CoglClipStackState clip;
+  CoglHandle        window_buffer;
+  gboolean          dirty_bound_framebuffer;
+  gboolean          dirty_viewport;
 
   /* Primitives */
   floatVec2         path_start;
@@ -114,9 +105,6 @@ typedef struct
 
   gboolean          in_begin_gl_block;
 
-  guint             viewport_width;
-  guint             viewport_height;
-
   CoglHandle        texture_download_material;
 
   CoglContextDriver drv;
diff --git a/clutter/cogl/cogl/cogl-draw-buffer-private.h b/clutter/cogl/cogl/cogl-draw-buffer-private.h
new file mode 100644 (file)
index 0000000..d5bdf0b
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2007,2008,2009 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __COGL_DRAW_BUFFER_PRIVATE_H
+#define __COGL_DRAW_BUFFER_PRIVATE_H
+
+#include "cogl-handle.h"
+#include "cogl-matrix-stack.h"
+#include "cogl-clip-stack.h"
+
+typedef enum _CoglDrawBufferType {
+  COGL_DRAW_BUFFER_TYPE_ONSCREEN,
+  COGL_DRAW_BUFFER_TYPE_OFFSCREEN
+} CoglDrawBufferType;
+
+typedef struct
+{
+  CoglHandleObject    _parent;
+  CoglDrawBufferType  type;
+  int                 width;
+  int                 height;
+
+  CoglMatrixStack    *modelview_stack;
+  CoglMatrixStack    *projection_stack;
+  int                 viewport_x;
+  int                 viewport_y;
+  int                 viewport_width;
+  int                 viewport_height;
+
+  CoglClipStackState  clip_state;
+} CoglDrawBuffer;
+
+#define COGL_DRAW_BUFFER(X) ((CoglDrawBuffer *)(X))
+
+typedef struct _CoglDrawBufferStackEntry
+{
+  CoglBufferTarget target;
+  CoglHandle draw_buffer;
+} CoglDrawBufferStackEntry;
+
+typedef struct _CoglOffscreen
+{
+  CoglDrawBuffer  _parent;
+  GLuint          fbo_handle;
+  GLuint          gl_stencil_handle;
+} CoglOffscreen;
+
+#define COGL_OFFSCREEN(X) ((CoglOffscreen *)(X))
+
+typedef struct _CoglOnscreen
+{
+  CoglDrawBuffer  _parent;
+} CoglOnscreen;
+
+#define COGL_ONSCREEN(X) ((CoglOnscreen *)(X))
+
+void
+_cogl_draw_buffer_state_init (void);
+CoglClipStackState *
+_cogl_draw_buffer_get_clip_state (CoglHandle handle);
+void
+_cogl_draw_buffer_set_viewport (CoglHandle handle,
+                                int x,
+                                int y,
+                                int width,
+                                int height);
+int
+_cogl_draw_buffer_get_viewport_x (CoglHandle handle);
+int
+_cogl_draw_buffer_get_viewport_y (CoglHandle handle);
+int
+_cogl_draw_buffer_get_viewport_width (CoglHandle handle);
+int
+_cogl_draw_buffer_get_viewport_height (CoglHandle handle);
+void
+_cogl_draw_buffer_get_viewport4fv (CoglHandle handle, int *viewport);
+CoglMatrixStack *
+_cogl_draw_buffer_get_modelview_stack (CoglHandle handle);
+CoglMatrixStack *
+_cogl_draw_buffer_get_projection_stack (CoglHandle handle);
+
+typedef enum _CoglDrawBufferFlushFlags
+{
+  /* XXX: When using this, that imples you are going to manually load the
+   * modelview matrix (via glLoadMatrix). _cogl_matrix_stack_flush_to_gl wont
+   * be called for draw_buffer->modelview_stack, and the modelview_stack will
+   * also be marked as dirty. */
+  COGL_DRAW_BUFFER_FLUSH_SKIP_MODELVIEW =     1L<<0,
+} CoglDrawBufferFlushFlags;
+
+void
+_cogl_draw_buffer_flush_state (CoglHandle handle,
+                               CoglDrawBufferFlushFlags flags);
+
+CoglHandle
+_cogl_onscreen_new (void);
+
+CoglHandle
+_cogl_get_draw_buffer (void);
+GSList *
+_cogl_create_draw_buffer_stack (void);
+void
+_cogl_free_draw_buffer_stack (GSList *stack);
+
+#endif /* __COGL_DRAW_BUFFER_PRIVATE_H */
+
diff --git a/clutter/cogl/cogl/cogl-draw-buffer.c b/clutter/cogl/cogl/cogl-draw-buffer.c
new file mode 100644 (file)
index 0000000..41f0a5f
--- /dev/null
@@ -0,0 +1,555 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2007,2008,2009 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl.h"
+#include "cogl-internal.h"
+#include "cogl-context.h"
+#include "cogl-handle.h"
+#include "cogl-util.h"
+#include "cogl-texture-private.h"
+#include "cogl-draw-buffer-private.h"
+#include "cogl-clip-stack.h"
+
+#ifdef HAVE_COGL_GLES2
+
+#include "../gles/cogl-gles2-wrapper.h"
+
+#else
+
+#define glGenRenderbuffers                ctx->drv.pf_glGenRenderbuffers
+#define glDeleteRenderbuffers             ctx->drv.pf_glDeleteRenderbuffers
+#define glBindRenderbuffer                ctx->drv.pf_glBindRenderbuffer
+#define glRenderbufferStorage             ctx->drv.pf_glRenderbufferStorage
+#define glGenFramebuffers                 ctx->drv.pf_glGenFramebuffers
+#define glBindFramebuffer                 ctx->drv.pf_glBindFramebuffer
+#define glFramebufferTexture2D            ctx->drv.pf_glFramebufferTexture2D
+#define glFramebufferRenderbuffer         ctx->drv.pf_glFramebufferRenderbuffer
+#define glCheckFramebufferStatus          ctx->drv.pf_glCheckFramebufferStatus
+#define glDeleteFramebuffers              ctx->drv.pf_glDeleteFramebuffers
+
+#endif
+
+#ifndef GL_FRAMEBUFFER
+#define GL_FRAMEBUFFER         0x8D40
+#endif
+#ifndef GL_RENDERBUFFER
+#define GL_RENDERBUFFER                0x8D41
+#endif
+#ifndef GL_STENCIL_ATTACHMENT
+#define GL_STENCIL_ATTACHMENT  0x8D00
+#endif
+#ifndef GL_COLOR_ATTACHMENT0
+#define GL_COLOR_ATTACHMENT0   0x8CE0
+#endif
+#ifndef GL_FRAMEBUFFER_COMPLETE
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#endif
+#ifndef GL_STENCIL_INDEX8
+#define GL_STENCIL_INDEX8       0x8D48
+#endif
+
+static void _cogl_draw_buffer_free (CoglDrawBuffer *draw_buffer);
+static void _cogl_onscreen_free (CoglOnscreen *onscreen);
+static void _cogl_offscreen_free (CoglOffscreen *offscreen);
+
+COGL_HANDLE_DEFINE (Onscreen, onscreen);
+COGL_HANDLE_DEFINE (Offscreen, offscreen);
+
+/* XXX:
+ * The CoglHandle macros don't support any form of inheritance, so for
+ * now we implement the CoglHandle support for the CoglDrawBuffer
+ * abstract class manually.
+ */
+
+gboolean
+cogl_is_draw_buffer (CoglHandle handle)
+{
+  CoglHandleObject *obj = (CoglHandleObject *)handle;
+
+  if (handle == COGL_INVALID_HANDLE)
+    return FALSE;
+
+  return obj->klass->type == _cogl_handle_onscreen_get_type ()
+    || obj->klass->type == _cogl_handle_offscreen_get_type ();
+}
+
+static void
+_cogl_draw_buffer_init (CoglDrawBuffer *draw_buffer,
+                        CoglDrawBufferType type,
+                        int width,
+                        int height)
+{
+  draw_buffer->type             = type;
+  draw_buffer->width            = width;
+  draw_buffer->height           = height;
+  draw_buffer->viewport_x       = 0;
+  draw_buffer->viewport_y       = 0;
+  draw_buffer->viewport_width   = width;
+  draw_buffer->viewport_height  = height;
+
+  draw_buffer->modelview_stack  = _cogl_matrix_stack_new ();
+  draw_buffer->projection_stack = _cogl_matrix_stack_new ();
+
+  /* Initialise the clip stack */
+  _cogl_clip_stack_state_init (&draw_buffer->clip_state);
+}
+
+void
+_cogl_draw_buffer_free (CoglDrawBuffer *draw_buffer)
+{
+  _cogl_clip_stack_state_destroy (&draw_buffer->clip_state);
+
+  _cogl_matrix_stack_destroy (draw_buffer->modelview_stack);
+  draw_buffer->modelview_stack = NULL;
+
+  _cogl_matrix_stack_destroy (draw_buffer->projection_stack);
+  draw_buffer->projection_stack = NULL;
+}
+
+CoglClipStackState *
+_cogl_draw_buffer_get_clip_state (CoglHandle handle)
+{
+  CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
+
+  return &draw_buffer->clip_state;
+}
+
+void
+_cogl_draw_buffer_set_viewport (CoglHandle handle,
+                                int x,
+                                int y,
+                                int width,
+                                int height)
+{
+  CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
+
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  if (draw_buffer->viewport_x == x &&
+      draw_buffer->viewport_y == y &&
+      draw_buffer->viewport_width == width &&
+      draw_buffer->viewport_height == height)
+    return;
+
+  _cogl_journal_flush ();
+
+  draw_buffer->viewport_x = x;
+  draw_buffer->viewport_y = y;
+  draw_buffer->viewport_width = width;
+  draw_buffer->viewport_height = height;
+
+  if (_cogl_get_draw_buffer () == draw_buffer)
+    ctx->dirty_viewport = TRUE;
+}
+
+int
+_cogl_draw_buffer_get_viewport_x (CoglHandle handle)
+{
+  CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
+  return draw_buffer->viewport_x;
+}
+
+int
+_cogl_draw_buffer_get_viewport_y (CoglHandle handle)
+{
+  CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
+  return draw_buffer->viewport_y;
+}
+
+int
+_cogl_draw_buffer_get_viewport_width (CoglHandle handle)
+{
+  CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
+  return draw_buffer->viewport_width;
+}
+
+int
+_cogl_draw_buffer_get_viewport_height (CoglHandle handle)
+{
+  CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
+  return draw_buffer->viewport_height;
+}
+
+void
+_cogl_draw_buffer_get_viewport4fv (CoglHandle handle, int *viewport)
+{
+  CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
+  viewport[0] = draw_buffer->viewport_x;
+  viewport[1] = draw_buffer->viewport_y;
+  viewport[2] = draw_buffer->viewport_width;
+  viewport[3] = draw_buffer->viewport_height;
+}
+
+CoglMatrixStack *
+_cogl_draw_buffer_get_modelview_stack (CoglHandle handle)
+{
+  CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
+  return draw_buffer->modelview_stack;
+}
+
+CoglMatrixStack *
+_cogl_draw_buffer_get_projection_stack (CoglHandle handle)
+{
+  CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
+  return draw_buffer->projection_stack;
+}
+
+CoglHandle
+cogl_offscreen_new_to_texture (CoglHandle texhandle)
+{
+  CoglOffscreen    *offscreen;
+  int               width;
+  int               height;
+  GLuint            tex_gl_handle;
+  GLenum            tex_gl_target;
+  GLuint            fbo_gl_handle;
+  GLuint            gl_stencil_handle;
+  GLenum            status;
+
+  _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
+
+  if (!cogl_features_available (COGL_FEATURE_OFFSCREEN))
+    return COGL_INVALID_HANDLE;
+
+  /* Make texhandle is a valid texture object */
+  if (!cogl_is_texture (texhandle))
+    return COGL_INVALID_HANDLE;
+
+  /* The texture must not be sliced */
+  if (cogl_texture_is_sliced (texhandle))
+    return COGL_INVALID_HANDLE;
+
+  /* Pick the single texture slice width, height and GL id */
+
+  width = cogl_texture_get_width (texhandle);
+  height = cogl_texture_get_height (texhandle);
+
+  if (!cogl_texture_get_gl_texture (texhandle, &tex_gl_handle, &tex_gl_target))
+    return COGL_INVALID_HANDLE;
+
+  if (tex_gl_target != GL_TEXTURE_2D)
+    return COGL_INVALID_HANDLE;
+
+  /* Create a renderbuffer for stenciling */
+  GE (glGenRenderbuffers (1, &gl_stencil_handle));
+  GE (glBindRenderbuffer (GL_RENDERBUFFER, gl_stencil_handle));
+  GE (glRenderbufferStorage (GL_RENDERBUFFER, GL_STENCIL_INDEX8,
+                            cogl_texture_get_width (texhandle),
+                            cogl_texture_get_height (texhandle)));
+  GE (glBindRenderbuffer (GL_RENDERBUFFER, 0));
+
+  /* We are about to generate and bind a new fbo, so when next flushing the
+   * journal, we will need to rebind the current draw buffer... */
+  ctx->dirty_bound_framebuffer = 1;
+
+  /* Generate framebuffer */
+  glGenFramebuffers (1, &fbo_gl_handle);
+  GE (glBindFramebuffer (GL_FRAMEBUFFER, fbo_gl_handle));
+  GE (glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                             tex_gl_target, tex_gl_handle, 0));
+  GE (glFramebufferRenderbuffer (GL_FRAMEBUFFER,
+                                GL_STENCIL_ATTACHMENT,
+                                GL_RENDERBUFFER, gl_stencil_handle));
+
+  /* XXX: The framebuffer_object spec isn't clear in defining whether attaching
+   * a texture as a renderbuffer with mipmap filtering enabled while the
+   * mipmaps have not been uploaded should result in an incomplete framebuffer
+   * object. (different drivers make different decisions)
+   *
+   * To avoid an error with drivers that do consider this a problem we
+   * explicitly set non mipmapped filters here. These will later be reset when
+   * the texture is actually used for rendering according to the filters set on
+   * the corresponding CoglMaterial.
+   */
+  _cogl_texture_set_filters (texhandle, GL_NEAREST, GL_NEAREST);
+
+  /* Make sure it's complete */
+  status = glCheckFramebufferStatus (GL_FRAMEBUFFER);
+
+  if (status != GL_FRAMEBUFFER_COMPLETE)
+    {
+      /* Stencil renderbuffers aren't always supported. Try again
+        without the stencil buffer */
+      GE (glFramebufferRenderbuffer (GL_FRAMEBUFFER,
+                                    GL_STENCIL_ATTACHMENT,
+                                    GL_RENDERBUFFER,
+                                    0));
+      GE (glDeleteRenderbuffers (1, &gl_stencil_handle));
+      gl_stencil_handle = 0;
+
+      status = glCheckFramebufferStatus (GL_FRAMEBUFFER);
+
+      if (status != GL_FRAMEBUFFER_COMPLETE)
+       {
+         /* Still failing, so give up */
+         GE (glDeleteFramebuffers (1, &fbo_gl_handle));
+         GE (glBindFramebuffer (GL_FRAMEBUFFER, 0));
+         return COGL_INVALID_HANDLE;
+       }
+    }
+
+  offscreen                     = g_new0 (CoglOffscreen, 1);
+
+  _cogl_draw_buffer_init (COGL_DRAW_BUFFER (offscreen),
+                          COGL_DRAW_BUFFER_TYPE_OFFSCREEN,
+                          width,
+                          height);
+
+  offscreen->fbo_handle         = fbo_gl_handle;
+  offscreen->gl_stencil_handle  = gl_stencil_handle;
+
+  /* XXX: Can we get a away with removing this? It wasn't documented, and most
+   * users of the API are hopefully setting up the modelview from scratch
+   * anyway */
+#if 0
+  cogl_matrix_translate (&draw_buffer->modelview, -1.0f, -1.0f, 0.0f);
+  cogl_matrix_scale (&draw_buffer->modelview,
+                     2.0f / draw_buffer->width, 2.0f / draw_buffer->height, 1.0f);
+#endif
+
+  return _cogl_offscreen_handle_new (offscreen);
+}
+
+static void
+_cogl_offscreen_free (CoglOffscreen *offscreen)
+{
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  /* Chain up to parent */
+  _cogl_draw_buffer_free (COGL_DRAW_BUFFER (offscreen));
+
+  if (offscreen->gl_stencil_handle)
+    GE (glDeleteRenderbuffers (1, &offscreen->gl_stencil_handle));
+  GE (glDeleteFramebuffers (1, &offscreen->fbo_handle));
+  g_free (offscreen);
+}
+
+CoglHandle
+_cogl_onscreen_new (void)
+{
+  CoglOnscreen *onscreen;
+
+  /* XXX: Until we have full winsys support in Cogl then we can't fully
+   * implement CoglOnscreen draw buffers, since we can't, e.g. keep track of
+   * the window size. */
+
+  onscreen = g_new0 (CoglOnscreen, 1);
+  _cogl_draw_buffer_init (COGL_DRAW_BUFFER (onscreen),
+                          COGL_DRAW_BUFFER_TYPE_ONSCREEN,
+                          0xdeadbeef, /* width */
+                          0xdeadbeef); /* height */
+
+  return _cogl_onscreen_handle_new (onscreen);
+}
+
+static void
+_cogl_onscreen_free (CoglOnscreen *onscreen)
+{
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  /* Chain up to parent */
+  _cogl_draw_buffer_free (COGL_DRAW_BUFFER (onscreen));
+
+  g_free (onscreen);
+}
+
+GSList *
+_cogl_create_draw_buffer_stack (void)
+{
+  GSList *stack = NULL;
+  CoglDrawBufferStackEntry *entry;
+
+  entry = g_slice_new0 (CoglDrawBufferStackEntry);
+  entry->target = COGL_WINDOW_BUFFER;
+  entry->draw_buffer = COGL_INVALID_HANDLE;
+
+  return g_slist_prepend (stack, entry);
+}
+
+void
+_cogl_free_draw_buffer_stack (GSList *stack)
+{
+  GSList *l;
+
+  for (l = stack; l != NULL; l = l->next)
+    {
+      CoglDrawBufferStackEntry *entry = l->data;
+      CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (entry->draw_buffer);
+      if (draw_buffer->type == COGL_DRAW_BUFFER_TYPE_OFFSCREEN)
+        _cogl_offscreen_free (COGL_OFFSCREEN (draw_buffer));
+      else
+        _cogl_onscreen_free (COGL_ONSCREEN (draw_buffer));
+    }
+  g_slist_free (stack);
+}
+
+/* XXX: The target argument is redundant; when we break API, we should
+ * remove it! */
+void
+cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle handle)
+{
+  CoglDrawBuffer *draw_buffer = NULL;
+  CoglDrawBufferStackEntry *entry;
+
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  _cogl_journal_flush ();
+
+  g_assert (ctx->draw_buffer_stack != NULL);
+  entry = ctx->draw_buffer_stack->data;
+
+  if (target == COGL_WINDOW_BUFFER)
+    handle = ctx->window_buffer;
+  else if (!cogl_is_draw_buffer (handle))
+    return;
+
+  draw_buffer = COGL_DRAW_BUFFER (handle);
+
+  if (entry->draw_buffer != draw_buffer)
+    {
+      entry->target = target;
+
+      ctx->dirty_bound_framebuffer = 1;
+      ctx->dirty_viewport = 1;
+
+      if (draw_buffer != COGL_INVALID_HANDLE)
+        cogl_handle_ref (draw_buffer);
+      if (entry->draw_buffer != COGL_INVALID_HANDLE)
+        cogl_handle_unref (entry->draw_buffer);
+      entry->draw_buffer = draw_buffer;
+
+      /* We've effectively just switched the current modelview and
+       * projection matrix stacks and clip state so we need to dirty
+       * them to ensure they get flushed for the next batch of geometry
+       * we flush */
+      _cogl_matrix_stack_dirty (draw_buffer->modelview_stack);
+      _cogl_matrix_stack_dirty (draw_buffer->projection_stack);
+      _cogl_clip_stack_state_dirty (&draw_buffer->clip_state);
+    }
+}
+
+CoglHandle
+_cogl_get_draw_buffer (void)
+{
+  CoglDrawBufferStackEntry *entry;
+
+  _COGL_GET_CONTEXT (ctx, NULL);
+
+  g_assert (ctx->draw_buffer_stack);
+  entry = ctx->draw_buffer_stack->data;
+
+  return entry->draw_buffer;
+}
+
+void
+cogl_push_draw_buffer (void)
+{
+  CoglDrawBufferStackEntry *old;
+  CoglDrawBufferStackEntry *entry;
+
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  entry = g_slice_new0 (CoglDrawBufferStackEntry);
+
+  g_assert (ctx->draw_buffer_stack);
+
+  old = ctx->draw_buffer_stack->data;
+  *entry = *old;
+
+  cogl_handle_ref (entry->draw_buffer);
+
+  ctx->draw_buffer_stack =
+    g_slist_prepend (ctx->draw_buffer_stack, entry);
+}
+
+void
+cogl_pop_draw_buffer (void)
+{
+  CoglDrawBufferStackEntry *to_pop;
+  CoglDrawBufferStackEntry *to_restore;
+
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  g_assert (ctx->draw_buffer_stack != NULL);
+
+  to_pop = ctx->draw_buffer_stack->data;
+  to_restore = ctx->draw_buffer_stack->next->data;
+
+  cogl_set_draw_buffer (to_restore->target, to_restore->draw_buffer);
+
+  cogl_handle_unref (to_pop->draw_buffer);
+  ctx->draw_buffer_stack =
+    g_slist_remove_link (ctx->draw_buffer_stack,
+                         ctx->draw_buffer_stack);
+  g_slice_free (CoglDrawBufferStackEntry, to_pop);
+}
+
+void
+_cogl_draw_buffer_flush_state (CoglHandle handle,
+                               CoglDrawBufferFlushFlags flags)
+{
+  CoglDrawBuffer *draw_buffer;
+
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  draw_buffer = COGL_DRAW_BUFFER (handle);
+
+  if (cogl_features_available (COGL_FEATURE_OFFSCREEN) &&
+      ctx->dirty_bound_framebuffer)
+    {
+      if (draw_buffer->type == COGL_DRAW_BUFFER_TYPE_OFFSCREEN)
+        {
+          GE (glBindFramebuffer (GL_FRAMEBUFFER,
+                                 COGL_OFFSCREEN (draw_buffer)->fbo_handle));
+        }
+      else
+        GE (glBindFramebuffer (GL_FRAMEBUFFER, 0));
+      ctx->dirty_bound_framebuffer = FALSE;
+    }
+
+  if (ctx->dirty_viewport)
+    {
+      GE (glViewport (draw_buffer->viewport_x,
+                      draw_buffer->viewport_y,
+                      draw_buffer->viewport_width,
+                      draw_buffer->viewport_height));
+      ctx->dirty_viewport = FALSE;
+    }
+
+  /* XXX: Flushing clip state may trash the modelview and projection
+   * matrices so we must do it before flushing the matrices...
+   */
+  _cogl_flush_clip_state (&draw_buffer->clip_state);
+
+  if (!(flags & COGL_DRAW_BUFFER_FLUSH_SKIP_MODELVIEW))
+    _cogl_matrix_stack_flush_to_gl (draw_buffer->modelview_stack,
+                                    COGL_MATRIX_MODELVIEW);
+
+  _cogl_matrix_stack_flush_to_gl (draw_buffer->projection_stack,
+                                  COGL_MATRIX_PROJECTION);
+}
+
index aa0d589..a50bf8e 100644 (file)
@@ -32,6 +32,7 @@
 #include "cogl-texture-private.h"
 #include "cogl-material-private.h"
 #include "cogl-vertex-buffer-private.h"
+#include "cogl-draw-buffer-private.h"
 
 #include <string.h>
 #include <gmodule.h>
@@ -531,6 +532,8 @@ _cogl_journal_flush (void)
   GLuint                journal_vbo;
   gboolean              vbo_fallback =
     (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
+  CoglHandle            draw_buffer;
+  CoglMatrixStack      *modelview_stack;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
@@ -547,20 +550,19 @@ _cogl_journal_flush (void)
   else
     state.vbo_offset = (char *)ctx->logged_vertices->data;
 
-  _cogl_matrix_stack_flush_to_gl (ctx->projection_stack,
-                                  COGL_MATRIX_PROJECTION);
+  draw_buffer = _cogl_get_draw_buffer ();
+  modelview_stack = _cogl_draw_buffer_get_modelview_stack (draw_buffer);
+  state.modelview_stack = modelview_stack;
 
-  state.modelview_stack = ctx->modelview_stack;
-  _cogl_matrix_stack_push (ctx->modelview_stack);
+  _cogl_matrix_stack_push (modelview_stack);
 
   /* If we have transformed all our quads at log time then we ensure no
    * further model transform is applied by loading the identity matrix
    * here... */
   if (G_LIKELY (!(cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
     {
-      _cogl_matrix_stack_load_identity (ctx->modelview_stack);
-      _cogl_matrix_stack_flush_to_gl (ctx->modelview_stack,
-                                      COGL_MATRIX_MODELVIEW);
+      _cogl_matrix_stack_load_identity (modelview_stack);
+      _cogl_matrix_stack_flush_to_gl (modelview_stack, COGL_MATRIX_MODELVIEW);
     }
 
   /* batch_and_call() batches a list of journal entries according to some
@@ -591,7 +593,7 @@ _cogl_journal_flush (void)
                   _cogl_journal_flush_vbo_offsets_and_entries, /* callback */
                   &state); /* data */
 
-  _cogl_matrix_stack_pop (ctx->modelview_stack);
+  _cogl_matrix_stack_pop (modelview_stack);
 
   for (i = 0; i < ctx->journal->len; i++)
     {
@@ -607,6 +609,18 @@ _cogl_journal_flush (void)
   g_array_set_size (ctx->logged_vertices, 0);
 }
 
+static void
+_cogl_journal_init (void)
+{
+  /* Here we flush anything that we know must remain constant until the
+   * next the the journal is flushed. Note: This lets up flush things
+   * that themselves depend on the journal, such as clip state. */
+
+  /* NB: the journal deals with flushing the modelview stack manually */
+  _cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (),
+                                 COGL_DRAW_BUFFER_FLUSH_SKIP_MODELVIEW);
+}
+
 void
 _cogl_journal_log_quad (float         x_1,
                         float         y_1,
@@ -632,6 +646,9 @@ _cogl_journal_log_quad (float         x_1,
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
+  if (ctx->logged_vertices->len == 0)
+    _cogl_journal_init ();
+
   /* The vertex data is logged into a separate array in a layout that can be
    * directly passed to OpenGL
    */
index 016833a..45ec90c 100644 (file)
@@ -32,6 +32,7 @@
 #include "cogl-texture-private.h"
 #include "cogl-material-private.h"
 #include "cogl-vertex-buffer-private.h"
+#include "cogl-draw-buffer-private.h"
 
 #include <string.h>
 #include <math.h>
@@ -396,8 +397,6 @@ _cogl_rectangles_with_multitexture_coords (
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  cogl_clip_ensure ();
-
   material = ctx->source_material;
 
   layers = cogl_material_get_layers (material);
@@ -706,7 +705,6 @@ draw_polygon_sub_texture_cb (CoglHandle tex_handle,
   options.layer0_override_texture = gl_handle;
 
   _cogl_material_flush_gl_state (ctx->source_material, &options);
-  _cogl_flush_matrix_stacks ();
 
   GE (glDrawArrays (GL_TRIANGLE_FAN, 0, state->n_vertices));
 }
@@ -840,7 +838,6 @@ _cogl_multitexture_polygon_single_primitive (CoglTextureVertex *vertices,
     options.flags |= COGL_MATERIAL_FLUSH_SKIP_GL_COLOR;
   options.fallback_layers = fallback_layers;
   _cogl_material_flush_gl_state (ctx->source_material, &options);
-  _cogl_flush_matrix_stacks ();
 
   GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices));
 }
@@ -866,7 +863,11 @@ cogl_polygon (CoglTextureVertex *vertices,
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
   _cogl_journal_flush ();
-  cogl_clip_ensure ();
+
+  /* NB: _cogl_draw_buffer_flush_state may disrupt various state (such
+   * as the material state) when flushing the clip stack, so should
+   * always be done first when preparing to draw. */
+  _cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0);
 
   material = ctx->source_material;
   layers = cogl_material_get_layers (ctx->source_material);
@@ -1030,9 +1031,6 @@ cogl_path_fill_preserve (void)
 {
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  _cogl_journal_flush ();
-  cogl_clip_ensure ();
-
   if (ctx->path_nodes->len == 0)
     return;
 
@@ -1055,10 +1053,7 @@ cogl_path_stroke_preserve (void)
   if (ctx->path_nodes->len == 0)
     return;
 
-  _cogl_journal_flush ();
-  cogl_clip_ensure ();
-
-  _cogl_path_stroke_nodes();
+  _cogl_path_stroke_nodes ();
 }
 
 void
index fa33f04..763edbc 100644 (file)
@@ -42,6 +42,7 @@
 #include "cogl-context.h"
 #include "cogl-handle.h"
 #include "cogl-primitives.h"
+#include "cogl-draw-buffer-private.h"
 
 #include <string.h>
 #include <stdlib.h>
@@ -667,7 +668,8 @@ _cogl_texture_draw_and_read (CoglTexture *tex,
                              GLuint       target_gl_type)
 {
   gint       bpp;
-  GLint      viewport[4];
+  CoglHandle draw_buffer;
+  int        viewport[4];
   CoglBitmap alpha_bmp;
   CoglHandle prev_source;
   CoglMatrixStack *projection_stack;
@@ -677,8 +679,9 @@ _cogl_texture_draw_and_read (CoglTexture *tex,
 
   bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888);
 
+  draw_buffer = _cogl_get_draw_buffer ();
   /* Viewport needs to have some size and be inside the window for this */
-  GE( glGetIntegerv (GL_VIEWPORT, viewport));
+  _cogl_draw_buffer_get_viewport4fv (draw_buffer, viewport);
   if (viewport[0] <  0 || viewport[1] <  0 ||
       viewport[2] <= 0 || viewport[3] <= 0)
     return FALSE;
@@ -688,16 +691,18 @@ _cogl_texture_draw_and_read (CoglTexture *tex,
    * works)
    */
 
-  _cogl_matrix_stack_push (ctx->projection_stack);
-  _cogl_matrix_stack_load_identity (ctx->projection_stack);
-  _cogl_matrix_stack_ortho (ctx->projection_stack,
+  projection_stack = _cogl_draw_buffer_get_projection_stack (draw_buffer);
+  _cogl_matrix_stack_push (projection_stack);
+  _cogl_matrix_stack_load_identity (projection_stack);
+  _cogl_matrix_stack_ortho (projection_stack,
                             0, (float)(viewport[2]),
                             0, (float)(viewport[3]),
                             (float)(0),
                             (float)(100));
 
-  _cogl_matrix_stack_push (ctx->modelview_stack);
-  _cogl_matrix_stack_load_identity (ctx->modelview_stack);
+  modelview_stack = _cogl_draw_buffer_get_modelview_stack (draw_buffer);
+  _cogl_matrix_stack_push (modelview_stack);
+  _cogl_matrix_stack_load_identity (modelview_stack);
 
   /* Direct copy operation */
 
index c1aa172..357d1e6 100644 (file)
 #include "cogl-texture-private.h"
 #include "cogl-material-private.h"
 #include "cogl-primitives.h"
+#include "cogl-draw-buffer-private.h"
 
 #define PAD_FOR_ALIGNMENT(VAR, TYPE_SIZE) \
   (VAR = TYPE_SIZE + ((VAR - 1) & ~(TYPE_SIZE - 1)))
@@ -1664,6 +1665,11 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
     }
   ctx->n_texcoord_arrays_enabled = max_texcoord_attrib_unit + 1;
 
+  /* NB: _cogl_draw_buffer_flush_state may disrupt various state (such
+   * as the material state) when flushing the clip stack, so should
+   * always be done first when preparing to draw. */
+  _cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0);
+
   options.flags =
     COGL_MATERIAL_FLUSH_FALLBACK_MASK |
     COGL_MATERIAL_FLUSH_DISABLE_MASK;
@@ -1753,15 +1759,11 @@ cogl_vertex_buffer_draw (CoglHandle       handle,
     return;
 
   _cogl_journal_flush ();
-  cogl_clip_ensure ();
 
   buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
 
-  cogl_clip_ensure ();
-  _cogl_flush_matrix_stacks ();
   enable_state_for_drawing_buffer (buffer);
 
-  /* FIXME: flush cogl cache */
   GE (glDrawArrays (mode, first, count));
 
   disable_state_for_drawing_buffer (buffer);
@@ -1885,7 +1887,6 @@ cogl_vertex_buffer_draw_elements (CoglHandle       handle,
     return;
 
   _cogl_journal_flush ();
-  cogl_clip_ensure ();
 
   buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
 
@@ -1894,8 +1895,6 @@ cogl_vertex_buffer_draw_elements (CoglHandle       handle,
 
   indices = _cogl_vertex_buffer_indices_pointer_from_handle (indices_handle);
 
-  cogl_clip_ensure ();
-  _cogl_flush_matrix_stacks ();
   enable_state_for_drawing_buffer (buffer);
 
   byte_offset = indices_offset * get_indices_type_size (indices->type);
@@ -1905,7 +1904,6 @@ cogl_vertex_buffer_draw_elements (CoglHandle       handle,
     GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER,
                       GPOINTER_TO_UINT (indices->vbo_name)));
 
-  /* FIXME: flush cogl cache */
   GE (glDrawRangeElements (mode, min_index, max_index,
                            count, indices->type, (void *)byte_offset));
 
index 4fb1c7e..8fdb36f 100644 (file)
@@ -38,6 +38,7 @@
 #include "cogl-context.h"
 #include "cogl-material-private.h"
 #include "cogl-winsys.h"
+#include "cogl-draw-buffer-private.h"
 
 #if defined (HAVE_COGL_GLES2) || defined (HAVE_COGL_GLES)
 #include "cogl-gles2-wrapper.h"
@@ -116,7 +117,12 @@ cogl_clear (const CoglColor *color, gulong buffers)
 
   COGL_NOTE (DRAW, "Clear begin");
 
-  cogl_clip_ensure ();
+  _cogl_journal_flush ();
+
+  /* NB: _cogl_draw_buffer_flush_state may disrupt various state (such
+   * as the material state) when flushing the clip stack, so should
+   * always be done first when preparing to draw. */
+  _cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0);
 
   if (buffers & COGL_BUFFER_BIT_COLOR)
     {
@@ -327,6 +333,10 @@ set_clip_plane (GLint plane_num,
 #endif
   GLfloat angle;
   CoglMatrix inverse_projection;
+  CoglHandle draw_buffer = _cogl_get_draw_buffer ();
+  CoglMatrixStack *modelview_stack =
+    _cogl_draw_buffer_get_modelview_stack (draw_buffer);
+
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
   /* Calculate the angle between the axes and the line crossing the
@@ -334,24 +344,25 @@ set_clip_plane (GLint plane_num,
   angle = atan2f (vertex_b[1] - vertex_a[1],
                   vertex_b[0] - vertex_a[0]) * (180.0/G_PI);
 
-  _cogl_matrix_stack_push (ctx->modelview_stack);
+  _cogl_matrix_stack_push (modelview_stack);
+
   /* Load the identity matrix and multiply by the reverse of the
      projection matrix so we can specify the plane in screen
      coordinates */
-  _cogl_matrix_stack_load_identity (ctx->modelview_stack);
+  _cogl_matrix_stack_load_identity (modelview_stack);
   cogl_matrix_init_from_array (&inverse_projection,
                                ctx->inverse_projection);
-  _cogl_matrix_stack_multiply (ctx->modelview_stack, &inverse_projection);
+  _cogl_matrix_stack_multiply (modelview_stack, &inverse_projection);
   /* Rotate about point a */
-  _cogl_matrix_stack_translate (ctx->modelview_stack,
+  _cogl_matrix_stack_translate (modelview_stack,
                                 vertex_a[0], vertex_a[1], vertex_a[2]);
   /* Rotate the plane by the calculated angle so that it will connect
      the two points */
-  _cogl_matrix_stack_rotate (ctx->modelview_stack, angle, 0.0f, 0.0f, 1.0f);
-  _cogl_matrix_stack_translate (ctx->modelview_stack,
+  _cogl_matrix_stack_rotate (modelview_stack, angle, 0.0f, 0.0f, 1.0f);
+  _cogl_matrix_stack_translate (modelview_stack,
                                 -vertex_a[0], -vertex_a[1], -vertex_a[2]);
 
-  _cogl_flush_matrix_stacks ();
+  _cogl_matrix_stack_flush_to_gl (modelview_stack, COGL_MATRIX_MODELVIEW);
 
   plane[0] = 0;
   plane[1] = -1.0;
@@ -363,7 +374,7 @@ set_clip_plane (GLint plane_num,
   GE( glClipPlane (plane_num, plane) );
 #endif
 
-  _cogl_matrix_stack_pop (ctx->modelview_stack);
+  _cogl_matrix_stack_pop (modelview_stack);
 }
 
 void
@@ -372,7 +383,12 @@ _cogl_set_clip_planes (float x_offset,
                       float width,
                       float height)
 {
+  CoglHandle draw_buffer = _cogl_get_draw_buffer ();
+  CoglMatrixStack *modelview_stack =
+    _cogl_draw_buffer_get_modelview_stack (draw_buffer);
   CoglMatrix modelview_matrix;
+  CoglMatrixStack *projection_stack =
+    _cogl_draw_buffer_get_projection_stack (draw_buffer);
   CoglMatrix projection_matrix;
 
   float vertex_tl[4] = { x_offset, y_offset, 0, 1.0 };
@@ -381,10 +397,8 @@ _cogl_set_clip_planes (float x_offset,
   float vertex_br[4] = { x_offset + width, y_offset + height,
                         0, 1.0 };
 
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  _cogl_matrix_stack_get (ctx->projection_stack, &projection_matrix);
-  _cogl_matrix_stack_get (ctx->modelview_stack, &modelview_matrix);
+  _cogl_matrix_stack_get (projection_stack, &projection_matrix);
+  _cogl_matrix_stack_get (modelview_stack, &modelview_matrix);
 
   project_vertex (&modelview_matrix, &projection_matrix, vertex_tl);
   project_vertex (&modelview_matrix, &projection_matrix, vertex_tr);
@@ -422,6 +436,7 @@ _cogl_add_stencil_clip (float x_offset,
                        gboolean first)
 {
   CoglHandle current_source;
+  CoglHandle draw_buffer = _cogl_get_draw_buffer ();
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
@@ -429,6 +444,8 @@ _cogl_add_stencil_clip (float x_offset,
    * batched geometry before we start... */
   _cogl_journal_flush ();
 
+  _cogl_draw_buffer_flush_state (draw_buffer, 0);
+
   /* temporarily swap in our special stenciling material */
   current_source = cogl_handle_ref (ctx->source_material);
   cogl_set_source (ctx->stencil_material);
@@ -450,6 +467,11 @@ _cogl_add_stencil_clip (float x_offset,
     }
   else
     {
+      CoglMatrixStack *modelview_stack =
+        _cogl_draw_buffer_get_modelview_stack (draw_buffer);
+      CoglMatrixStack *projection_stack =
+        _cogl_draw_buffer_get_projection_stack (draw_buffer);
+
       /* Add one to every pixel of the stencil buffer in the
         rectangle */
       GE( glStencilFunc (GL_NEVER, 0x1, 0x3) );
@@ -466,16 +488,16 @@ _cogl_add_stencil_clip (float x_offset,
         rectangle are set will be valid */
       GE( glStencilOp (GL_DECR, GL_DECR, GL_DECR) );
 
-      _cogl_matrix_stack_push (ctx->projection_stack);
-      _cogl_matrix_stack_load_identity (ctx->projection_stack);
+      _cogl_matrix_stack_push (projection_stack);
+      _cogl_matrix_stack_load_identity (projection_stack);
 
-      _cogl_matrix_stack_push (ctx->modelview_stack);
-      _cogl_matrix_stack_load_identity (ctx->modelview_stack);
+      _cogl_matrix_stack_push (modelview_stack);
+      _cogl_matrix_stack_load_identity (modelview_stack);
 
       cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
 
-      _cogl_matrix_stack_pop (ctx->modelview_stack);
-      _cogl_matrix_stack_pop (ctx->projection_stack);
+      _cogl_matrix_stack_pop (modelview_stack);
+      _cogl_matrix_stack_pop (projection_stack);
     }
 
   /* make sure our rectangles hit the stencil buffer before we restore
@@ -515,19 +537,32 @@ _cogl_disable_clip_planes (void)
   GE( glDisable (GL_CLIP_PLANE0) );
 }
 
-/* XXX: This should be deprecated and Cogl should be left to manage
- * the glViewport automatically when switching draw buffers. */
 void
-cogl_viewport (guint width,
-              guint height)
+_cogl_set_viewport (int x,
+                    int y,
+                    int width,
+                    int height)
 {
+  CoglHandle draw_buffer;
+
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  COGL_NOTE (MISC, "glViewport(0, 0, %u, %u)", width, height);
-  GE( glViewport (0, 0, width, height) );
+  draw_buffer = _cogl_get_draw_buffer ();
 
-  ctx->viewport_width = width;
-  ctx->viewport_height = height;
+  _cogl_draw_buffer_set_viewport (draw_buffer,
+                                  x,
+                                  y,
+                                  width,
+                                  height);
+}
+
+/* XXX: This should be deprecated, and we should expose a way to also
+ * specify an x and y viewport offset */
+void
+cogl_viewport (guint width,
+              guint height)
+{
+  _cogl_set_viewport (0, 0, width, height);
 }
 
 void
@@ -540,6 +575,7 @@ _cogl_setup_viewport (guint width,
 {
   float z_camera;
   CoglMatrix projection_matrix;
+  CoglMatrixStack *modelview_stack;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
@@ -593,11 +629,13 @@ _cogl_setup_viewport (guint width,
   cogl_get_projection_matrix (&projection_matrix);
   z_camera = 0.5 * projection_matrix.xx;
 
-  _cogl_matrix_stack_load_identity (ctx->modelview_stack);
-  _cogl_matrix_stack_translate (ctx->modelview_stack, -0.5f, -0.5f, -z_camera);
-  _cogl_matrix_stack_scale (ctx->modelview_stack,
+  modelview_stack =
+    _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
+  _cogl_matrix_stack_load_identity (modelview_stack);
+  _cogl_matrix_stack_translate (modelview_stack, -0.5f, -0.5f, -z_camera);
+  _cogl_matrix_stack_scale (modelview_stack,
                             1.0f / width, -1.0f / height, 1.0f / width);
-  _cogl_matrix_stack_translate (ctx->modelview_stack,
+  _cogl_matrix_stack_translate (modelview_stack,
                                 0.0f, -1.0 * height, 0.0f);
 }
 
@@ -606,9 +644,6 @@ cogl_get_features (void)
 {
   _COGL_GET_CONTEXT (ctx, 0);
 
-  if (!ctx->features_cached)
-    _cogl_features_init ();
-
   if (cogl_debug_flags & COGL_DEBUG_DISABLE_VBOS)
     ctx->feature_flags &= ~COGL_FEATURE_VBOS;
 
@@ -626,18 +661,24 @@ cogl_features_available (CoglFeatureFlags features)
   return (ctx->feature_flags & features) == features;
 }
 
-/* XXX: This function should be deprecated, and replaced with a
- * cogl_draw_buffer_get_size() API instead. We don't support offset
- * viewports, and you can't have floating point viewport sizes. */
+/* XXX: This function should either be replaced with one returning
+ * integers, or removed/deprecated and make the
+ * _cogl_draw_buffer_get_viewport* functions public.
+ */
 void
 cogl_get_viewport (float v[4])
 {
+  CoglHandle draw_buffer;
+  int viewport[4];
+  int i;
+
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  v[0] = 0;
-  v[1] = 0;
-  v[2] = ctx->viewport_width;
-  v[3] = ctx->viewport_height;
+  draw_buffer = _cogl_get_draw_buffer ();
+  _cogl_draw_buffer_get_viewport4fv (draw_buffer, viewport);
+
+  for (i = 0; i < 4; i++)
+    v[i] = viewport[i];
 }
 
 void
@@ -733,7 +774,7 @@ cogl_disable_fog (void)
 void
 cogl_flush_gl_state (int flags)
 {
-  _cogl_flush_matrix_stacks ();
+  _cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0);
 }
 #endif
 
@@ -752,18 +793,20 @@ cogl_read_pixels (int x,
                   CoglPixelFormat format,
                   guint8 *pixels)
 {
-  GLint   viewport[4];
-  GLint   viewport_height;
-  int     rowstride = width * 4;
-  guint8  *temprow;
+  int        viewport_height;
+  int        rowstride = width * 4;
+  guint8    *temprow;
+  CoglHandle draw_buffer;
+
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
   g_return_if_fail (format == COGL_PIXEL_FORMAT_RGBA_8888);
   g_return_if_fail (source == COGL_READ_PIXELS_COLOR_BUFFER);
 
   temprow = g_alloca (rowstride * sizeof (guint8));
 
-  glGetIntegerv (GL_VIEWPORT, viewport);
-  viewport_height = viewport[3];
+  draw_buffer = _cogl_get_draw_buffer ();
+  viewport_height = _cogl_draw_buffer_get_viewport_height (draw_buffer);
 
   /* The y co-ordinate should be given in OpenGL's coordinate system
      so 0 is the bottom row */
@@ -825,12 +868,13 @@ cogl_begin_gl (void)
   /* Flush all batched primitives */
   cogl_flush ();
 
-  /* Flush our clipping state to GL */
-  cogl_clip_ensure ();
-
-  /* Flush any client side matrix state */
-  _cogl_flush_matrix_stacks ();
-
+  /* Flush framebuffer state, including clip state, modelview and
+   * projection matrix state
+   *
+   * NB: _cogl_draw_buffer_flush_state may disrupt various state (such
+   * as the material state) when flushing the clip stack, so should
+   * always be done first when preparing to draw. */
+  _cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0);
 
   /* Setup the state for the current material */
 
@@ -940,36 +984,41 @@ _cogl_destroy_texture_units (void)
 void
 cogl_push_matrix (void)
 {
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-  _cogl_matrix_stack_push (ctx->modelview_stack);
+  CoglMatrixStack *modelview_stack =
+    _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
+  _cogl_matrix_stack_push (modelview_stack);
 }
 
 void
 cogl_pop_matrix (void)
 {
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-  _cogl_matrix_stack_pop (ctx->modelview_stack);
+  CoglMatrixStack *modelview_stack =
+    _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
+  _cogl_matrix_stack_pop (modelview_stack);
 }
 
 void
 cogl_scale (float x, float y, float z)
 {
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-  _cogl_matrix_stack_scale (ctx->modelview_stack, x, y, z);
+  CoglMatrixStack *modelview_stack =
+    _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
+  _cogl_matrix_stack_scale (modelview_stack, x, y, z);
 }
 
 void
 cogl_translate (float x, float y, float z)
 {
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-  _cogl_matrix_stack_translate (ctx->modelview_stack, x, y, z);
+  CoglMatrixStack *modelview_stack =
+    _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
+  _cogl_matrix_stack_translate (modelview_stack, x, y, z);
 }
 
 void
 cogl_rotate (float angle, float x, float y, float z)
 {
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-  _cogl_matrix_stack_rotate (ctx->modelview_stack, angle, x, y, z);
+  CoglMatrixStack *modelview_stack =
+    _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
+  _cogl_matrix_stack_rotate (modelview_stack, angle, x, y, z);
 }
 
 void
@@ -997,12 +1046,14 @@ cogl_frustum (float        left,
              float        z_far)
 {
   float c, d;
+  CoglMatrixStack *projection_stack =
+    _cogl_draw_buffer_get_projection_stack (_cogl_get_draw_buffer ());
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  _cogl_matrix_stack_load_identity (ctx->projection_stack);
+  _cogl_matrix_stack_load_identity (projection_stack);
 
-  _cogl_matrix_stack_frustum (ctx->projection_stack,
+  _cogl_matrix_stack_frustum (projection_stack,
                               left,
                               right,
                               bottom,
@@ -1036,12 +1087,14 @@ cogl_ortho (float left,
            float z_far)
 {
   CoglMatrix ortho;
+  CoglMatrixStack *projection_stack =
+    _cogl_draw_buffer_get_projection_stack (_cogl_get_draw_buffer ());
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
   cogl_matrix_init_identity (&ortho);
   cogl_matrix_ortho (&ortho, left, right, bottom, top, z_near, z_far);
-  _cogl_matrix_stack_set (ctx->projection_stack, &ortho);
+  _cogl_matrix_stack_set (projection_stack, &ortho);
 
   /* Calculate and store the inverse of the matrix */
   memset (ctx->inverse_projection, 0, sizeof (float) * 16);
@@ -1060,41 +1113,44 @@ cogl_ortho (float left,
 void
 cogl_get_modelview_matrix (CoglMatrix *matrix)
 {
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-  _cogl_matrix_stack_get (ctx->modelview_stack, matrix);
+  CoglMatrixStack *modelview_stack =
+    _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
+  _cogl_matrix_stack_get (modelview_stack, matrix);
 }
 
 void
 cogl_set_modelview_matrix (CoglMatrix *matrix)
 {
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-  _cogl_matrix_stack_set (ctx->modelview_stack, matrix);
+  CoglMatrixStack *modelview_stack =
+    _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
+  _cogl_matrix_stack_set (modelview_stack, matrix);
 }
 
 void
 cogl_get_projection_matrix (CoglMatrix *matrix)
 {
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-  _cogl_matrix_stack_get (ctx->projection_stack, matrix);
+  CoglMatrixStack *projection_stack =
+    _cogl_draw_buffer_get_projection_stack (_cogl_get_draw_buffer ());
+  _cogl_matrix_stack_get (projection_stack, matrix);
 }
 
 void
 cogl_set_projection_matrix (CoglMatrix *matrix)
 {
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-  _cogl_matrix_stack_set (ctx->projection_stack, matrix);
+  CoglMatrixStack *projection_stack =
+    _cogl_draw_buffer_get_projection_stack (_cogl_get_draw_buffer ());
+  _cogl_matrix_stack_set (projection_stack, matrix);
 
   /* FIXME: Update the inverse projection matrix!! Presumably use
    * of clip planes must currently be broken if this API is used. */
 }
 
-void
-_cogl_flush_matrix_stacks (void)
+CoglClipStackState *
+_cogl_get_clip_state (void)
 {
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-  _cogl_matrix_stack_flush_to_gl (ctx->projection_stack,
-                                  COGL_MATRIX_PROJECTION);
-  _cogl_matrix_stack_flush_to_gl (ctx->modelview_stack,
-                                  COGL_MATRIX_MODELVIEW);
+  CoglHandle draw_buffer;
+
+  draw_buffer = _cogl_get_draw_buffer ();
+  return _cogl_draw_buffer_get_clip_state (draw_buffer);
 }
 
index 524aec7..23e417a 100644 (file)
@@ -867,6 +867,7 @@ void            cogl_flush_gl_state         (int      flags);
 
 /* private */
 void            _cogl_set_indirect_context  (gboolean indirect);
+void            _cogl_set_viewport (int x, int y, int width, int height);
 
 G_END_DECLS
 
index 81a21c9..afe9617 100644 (file)
@@ -25,8 +25,6 @@ libclutter_cogl_driver_la_SOURCES = \
        cogl.c \
        cogl-primitives.c \
        cogl-texture-driver.c \
-       cogl-fbo.h \
-       cogl-fbo.c \
        cogl-shader-private.h \
        cogl-shader.c \
        cogl-program.h \
index dcf65ef..c27721f 100644 (file)
 void
 _cogl_create_context_driver (CoglContext *_context)
 {
-  _context->drv.pf_glGenRenderbuffersEXT = NULL;
-  _context->drv.pf_glBindRenderbufferEXT = NULL;
-  _context->drv.pf_glRenderbufferStorageEXT = NULL;
-  _context->drv.pf_glGenFramebuffersEXT = NULL;
-  _context->drv.pf_glBindFramebufferEXT = NULL;
-  _context->drv.pf_glFramebufferTexture2DEXT = NULL;
-  _context->drv.pf_glFramebufferRenderbufferEXT = NULL;
-  _context->drv.pf_glCheckFramebufferStatusEXT = NULL;
-  _context->drv.pf_glDeleteFramebuffersEXT = NULL;
+  _context->drv.pf_glGenRenderbuffers = NULL;
+  _context->drv.pf_glBindRenderbuffer = NULL;
+  _context->drv.pf_glRenderbufferStorage = NULL;
+  _context->drv.pf_glGenFramebuffers = NULL;
+  _context->drv.pf_glBindFramebuffer = NULL;
+  _context->drv.pf_glFramebufferTexture2D = NULL;
+  _context->drv.pf_glFramebufferRenderbuffer = NULL;
+  _context->drv.pf_glCheckFramebufferStatus = NULL;
+  _context->drv.pf_glDeleteFramebuffers = NULL;
+
   _context->drv.pf_glBlitFramebufferEXT = NULL;
   _context->drv.pf_glRenderbufferStorageMultisampleEXT = NULL;
 
index ac5e616..ff266d6 100644 (file)
 typedef struct _CoglContextDriver
 {
   /* Relying on glext.h to define these */
-  COGL_PFNGLGENRENDERBUFFERSEXTPROC                pf_glGenRenderbuffersEXT;
-  COGL_PFNGLDELETERENDERBUFFERSEXTPROC             pf_glDeleteRenderbuffersEXT;
-  COGL_PFNGLBINDRENDERBUFFEREXTPROC                pf_glBindRenderbufferEXT;
-  COGL_PFNGLRENDERBUFFERSTORAGEEXTPROC             pf_glRenderbufferStorageEXT;
-  COGL_PFNGLGENFRAMEBUFFERSEXTPROC                 pf_glGenFramebuffersEXT;
-  COGL_PFNGLBINDFRAMEBUFFEREXTPROC                 pf_glBindFramebufferEXT;
-  COGL_PFNGLFRAMEBUFFERTEXTURE2DEXTPROC            pf_glFramebufferTexture2DEXT;
-  COGL_PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC         pf_glFramebufferRenderbufferEXT;
-  COGL_PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC          pf_glCheckFramebufferStatusEXT;
-  COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC              pf_glDeleteFramebuffersEXT;
+  COGL_PFNGLGENRENDERBUFFERSPROC                   pf_glGenRenderbuffers;
+  COGL_PFNGLDELETERENDERBUFFERSPROC                pf_glDeleteRenderbuffers;
+  COGL_PFNGLBINDRENDERBUFFERPROC                   pf_glBindRenderbuffer;
+  COGL_PFNGLRENDERBUFFERSTORAGEPROC                pf_glRenderbufferStorage;
+  COGL_PFNGLGENFRAMEBUFFERSPROC                    pf_glGenFramebuffers;
+  COGL_PFNGLBINDFRAMEBUFFERPROC                    pf_glBindFramebuffer;
+  COGL_PFNGLFRAMEBUFFERTEXTURE2DPROC               pf_glFramebufferTexture2D;
+  COGL_PFNGLFRAMEBUFFERRENDERBUFFERPROC            pf_glFramebufferRenderbuffer;
+  COGL_PFNGLCHECKFRAMEBUFFERSTATUSPROC             pf_glCheckFramebufferStatus;
+  COGL_PFNGLDELETEFRAMEBUFFERSPROC                 pf_glDeleteFramebuffers;
+  COGL_PFNGLGENERATEMIPMAPPROC                     pf_glGenerateMipmap;
+
   COGL_PFNGLBLITFRAMEBUFFEREXTPROC                 pf_glBlitFramebufferEXT;
   COGL_PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC  pf_glRenderbufferStorageMultisampleEXT;
-  COGL_PFNGLGENERATEMIPMAPEXTPROC                  pf_glGenerateMipmapEXT;
 
   COGL_PFNGLCREATEPROGRAMOBJECTARBPROC             pf_glCreateProgramObjectARB;
   COGL_PFNGLCREATESHADEROBJECTARBPROC              pf_glCreateShaderObjectARB;
index 1c79bed..9d04be9 100644 (file)
@@ -698,34 +698,34 @@ G_BEGIN_DECLS
 #endif
 
 typedef void
-  (APIENTRYP             COGL_PFNGLGENRENDERBUFFERSEXTPROC)
+  (APIENTRYP             COGL_PFNGLGENRENDERBUFFERSPROC)
   (GLsizei               n,
    GLuint               *renderbuffers);
 
 typedef void
-  (APIENTRYP             COGL_PFNGLBINDRENDERBUFFEREXTPROC)
+  (APIENTRYP             COGL_PFNGLBINDRENDERBUFFERPROC)
   (GLenum                target,
    GLuint                renderbuffer);
 
 typedef void
-  (APIENTRYP             COGL_PFNGLRENDERBUFFERSTORAGEEXTPROC)
+  (APIENTRYP             COGL_PFNGLRENDERBUFFERSTORAGEPROC)
   (GLenum                target,
    GLenum                internalformat,
    GLsizei               width,
    GLsizei               height);
 
 typedef void
-  (APIENTRYP             COGL_PFNGLGENFRAMEBUFFERSEXTPROC)
+  (APIENTRYP             COGL_PFNGLGENFRAMEBUFFERSPROC)
   (GLsizei               n,
    GLuint               *framebuffers);
 
 typedef void
-  (APIENTRYP             COGL_PFNGLBINDFRAMEBUFFEREXTPROC)
+  (APIENTRYP             COGL_PFNGLBINDFRAMEBUFFERPROC)
   (GLenum                target,
    GLuint                framebuffer);
 
 typedef void
-  (APIENTRYP             COGL_PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
+  (APIENTRYP             COGL_PFNGLFRAMEBUFFERTEXTURE2DPROC)
   (GLenum                target,
    GLenum                attachment,
    GLenum                textarget,
@@ -733,27 +733,31 @@ typedef void
    GLint                 level);
 
 typedef void
-  (APIENTRYP             COGL_PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)
+  (APIENTRYP             COGL_PFNGLFRAMEBUFFERRENDERBUFFERPROC)
   (GLenum                target,
    GLenum                attachment,
    GLenum                renderbuffertarget,
    GLuint                renderbuffer);
 
 typedef GLenum
-  (APIENTRYP             COGL_PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
+  (APIENTRYP             COGL_PFNGLCHECKFRAMEBUFFERSTATUSPROC)
   (GLenum                target);
 
 typedef void
-  (APIENTRYP             COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC)
+  (APIENTRYP             COGL_PFNGLDELETEFRAMEBUFFERSPROC)
   (GLsizei               n,
    const                 GLuint *framebuffers);
 
 typedef void
-  (APIENTRYP             COGL_PFNGLDELETERENDERBUFFERSEXTPROC)
+  (APIENTRYP             COGL_PFNGLDELETERENDERBUFFERSPROC)
   (GLsizei               n,
    const GLuint         *renderbuffers);
 
 typedef void
+  (APIENTRYP             COGL_PFNGLGENERATEMIPMAPPROC)
+  (GLenum                target);
+
+typedef void
   (APIENTRYP             COGL_PFNGLBLITFRAMEBUFFEREXTPROC)
   (GLint                 srcX0,
    GLint                 srcY0,
@@ -774,10 +778,6 @@ typedef void
    GLsizei               width,
    GLsizei               height);
 
-typedef void
-  (APIENTRYP             COGL_PFNGLGENERATEMIPMAPEXTPROC)
-  (GLenum                target);
-
 typedef GLhandleARB
   (APIENTRYP             COGL_PFNGLCREATEPROGRAMOBJECTARBPROC)
   (void);
diff --git a/clutter/cogl/cogl/driver/gl/cogl-fbo.c b/clutter/cogl/cogl/driver/gl/cogl-fbo.c
deleted file mode 100644 (file)
index 99315e6..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * Cogl
- *
- * An object oriented GL/GLES Abstraction/Utility Layer
- *
- * Copyright (C) 2007,2008,2009 Intel Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "cogl.h"
-#include "cogl-internal.h"
-#include "cogl-util.h"
-#include "cogl-texture-private.h"
-#include "cogl-fbo.h"
-#include "cogl-context.h"
-#include "cogl-handle.h"
-
-/* Expecting EXT functions not to be defined - redirect to pointers in context  */
-#define glGenRenderbuffersEXT                ctx->drv.pf_glGenRenderbuffersEXT
-#define glDeleteRenderbuffersEXT             ctx->drv.pf_glDeleteRenderbuffersEXT
-#define glBindRenderbufferEXT                ctx->drv.pf_glBindRenderbufferEXT
-#define glRenderbufferStorageEXT             ctx->drv.pf_glRenderbufferStorageEXT
-#define glGenFramebuffersEXT                 ctx->drv.pf_glGenFramebuffersEXT
-#define glBindFramebufferEXT                 ctx->drv.pf_glBindFramebufferEXT
-#define glFramebufferTexture2DEXT            ctx->drv.pf_glFramebufferTexture2DEXT
-#define glFramebufferRenderbufferEXT         ctx->drv.pf_glFramebufferRenderbufferEXT
-#define glCheckFramebufferStatusEXT          ctx->drv.pf_glCheckFramebufferStatusEXT
-#define glDeleteFramebuffersEXT              ctx->drv.pf_glDeleteFramebuffersEXT
-#define glBlitFramebufferEXT                 ctx->drv.pf_glBlitFramebufferEXT
-#define glRenderbufferStorageMultisampleEXT  ctx->drv.pf_glRenderbufferStorageMultisampleEXT
-
-#ifndef GL_READ_FRAMEBUFFER_EXT
-#define GL_READ_FRAMEBUFFER_EXT 0x8CA8
-#endif
-#ifndef GL_DRAW_FRAMEBUFFER_EXT
-#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9
-#endif
-
-static void _cogl_offscreen_free (CoglFbo *fbo);
-
-COGL_HANDLE_DEFINE (Fbo, offscreen);
-
-CoglHandle
-cogl_offscreen_new_to_texture (CoglHandle texhandle)
-{
-  CoglFbo          *fbo;
-  int               width;
-  int               height;
-  GLuint            tex_gl_handle;
-  GLenum            tex_gl_target;
-  GLuint            fbo_gl_handle;
-  GLuint            gl_stencil_handle;
-  GLenum            status;
-
-  _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
-
-  if (!cogl_features_available (COGL_FEATURE_OFFSCREEN))
-    return COGL_INVALID_HANDLE;
-
-  /* Make texhandle is a valid texture object */
-  if (!cogl_is_texture (texhandle))
-    return COGL_INVALID_HANDLE;
-
-  /* The texture must not be sliced */
-  if (cogl_texture_is_sliced (texhandle))
-    return COGL_INVALID_HANDLE;
-
-  /* Pick the single texture slice width, height and GL id */
-
-  width = cogl_texture_get_width (texhandle);
-  height = cogl_texture_get_height (texhandle);
-
-  if (!cogl_texture_get_gl_texture (texhandle, &tex_gl_handle, &tex_gl_target))
-    return COGL_INVALID_HANDLE;
-
-  if (tex_gl_target != GL_TEXTURE_2D)
-    return COGL_INVALID_HANDLE;
-
-  /* Create a renderbuffer for stenciling */
-  GE( glGenRenderbuffersEXT (1, &gl_stencil_handle) );
-  GE( glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, gl_stencil_handle) );
-  GE( glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX8_EXT,
-                               cogl_texture_get_width (texhandle),
-                               cogl_texture_get_height (texhandle)) );
-  GE( glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, 0) );
-
-  /* Generate framebuffer */
-  glGenFramebuffersEXT (1, &fbo_gl_handle);
-  GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo_gl_handle) );
-  GE( glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
-                                tex_gl_target, tex_gl_handle, 0) );
-  GE( glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT,
-                                   GL_STENCIL_ATTACHMENT_EXT,
-                                   GL_RENDERBUFFER_EXT, gl_stencil_handle) );
-
-  /* XXX: The framebuffer_object spec isn't clear in defining whether attaching
-   * a texture as a renderbuffer with mipmap filtering enabled while the
-   * mipmaps have not been uploaded should result in an incomplete framebuffer
-   * object. (different drivers make different decisions)
-   *
-   * To avoid an error with drivers that do consider this a problem we
-   * explicitly set non mipmapped filters here. These will later be reset when
-   * the texture is actually used for rendering according to the filters set on
-   * the corresponding CoglMaterial.
-   */
-  _cogl_texture_set_filters (texhandle, GL_NEAREST, GL_NEAREST);
-
-  /* Make sure it's complete */
-  status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
-
-  if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
-    {
-      /* Stencil renderbuffers aren't always supported. Try again
-        without the stencil buffer */
-      GE( glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT,
-                                       GL_STENCIL_ATTACHMENT_EXT,
-                                       GL_RENDERBUFFER_EXT,
-                                       0) );
-      GE( glDeleteRenderbuffersEXT (1, &gl_stencil_handle) );
-      gl_stencil_handle = 0;
-
-      status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT);
-
-      if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
-       {
-         /* Still failing, so give up */
-         GE( glDeleteFramebuffersEXT (1, &fbo_gl_handle) );
-         GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0) );
-         return COGL_INVALID_HANDLE;
-       }
-    }
-
-  GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0) );
-
-  /* Allocate and init a CoglFbo object (store non-wasted size
-     for subsequent blits and viewport setup) */
-  fbo = (CoglFbo*) g_malloc (sizeof (CoglFbo));
-  fbo->width             = width;
-  fbo->height            = height;
-  fbo->gl_handle         = fbo_gl_handle;
-  fbo->gl_stencil_handle = gl_stencil_handle;
-
-  return _cogl_offscreen_handle_new (fbo);
-}
-
-static void
-_cogl_offscreen_free (CoglFbo *fbo)
-{
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  /* Frees FBO resources but its handle is not
-     released! Do that separately before this! */
-  if (fbo->gl_stencil_handle)
-    GE( glDeleteRenderbuffersEXT (1, &fbo->gl_stencil_handle) );
-  GE( glDeleteFramebuffersEXT (1, &fbo->gl_handle) );
-  g_free (fbo);
-}
-
-void
-cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
-{
-  CoglFbo *fbo = NULL;
-  CoglDrawBufferState *draw_buffer;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  _cogl_journal_flush ();
-
-  g_assert (ctx->draw_buffer_stack != NULL);
-  draw_buffer = ctx->draw_buffer_stack->data;
-
-  if (target == COGL_OFFSCREEN_BUFFER)
-    {
-      /* Make sure it is a valid fbo handle */
-      if (!cogl_is_offscreen (offscreen))
-       return;
-
-      fbo = _cogl_offscreen_pointer_from_handle (offscreen);
-
-      /* Check current draw buffer target */
-      if (draw_buffer->target != COGL_OFFSCREEN_BUFFER)
-       {
-         /* Push the viewport and matrix setup if redirecting
-             from a non-screen buffer */
-         GE( glPushAttrib (GL_VIEWPORT_BIT) );
-
-          _cogl_matrix_stack_push (ctx->projection_stack);
-          _cogl_matrix_stack_load_identity (ctx->projection_stack);
-
-          _cogl_matrix_stack_push (ctx->modelview_stack);
-          _cogl_matrix_stack_load_identity (ctx->modelview_stack);
-       }
-      else
-       {
-         /* Override viewport and matrix setup if redirecting
-             from another offscreen buffer */
-          _cogl_matrix_stack_load_identity (ctx->projection_stack);
-
-          _cogl_matrix_stack_load_identity (ctx->modelview_stack);
-       }
-
-      /* Setup new viewport and matrices */
-      cogl_viewport (fbo->width, fbo->height);
-      _cogl_matrix_stack_translate (ctx->modelview_stack, -1.0f, -1.0f, 0.0f);
-      _cogl_matrix_stack_scale (ctx->modelview_stack, 2.0f / fbo->width, 2.0f / fbo->height, 1.0f);
-
-      /* Bind offscreen framebuffer object */
-      GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo->gl_handle) );
-      GE( glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) );
-    }
-  else if (target & COGL_WINDOW_BUFFER)
-    {
-      /* Check current draw buffer target */
-      if (draw_buffer->target == COGL_OFFSCREEN_BUFFER)
-       {
-         /* Pop viewport and matrices if redirecting back
-             from an offscreen buffer */
-         GE( glPopAttrib () );
-
-          _cogl_matrix_stack_pop (ctx->projection_stack);
-
-          _cogl_matrix_stack_pop (ctx->modelview_stack);
-       }
-
-      /* Bind window framebuffer object */
-      GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0) );
-    }
-
-  /* Store new target */
-  draw_buffer->target = target;
-  if (draw_buffer->offscreen != offscreen)
-    {
-      if (draw_buffer->offscreen != COGL_INVALID_HANDLE)
-        cogl_handle_unref (draw_buffer->offscreen);
-      if (offscreen != COGL_INVALID_HANDLE)
-        cogl_handle_ref (offscreen);
-      draw_buffer->offscreen = offscreen;
-    }
-}
-
-void
-cogl_push_draw_buffer(void)
-{
-  CoglDrawBufferState *old;
-  CoglDrawBufferState *draw_buffer;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  g_assert (ctx->draw_buffer_stack != NULL);
-  old = ctx->draw_buffer_stack->data;
-
-  draw_buffer = g_slice_new0 (CoglDrawBufferState);
-  *draw_buffer = *old;
-
-  ctx->draw_buffer_stack =
-    g_slist_prepend (ctx->draw_buffer_stack, draw_buffer);
-}
-
-void
-cogl_pop_draw_buffer(void)
-{
-  CoglDrawBufferState *to_pop;
-  CoglDrawBufferState *to_restore;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  g_assert (ctx->draw_buffer_stack != NULL);
-  if (ctx->draw_buffer_stack->next == NULL)
-    {
-      g_warning ("1 more cogl_pop_draw_buffer() than cogl_push_draw_buffer()");
-      return;
-    }
-
-  to_pop = ctx->draw_buffer_stack->data;
-  to_restore = ctx->draw_buffer_stack->next->data;
-
-  /* the logic in cogl_set_draw_buffer() only works if
-   * to_pop is still on top of the stack, because
-   * cogl_set_draw_buffer() needs to know the previous
-   * state.
-   */
-  cogl_set_draw_buffer (to_restore->target, to_restore->offscreen);
-
-  /* cogl_set_draw_buffer() should have set top of stack
-   * to to_restore
-   */
-  g_assert (to_restore->target == to_pop->target);
-  g_assert (to_restore->offscreen == to_pop->offscreen);
-
-  g_assert (ctx->draw_buffer_stack->data == to_pop);
-  ctx->draw_buffer_stack =
-    g_slist_remove_link (ctx->draw_buffer_stack,
-                         ctx->draw_buffer_stack);
-
-  g_slice_free (CoglDrawBufferState, to_pop);
-}
-
diff --git a/clutter/cogl/cogl/driver/gl/cogl-fbo.h b/clutter/cogl/cogl/driver/gl/cogl-fbo.h
deleted file mode 100644 (file)
index 8499f8f..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Cogl
- *
- * An object oriented GL/GLES Abstraction/Utility Layer
- *
- * Copyright (C) 2007,2008,2009 Intel Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __COGL_FBO_H
-#define __COGL_FBO_H
-
-#include "cogl-handle.h"
-
-typedef struct
-{
-  CoglHandleObject _parent;
-  int    width;
-  int    height;
-  GLuint gl_handle;
-  GLuint gl_stencil_handle;
-
-} CoglFbo;
-
-#endif /* __COGL_FBO_H */
index 3c1c9e6..d2bc193 100644 (file)
@@ -30,6 +30,8 @@
 #include "cogl-context.h"
 #include "cogl-clip-stack.h"
 #include "cogl-material-private.h"
+#include "cogl-clip-stack.h"
+#include "cogl-draw-buffer-private.h"
 
 #include <string.h>
 #include <gmodule.h>
@@ -74,7 +76,7 @@ _cogl_path_add_node (gboolean new_sub_path,
 }
 
 void
-_cogl_path_stroke_nodes ()
+_cogl_path_stroke_nodes (void)
 {
   guint   path_start = 0;
   gulong  enable_flags = COGL_ENABLE_VERTEX_ARRAY;
@@ -82,6 +84,13 @@ _cogl_path_stroke_nodes ()
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
+  _cogl_journal_flush ();
+
+  /* NB: _cogl_draw_buffer_flush_state may disrupt various state (such
+   * as the material state) when flushing the clip stack, so should
+   * always be done first when preparing to draw. */
+  _cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0);
+
   enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
   cogl_enable (enable_flags);
 
@@ -90,7 +99,6 @@ _cogl_path_stroke_nodes ()
   options.disable_layers = (guint32)~0;
 
   _cogl_material_flush_gl_state (ctx->source_material, &options);
-  _cogl_flush_matrix_stacks ();
 
   while (path_start < ctx->path_nodes->len)
     {
@@ -127,20 +135,33 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
                                   CoglPathNode *path,
                                   gboolean      merge)
 {
-  guint       path_start = 0;
-  guint       sub_path_num = 0;
-  float       bounds_x;
-  float       bounds_y;
-  float       bounds_w;
-  float       bounds_h;
-  gulong      enable_flags = COGL_ENABLE_VERTEX_ARRAY;
-  CoglHandle  prev_source;
-  int         i;
+  guint            path_start = 0;
+  guint            sub_path_num = 0;
+  float            bounds_x;
+  float            bounds_y;
+  float            bounds_w;
+  float            bounds_h;
+  gulong           enable_flags = COGL_ENABLE_VERTEX_ARRAY;
+  CoglHandle       prev_source;
+  int              i;
+  CoglHandle       draw_buffer = _cogl_get_draw_buffer ();
+  CoglMatrixStack *modelview_stack =
+    _cogl_draw_buffer_get_modelview_stack (draw_buffer);
+  CoglMatrixStack *projection_stack =
+    _cogl_draw_buffer_get_projection_stack (draw_buffer);
+
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
+  /* We don't track changes to the stencil buffer in the journal
+   * so we need to flush any batched geometry first */
   _cogl_journal_flush ();
 
+  /* NB: _cogl_draw_buffer_flush_state may disrupt various state (such
+   * as the material state) when flushing the clip stack, so should
+   * always be done first when preparing to draw. */
+  _cogl_draw_buffer_flush_state (draw_buffer, 0);
+
   /* Just setup a simple material that doesn't use texturing... */
   prev_source = cogl_handle_ref (ctx->source_material);
   cogl_set_source (ctx->stencil_material);
@@ -161,7 +182,7 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
     }
   else
     {
-      GE( glClear (GL_STENCIL_BUFFER_BIT) );
+      cogl_clear (NULL, COGL_BUFFER_BIT_STENCIL);
       GE( glStencilMask (1) );
       GE( glStencilFunc (GL_LEQUAL, 0x1, 0x3) );
     }
@@ -179,8 +200,6 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
     }
   ctx->n_texcoord_arrays_enabled = 0;
 
-  _cogl_flush_matrix_stacks ();
-
   while (path_start < path_size)
     {
       GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode),
@@ -194,8 +213,17 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
              significant bit */
           GE( glStencilMask (merge ? 6 : 3) );
           GE( glStencilOp (GL_ZERO, GL_REPLACE, GL_REPLACE) );
-          glRectf (bounds_x, bounds_y,
-                   bounds_x + bounds_w, bounds_y + bounds_h);
+          cogl_rectangle (bounds_x, bounds_y,
+                          bounds_x + bounds_w, bounds_y + bounds_h);
+          /* Make sure the rectangle hits the stencil buffer before
+           * directly changing other GL state. */
+          _cogl_journal_flush ();
+          /* NB: The journal flushing may trash the modelview state and
+           * enable flags */
+          _cogl_matrix_stack_flush_to_gl (modelview_stack,
+                                          COGL_MATRIX_MODELVIEW);
+          cogl_enable (enable_flags);
+
           GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) );
         }
 
@@ -216,19 +244,24 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
       /* Decrement all of the bits twice so that only pixels where the
          value is 3 will remain */
 
-      _cogl_matrix_stack_push (ctx->projection_stack);
-      _cogl_matrix_stack_load_identity (ctx->projection_stack);
-
-      _cogl_matrix_stack_push (ctx->modelview_stack);
-      _cogl_matrix_stack_load_identity (ctx->modelview_stack);
+      _cogl_matrix_stack_push (projection_stack);
+      _cogl_matrix_stack_load_identity (projection_stack);
+      _cogl_matrix_stack_flush_to_gl (projection_stack,
+                                      COGL_MATRIX_PROJECTION);
 
-      _cogl_flush_matrix_stacks ();
+      _cogl_matrix_stack_push (modelview_stack);
+      _cogl_matrix_stack_load_identity (modelview_stack);
+      _cogl_matrix_stack_flush_to_gl (modelview_stack,
+                                      COGL_MATRIX_MODELVIEW);
 
-      glRectf (-1.0, -1.0, 1.0, 1.0);
-      glRectf (-1.0, -1.0, 1.0, 1.0);
+      cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
+      cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
+      /* Make sure these rectangles hit the stencil buffer before we
+       * restore the stencil op/func. */
+      _cogl_journal_flush ();
 
-      _cogl_matrix_stack_pop (ctx->modelview_stack);
-      _cogl_matrix_stack_pop (ctx->projection_stack);
+      _cogl_matrix_stack_pop (modelview_stack);
+      _cogl_matrix_stack_pop (projection_stack);
     }
 
   GE( glStencilMask (~(GLuint) 0) );
@@ -244,8 +277,10 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
 }
 
 void
-_cogl_path_fill_nodes ()
+_cogl_path_fill_nodes (void)
 {
+  CoglHandle draw_buffer;
+  CoglClipStackState *clip_state;
   float bounds_x;
   float bounds_y;
   float bounds_w;
@@ -253,6 +288,11 @@ _cogl_path_fill_nodes ()
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
+  _cogl_journal_flush ();
+
+  draw_buffer = _cogl_get_draw_buffer ();
+  clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer);
+
   _cogl_path_get_bounds (ctx->path_nodes_min, ctx->path_nodes_max,
                          &bounds_x, &bounds_y, &bounds_w, &bounds_h);
 
@@ -261,12 +301,13 @@ _cogl_path_fill_nodes ()
                                     ctx->path_nodes->len,
                                     &g_array_index (ctx->path_nodes,
                                                     CoglPathNode, 0),
-                                    ctx->clip.stencil_used);
+                                    clip_state->stencil_used);
 
   cogl_rectangle (bounds_x, bounds_y,
                   bounds_x + bounds_w, bounds_y + bounds_h);
 
   /* The stencil buffer now contains garbage so the clip area needs to
      be rebuilt */
-  ctx->clip.stack_dirty = TRUE;
+  _cogl_clip_stack_state_dirty (clip_state);
 }
+
index e4c868d..742fab8 100644 (file)
@@ -45,7 +45,7 @@
 #include <stdlib.h>
 #include <math.h>
 
-#define glGenerateMipmap ctx->drv.pf_glGenerateMipmapEXT
+#define glGenerateMipmap ctx->drv.pf_glGenerateMipmap
 
 void
 _cogl_texture_driver_bind (GLenum gl_target,
index 04d3b75..e81ec37 100644 (file)
 #include "cogl-internal.h"
 #include "cogl-context.h"
 
+typedef struct _CoglGLSymbolTableEntry
+{
+  const char *name;
+  void *ptr;
+} CoglGLSymbolTableEntry;
+
 gboolean
 cogl_check_extension (const gchar *name, const gchar *ext)
 {
@@ -57,6 +63,26 @@ cogl_check_extension (const gchar *name, const gchar *ext)
   return FALSE;
 }
 
+gboolean
+_cogl_resolve_gl_symbols (CoglGLSymbolTableEntry *symbol_table,
+                          const char *suffix)
+{
+  int i;
+  gboolean status = TRUE;
+  for (i = 0; symbol_table[i].name; i++)
+    {
+      char *full_name = g_strdup_printf ("%s%s", symbol_table[i].name, suffix);
+      *((CoglFuncPtr *)symbol_table[i].ptr) = cogl_get_proc_address (full_name);
+      g_free (full_name);
+      if (!*((CoglFuncPtr *)symbol_table[i].ptr))
+        {
+          status = FALSE;
+          break;
+        }
+    }
+  return status;
+}
+
 #ifdef HAVE_CLUTTER_OSX
 static gboolean
 really_enable_npot (void)
@@ -90,6 +116,9 @@ _cogl_features_init (void)
   const gchar      *gl_extensions;
   GLint             max_clip_planes = 0;
   GLint             num_stencil_bits = 0;
+  gboolean          fbo_ARB = FALSE;
+  gboolean          fbo_EXT = FALSE;
+  const char       *suffix;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
@@ -284,64 +313,35 @@ _cogl_features_init (void)
        flags |= COGL_FEATURE_SHADERS_GLSL;
     }
 
-  if (cogl_check_extension ("GL_EXT_framebuffer_object", gl_extensions) ||
-      cogl_check_extension ("GL_ARB_framebuffer_object", gl_extensions))
+  fbo_ARB = cogl_check_extension ("GL_ARB_framebuffer_object", gl_extensions);
+  if (fbo_ARB)
+    suffix = "";
+  else
+    {
+      fbo_EXT = cogl_check_extension ("GL_EXT_framebuffer_object", gl_extensions);
+      if (fbo_EXT)
+        suffix = "EXT";
+    }
+
+  if (fbo_ARB || fbo_EXT)
     {
-      ctx->drv.pf_glGenRenderbuffersEXT =
-       (COGL_PFNGLGENRENDERBUFFERSEXTPROC)
-       cogl_get_proc_address ("glGenRenderbuffersEXT");
-
-      ctx->drv.pf_glDeleteRenderbuffersEXT =
-       (COGL_PFNGLDELETERENDERBUFFERSEXTPROC)
-       cogl_get_proc_address ("glDeleteRenderbuffersEXT");
-
-      ctx->drv.pf_glBindRenderbufferEXT =
-       (COGL_PFNGLBINDRENDERBUFFEREXTPROC)
-       cogl_get_proc_address ("glBindRenderbufferEXT");
-
-      ctx->drv.pf_glRenderbufferStorageEXT =
-       (COGL_PFNGLRENDERBUFFERSTORAGEEXTPROC)
-       cogl_get_proc_address ("glRenderbufferStorageEXT");
-
-      ctx->drv.pf_glGenFramebuffersEXT =
-       (COGL_PFNGLGENFRAMEBUFFERSEXTPROC)
-       cogl_get_proc_address ("glGenFramebuffersEXT");
-
-      ctx->drv.pf_glBindFramebufferEXT =
-       (COGL_PFNGLBINDFRAMEBUFFEREXTPROC)
-       cogl_get_proc_address ("glBindFramebufferEXT");
-
-      ctx->drv.pf_glFramebufferTexture2DEXT =
-       (COGL_PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
-       cogl_get_proc_address ("glFramebufferTexture2DEXT");
-
-      ctx->drv.pf_glFramebufferRenderbufferEXT =
-       (COGL_PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)
-       cogl_get_proc_address ("glFramebufferRenderbufferEXT");
-
-      ctx->drv.pf_glCheckFramebufferStatusEXT =
-       (COGL_PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
-       cogl_get_proc_address ("glCheckFramebufferStatusEXT");
-
-      ctx->drv.pf_glDeleteFramebuffersEXT =
-       (COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC)
-       cogl_get_proc_address ("glDeleteFramebuffersEXT");
-
-      ctx->drv.pf_glGenerateMipmapEXT =
-        (COGL_PFNGLGENERATEMIPMAPEXTPROC)
-        cogl_get_proc_address ("glGenerateMipmapEXT");
-
-      if (ctx->drv.pf_glGenRenderbuffersEXT         &&
-         ctx->drv.pf_glBindRenderbufferEXT         &&
-         ctx->drv.pf_glRenderbufferStorageEXT      &&
-         ctx->drv.pf_glGenFramebuffersEXT          &&
-         ctx->drv.pf_glBindFramebufferEXT          &&
-         ctx->drv.pf_glFramebufferTexture2DEXT     &&
-         ctx->drv.pf_glFramebufferRenderbufferEXT  &&
-         ctx->drv.pf_glCheckFramebufferStatusEXT   &&
-         ctx->drv.pf_glDeleteFramebuffersEXT       &&
-          ctx->drv.pf_glGenerateMipmapEXT)
-       flags |= COGL_FEATURE_OFFSCREEN;
+      CoglGLSymbolTableEntry symbol_table[] = {
+            {"glGenRenderbuffers", &ctx->drv.pf_glGenRenderbuffers},
+            {"glDeleteRenderbuffers", &ctx->drv.pf_glDeleteRenderbuffers},
+            {"glBindRenderbuffer", &ctx->drv.pf_glBindRenderbuffer},
+            {"glRenderbufferStorage", &ctx->drv.pf_glRenderbufferStorage},
+            {"glGenFramebuffers", &ctx->drv.pf_glGenFramebuffers},
+            {"glBindFramebuffer", &ctx->drv.pf_glBindFramebuffer},
+            {"glFramebufferTexture2D", &ctx->drv.pf_glFramebufferTexture2D},
+            {"glFramebufferRenderbuffer", &ctx->drv.pf_glFramebufferRenderbuffer},
+            {"glCheckFramebufferStatus", &ctx->drv.pf_glCheckFramebufferStatus},
+            {"glDeleteFramebuffers", &ctx->drv.pf_glDeleteFramebuffers},
+            {"glGenerateMipmap", &ctx->drv.pf_glGenerateMipmap},
+            {NULL, NULL}
+      };
+
+      if (_cogl_resolve_gl_symbols (symbol_table, suffix))
+        flags |= COGL_FEATURE_OFFSCREEN;
     }
 
   if (cogl_check_extension ("GL_EXT_framebuffer_blit", gl_extensions))
index 0a44fb4..182b29b 100644 (file)
@@ -22,11 +22,9 @@ libclutter_cogl_driver_la_CPPFLAGS = \
        $(CLUTTER_DEBUG_CFLAGS) \
        $(MAINTAINER_CFLAGS)
 libclutter_cogl_driver_la_SOURCES = \
-       cogl-fbo.h \
        cogl.c \
        cogl-primitives.c \
        cogl-texture-driver.c \
-       cogl-fbo.c \
        cogl-context-driver.c \
        cogl-context-driver.h \
        cogl-gles2-wrapper.h \
index 6660db1..ae2a064 100644 (file)
 void
 _cogl_create_context_driver (CoglContext *context)
 {
+  context->drv.pf_glGenRenderbuffers = NULL;
+  context->drv.pf_glBindRenderbuffer = NULL;
+  context->drv.pf_glRenderbufferStorage = NULL;
+  context->drv.pf_glGenFramebuffers = NULL;
+  context->drv.pf_glBindFramebuffer = NULL;
+  context->drv.pf_glFramebufferTexture2D = NULL;
+  context->drv.pf_glFramebufferRenderbuffer = NULL;
+  context->drv.pf_glCheckFramebufferStatus = NULL;
+  context->drv.pf_glDeleteFramebuffers = NULL;
+
   /* Init the GLES2 wrapper */
 #ifdef HAVE_COGL_GLES2
   cogl_gles2_wrapper_init (&context->drv.gles2);
index 9b5996e..de24eb7 100644 (file)
 #ifndef __COGL_CONTEXT_DRIVER_H
 #define __COGL_CONTEXT_DRIVER_H
 
+#include "cogl.h"
 #include "cogl-gles2-wrapper.h"
 
 typedef struct _CoglContextDriver
 
 {
+  COGL_PFNGLGENRENDERBUFFERSPROC                pf_glGenRenderbuffers;
+  COGL_PFNGLDELETERENDERBUFFERSPROC             pf_glDeleteRenderbuffers;
+  COGL_PFNGLBINDRENDERBUFFERPROC                pf_glBindRenderbuffer;
+  COGL_PFNGLRENDERBUFFERSTORAGEPROC             pf_glRenderbufferStorage;
+  COGL_PFNGLGENFRAMEBUFFERSPROC                 pf_glGenFramebuffers;
+  COGL_PFNGLBINDFRAMEBUFFERPROC                 pf_glBindFramebuffer;
+  COGL_PFNGLFRAMEBUFFERTEXTURE2DPROC            pf_glFramebufferTexture2D;
+  COGL_PFNGLFRAMEBUFFERRENDERBUFFERPROC         pf_glFramebufferRenderbuffer;
+  COGL_PFNGLCHECKFRAMEBUFFERSTATUSPROC          pf_glCheckFramebufferStatus;
+  COGL_PFNGLDELETEFRAMEBUFFERSPROC              pf_glDeleteFramebuffers;
+  COGL_PFNGLGENERATEMIPMAPPROC                  pf_glGenerateMipmap;
+
 #ifdef HAVE_COGL_GLES2
   CoglGles2Wrapper  gles2;
-
-  /* Viewport store for FBOs. Needed because glPushAttrib() isn't
-     supported */
-  GLint             viewport_store[4];
 #endif
 } CoglContextDriver;
 
index 97045df..8f0cff1 100644 (file)
@@ -633,6 +633,76 @@ G_BEGIN_DECLS
 #define CGL_SHININESS 0x1601
 #endif
 
+/* Extension function prototypes */
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+
+#ifndef APIENTRYP
+#define APIENTRYP APIENTRY *
+#endif
+
+typedef void
+  (APIENTRYP             COGL_PFNGLGENRENDERBUFFERSPROC)
+  (GLsizei               n,
+   GLuint               *renderbuffers);
+
+typedef void
+  (APIENTRYP             COGL_PFNGLBINDRENDERBUFFERPROC)
+  (GLenum                target,
+   GLuint                renderbuffer);
+
+typedef void
+  (APIENTRYP             COGL_PFNGLRENDERBUFFERSTORAGEPROC)
+  (GLenum                target,
+   GLenum                internalformat,
+   GLsizei               width,
+   GLsizei               height);
+
+typedef void
+  (APIENTRYP             COGL_PFNGLGENFRAMEBUFFERSPROC)
+  (GLsizei               n,
+   GLuint               *framebuffers);
+
+typedef void
+  (APIENTRYP             COGL_PFNGLBINDFRAMEBUFFERPROC)
+  (GLenum                target,
+   GLuint                framebuffer);
+
+typedef void
+  (APIENTRYP             COGL_PFNGLFRAMEBUFFERTEXTURE2DPROC)
+  (GLenum                target,
+   GLenum                attachment,
+   GLenum                textarget,
+   GLuint                texture,
+   GLint                 level);
+
+typedef void
+  (APIENTRYP             COGL_PFNGLFRAMEBUFFERRENDERBUFFERPROC)
+  (GLenum                target,
+   GLenum                attachment,
+   GLenum                renderbuffertarget,
+   GLuint                renderbuffer);
+
+typedef GLenum
+  (APIENTRYP             COGL_PFNGLCHECKFRAMEBUFFERSTATUSPROC)
+  (GLenum                target);
+
+typedef void
+  (APIENTRYP             COGL_PFNGLDELETEFRAMEBUFFERSPROC)
+  (GLsizei               n,
+   const                 GLuint *framebuffers);
+
+typedef void
+  (APIENTRYP             COGL_PFNGLDELETERENDERBUFFERSPROC)
+  (GLsizei               n,
+   const GLuint         *renderbuffers);
+
+typedef void
+  (APIENTRYP             COGL_PFNGLGENERATEMIPMAPPROC)
+  (GLenum                target);
+
 G_END_DECLS
 
 #endif
diff --git a/clutter/cogl/cogl/driver/gles/cogl-fbo.c b/clutter/cogl/cogl/driver/gles/cogl-fbo.c
deleted file mode 100644 (file)
index 41b5c6b..0000000
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Cogl
- *
- * An object oriented GL/GLES Abstraction/Utility Layer
- *
- * Copyright (C) 2008,2009 Intel Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "cogl.h"
-#include "cogl-internal.h"
-#include "cogl-util.h"
-#include "cogl-texture-private.h"
-#include "cogl-fbo.h"
-#include "cogl-context.h"
-#include "cogl-handle.h"
-#include "cogl-gles2-wrapper.h"
-
-#ifdef HAVE_COGL_GLES2
-
-static void _cogl_offscreen_free (CoglFbo *fbo);
-
-COGL_HANDLE_DEFINE (Fbo, offscreen);
-
-CoglHandle
-cogl_offscreen_new_to_texture (CoglHandle texhandle)
-{
-  CoglFbo          *fbo;
-  int               width;
-  int               height;
-  GLuint            tex_gl_handle;
-  GLenum            tex_gl_target;
-  GLuint            fbo_gl_handle;
-  GLuint            gl_stencil_handle;
-  GLenum            status;
-
-  _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
-
-  if (!cogl_features_available (COGL_FEATURE_OFFSCREEN))
-    return COGL_INVALID_HANDLE;
-
-  /* Make texhandle is a valid texture object */
-  if (!cogl_is_texture (texhandle))
-    return COGL_INVALID_HANDLE;
-
-  /* The texture must not be sliced */
-  if (cogl_texture_is_sliced (texhandle))
-    return COGL_INVALID_HANDLE;
-
-  /* Pick the single texture slice width, height and GL id */
-
-  width = cogl_texture_get_width (texhandle);
-  height = cogl_texture_get_height (texhandle);
-
-  if (!cogl_texture_get_gl_texture (texhandle, &tex_gl_handle, &tex_gl_target))
-    return COGL_INVALID_HANDLE;
-
-  if (tex_gl_target != GL_TEXTURE_2D)
-    return COGL_INVALID_HANDLE;
-
-  /* Create a renderbuffer for stenciling */
-  GE( glGenRenderbuffers (1, &gl_stencil_handle) );
-  GE( glBindRenderbuffer (GL_RENDERBUFFER, gl_stencil_handle) );
-  GE( glRenderbufferStorage (GL_RENDERBUFFER, GL_STENCIL_INDEX8,
-                            cogl_texture_get_width (texhandle),
-                            cogl_texture_get_height (texhandle)) );
-  GE( glBindRenderbuffer (GL_RENDERBUFFER, 0) );
-
-  /* Generate framebuffer */
-  glGenFramebuffers (1, &fbo_gl_handle);
-  GE( glBindFramebuffer (GL_FRAMEBUFFER, fbo_gl_handle) );
-  GE( glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                             tex_gl_target, tex_gl_handle, 0) );
-  GE( glFramebufferRenderbuffer (GL_FRAMEBUFFER,
-                                GL_STENCIL_ATTACHMENT,
-                                GL_RENDERBUFFER, gl_stencil_handle) );
-
-  /* Make sure it's complete */
-  status = glCheckFramebufferStatus (GL_FRAMEBUFFER);
-
-  if (status != GL_FRAMEBUFFER_COMPLETE)
-    {
-      /* Stencil renderbuffers aren't always supported. Try again
-        without the stencil buffer */
-      GE( glFramebufferRenderbuffer (GL_FRAMEBUFFER,
-                                    GL_STENCIL_ATTACHMENT,
-                                    GL_RENDERBUFFER,
-                                    0) );
-      GE( glDeleteRenderbuffers (1, &gl_stencil_handle) );
-      gl_stencil_handle = 0;
-
-      status = glCheckFramebufferStatus (GL_FRAMEBUFFER);
-
-      if (status != GL_FRAMEBUFFER_COMPLETE)
-       {
-         /* Still failing, so give up */
-         GE( glDeleteFramebuffers (1, &fbo_gl_handle) );
-         GE( glBindFramebuffer (GL_FRAMEBUFFER, 0) );
-         return COGL_INVALID_HANDLE;
-       }
-    }
-
-  GE( glBindFramebuffer (GL_FRAMEBUFFER, 0) );
-
-  /* Allocate and init a CoglFbo object (store non-wasted size
-     for subsequent blits and viewport setup) */
-  fbo = (CoglFbo*) g_malloc (sizeof (CoglFbo));
-  fbo->width             = width;
-  fbo->height            = height;
-  fbo->gl_handle         = fbo_gl_handle;
-  fbo->gl_stencil_handle = gl_stencil_handle;
-
-  return _cogl_offscreen_handle_new (fbo);
-}
-
-static void
-_cogl_offscreen_free (CoglFbo *fbo)
-{
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  /* Frees FBO resources but its handle is not
-     released! Do that separately before this! */
-  if (fbo->gl_stencil_handle)
-    GE( glDeleteRenderbuffers (1, &fbo->gl_stencil_handle) );
-  GE( glDeleteFramebuffers (1, &fbo->gl_handle) );
-  g_free (fbo);
-}
-
-void
-cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
-{
-  CoglFbo *fbo = NULL;
-  CoglDrawBufferState *draw_buffer;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  _cogl_journal_flush ();
-
-  g_assert (ctx->draw_buffer_stack != NULL);
-  draw_buffer = ctx->draw_buffer_stack->data;
-
-  if (target == COGL_OFFSCREEN_BUFFER)
-    {
-      /* Make sure it is a valid fbo handle */
-      if (!cogl_is_offscreen (offscreen))
-       return;
-
-      fbo = _cogl_offscreen_pointer_from_handle (offscreen);
-
-      /* Check current draw buffer target */
-      if (draw_buffer->target != COGL_OFFSCREEN_BUFFER)
-       {
-         /* Push the viewport and matrix setup if redirecting
-             from a non-screen buffer */
-         GE( glGetIntegerv (GL_VIEWPORT, ctx->drv.viewport_store) );
-
-          _cogl_matrix_stack_push (ctx->projection_stack);
-          _cogl_matrix_stack_load_identity (ctx->projection_stack);
-
-          _cogl_matrix_stack_push (ctx->modelview_stack);
-          _cogl_matrix_stack_load_identity (ctx->modelview_stack);
-       }
-      else
-       {
-         /* Override viewport and matrix setup if redirecting
-             from another offscreen buffer */
-          _cogl_matrix_stack_load_identity (ctx->projection_stack);
-
-          _cogl_matrix_stack_load_identity (ctx->modelview_stack);
-       }
-
-      /* Setup new viewport and matrices */
-<<<<<<< HEAD:clutter/cogl/cogl/driver/gles/cogl-fbo.c
-      GE( glViewport (0, 0, fbo->width, fbo->height) );
-      _cogl_matrix_stack_translate (ctx->modelview_stack, -1.0f, -1.0f, 0.0f);
-      _cogl_matrix_stack_scale (ctx->modelview_stack,
-                                2.0f / fbo->width, 2.0f / fbo->height, 1.0f);
-=======
-      cogl_viewport (fbo->width, fbo->height);
-      _cogl_current_matrix_translate (-1.0f, -1.0f, 0.0f);
-      _cogl_current_matrix_scale (2.0f / fbo->width, 2.0f / fbo->height, 1.0f);
->>>>>>> c3e471c... [cogl-fbo] Bring the gles code more in line with gl code:clutter/cogl/cogl/driver/gles/cogl-fbo.c
-
-      /* Bind offscreen framebuffer object */
-      GE( glBindFramebuffer (GL_FRAMEBUFFER, fbo->gl_handle) );
-      GE( glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) );
-    }
-  else if (target & COGL_WINDOW_BUFFER)
-    {
-      /* Check current draw buffer target */
-      if (draw_buffer->target == COGL_OFFSCREEN_BUFFER)
-       {
-         /* Pop viewport and matrices if redirecting back
-             from an offscreen buffer */
-         GE( glViewport (ctx->drv.viewport_store[0],
-                          ctx->drv.viewport_store[1],
-                         ctx->drv.viewport_store[2],
-                          ctx->drv.viewport_store[3]) );
-
-          _cogl_matrix_stack_pop (ctx->projection_stack);
-
-          _cogl_matrix_stack_pop (ctx->modelview_stack);
-       }
-
-      /* Bind window framebuffer object */
-      GE( glBindFramebuffer (GL_FRAMEBUFFER, 0) );
-    }
-
-  /* Store new target */
-  draw_buffer->target = target;
-  if (draw_buffer->offscreen != offscreen)
-    {
-      if (draw_buffer->offscreen != COGL_INVALID_HANDLE)
-        cogl_handle_unref (draw_buffer->offscreen);
-      if (offscreen != COGL_INVALID_HANDLE)
-        cogl_handle_ref (offscreen);
-      draw_buffer->offscreen = offscreen;
-    }
-}
-
-void
-cogl_push_draw_buffer(void)
-{
-  CoglDrawBufferState *old;
-  CoglDrawBufferState *draw_buffer;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  g_assert (ctx->draw_buffer_stack != NULL);
-  old = ctx->draw_buffer_stack->data;
-
-  draw_buffer = g_slice_new0 (CoglDrawBufferState);
-  *draw_buffer = *old;
-
-  ctx->draw_buffer_stack =
-    g_slist_prepend (ctx->draw_buffer_stack, draw_buffer);
-}
-
-void
-cogl_pop_draw_buffer(void)
-{
-  CoglDrawBufferState *to_pop;
-  CoglDrawBufferState *to_restore;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  g_assert (ctx->draw_buffer_stack != NULL);
-  if (ctx->draw_buffer_stack->next == NULL)
-    {
-      g_warning ("1 more cogl_pop_draw_buffer() than cogl_push_draw_buffer()");
-      return;
-    }
-
-  to_pop = ctx->draw_buffer_stack->data;
-  to_restore = ctx->draw_buffer_stack->next->data;
-
-  /* the logic in cogl_set_draw_buffer() only works if
-   * to_pop is still on top of the stack, because
-   * cogl_set_draw_buffer() needs to know the previous
-   * state.
-   */
-  cogl_set_draw_buffer (to_restore->target, to_restore->offscreen);
-
-  /* cogl_set_draw_buffer() should have set top of stack
-   * to to_restore
-   */
-  g_assert (to_restore->target == to_pop->target);
-  g_assert (to_restore->offscreen == to_pop->offscreen);
-
-  g_assert (ctx->draw_buffer_stack->data == to_pop);
-  ctx->draw_buffer_stack =
-    g_slist_remove_link (ctx->draw_buffer_stack,
-                         ctx->draw_buffer_stack);
-
-  g_slice_free (CoglDrawBufferState, to_pop);
-}
-
-#else /* HAVE_COGL_GLES2 */
-
-/* No support on regular OpenGL 1.1 */
-
-gboolean
-cogl_is_offscreen (CoglHandle handle)
-{
-  return FALSE;
-}
-
-CoglHandle
-cogl_offscreen_new_to_texture (CoglHandle texhandle)
-{
-  return COGL_INVALID_HANDLE;
-}
-
-CoglHandle
-cogl_offscreen_ref (CoglHandle handle)
-{
-  return COGL_INVALID_HANDLE;
-}
-
-void
-cogl_offscreen_unref (CoglHandle handle)
-{
-}
-
-void
-cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
-{
-}
-
-#endif /* HAVE_COGL_GLES2 */
diff --git a/clutter/cogl/cogl/driver/gles/cogl-fbo.h b/clutter/cogl/cogl/driver/gles/cogl-fbo.h
deleted file mode 100644 (file)
index 8499f8f..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Cogl
- *
- * An object oriented GL/GLES Abstraction/Utility Layer
- *
- * Copyright (C) 2007,2008,2009 Intel Corporation.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __COGL_FBO_H
-#define __COGL_FBO_H
-
-#include "cogl-handle.h"
-
-typedef struct
-{
-  CoglHandleObject _parent;
-  int    width;
-  int    height;
-  GLuint gl_handle;
-  GLuint gl_stencil_handle;
-
-} CoglFbo;
-
-#endif /* __COGL_FBO_H */
index f31bd21..09d637e 100644 (file)
@@ -30,6 +30,9 @@
 #include "cogl-context.h"
 #include "cogl-clip-stack.h"
 #include "cogl-material-private.h"
+#include "cogl-clip-stack.h"
+#include "cogl-draw-buffer-private.h"
+#include "cogl-clip-stack.h"
 
 #include <string.h>
 #include <gmodule.h>
@@ -72,7 +75,7 @@ _cogl_path_add_node (gboolean new_sub_path,
 }
 
 void
-_cogl_path_stroke_nodes ()
+_cogl_path_stroke_nodes (void)
 {
   guint   path_start = 0;
   gulong  enable_flags = COGL_ENABLE_VERTEX_ARRAY;
@@ -80,13 +83,21 @@ _cogl_path_stroke_nodes ()
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
+  _cogl_journal_flush ();
+
+  /* NB: _cogl_draw_buffer_flush_state may disrupt various state (such
+   * as the material state) when flushing the clip stack, so should
+   * always be done first when preparing to draw. */
+  _cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0);
+
   enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
   cogl_enable (enable_flags);
 
   options.flags = COGL_MATERIAL_FLUSH_DISABLE_MASK;
+  /* disable all texture layers */
   options.disable_layers = (guint32)~0;
-  _cogl_material_flush_gl_state (ctx->source_material,&options);
-  _cogl_flush_matrix_stacks();
+
+  _cogl_material_flush_gl_state (ctx->source_material, &options);
 
   while (path_start < ctx->path_nodes->len)
     {
@@ -129,18 +140,38 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
                                   CoglPathNode *path,
                                   gboolean      merge)
 {
-  guint   path_start = 0;
-  guint   sub_path_num = 0;
-  float   bounds_x;
-  float   bounds_y;
-  float   bounds_w;
-  float   bounds_h;
-  gulong  enable_flags = COGL_ENABLE_VERTEX_ARRAY;
+  guint            path_start = 0;
+  guint            sub_path_num = 0;
+  float            bounds_x;
+  float            bounds_y;
+  float            bounds_w;
+  float            bounds_h;
+  gulong           enable_flags = COGL_ENABLE_VERTEX_ARRAY;
+  CoglHandle       prev_source;
+  int              i;
+  CoglHandle       draw_buffer = _cogl_get_draw_buffer ();
+  CoglMatrixStack *modelview_stack =
+    _cogl_draw_buffer_get_modelview_stack (draw_buffer);
+  CoglMatrixStack *projection_stack =
+    _cogl_draw_buffer_get_projection_stack (draw_buffer);
+
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
+  /* We don't track changes to the stencil buffer in the journal
+   * so we need to flush any batched geometry first */
+  _cogl_journal_flush ();
+
+  /* NB: _cogl_draw_buffer_flush_state may disrupt various state (such
+   * as the material state) when flushing the clip stack, so should
+   * always be done first when preparing to draw. */
+  _cogl_draw_buffer_flush_state (draw_buffer, 0);
+
   /* Just setup a simple material that doesn't use texturing... */
-  _cogl_material_flush_gl_state (ctx->stencil_material, NULL);
+  prev_source = cogl_handle_ref (ctx->source_material);
+  cogl_set_source (ctx->stencil_material);
+
+  _cogl_material_flush_gl_state (ctx->source_material, NULL);
 
   enable_flags |=
     _cogl_material_get_cogl_enable_flags (ctx->source_material);
@@ -156,7 +187,7 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
     }
   else
     {
-      GE( glClear (GL_STENCIL_BUFFER_BIT) );
+      cogl_clear (NULL, COGL_BUFFER_BIT_STENCIL);
       GE( glStencilMask (1) );
       GE( glStencilFunc (GL_LEQUAL, 0x1, 0x3) );
     }
@@ -167,7 +198,13 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
   GE( glColorMask (FALSE, FALSE, FALSE, FALSE) );
   GE( glDepthMask (FALSE) );
 
-  _cogl_matrix_stack_flush_to_gl (ctx->modelview_stack, COGL_MATRIX_MODELVIEW);
+  for (i = 0; i < ctx->n_texcoord_arrays_enabled; i++)
+    {
+      GE (glClientActiveTexture (GL_TEXTURE0 + i));
+      GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY));
+    }
+  ctx->n_texcoord_arrays_enabled = 0;
+
   while (path_start < path_size)
     {
       GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode),
@@ -183,6 +220,14 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
           GE( glStencilOp (GL_ZERO, GL_REPLACE, GL_REPLACE) );
           cogl_rectangle (bounds_x, bounds_y,
                           bounds_x + bounds_w, bounds_y + bounds_h);
+          /* Make sure the rectangle hits the stencil buffer before
+           * directly changing other GL state. */
+          _cogl_journal_flush ();
+          /* NB: The journal flushing may trash the modelview state and
+           * enable flags */
+          _cogl_matrix_stack_flush_to_gl (modelview_stack,
+                                          COGL_MATRIX_MODELVIEW);
+          cogl_enable (enable_flags);
 
           GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) );
         }
@@ -204,17 +249,24 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
       /* Decrement all of the bits twice so that only pixels where the
          value is 3 will remain */
 
-      _cogl_matrix_stack_push (ctx->projection_stack);
-      _cogl_matrix_stack_load_identity (ctx->projection_stack);
+      _cogl_matrix_stack_push (projection_stack);
+      _cogl_matrix_stack_load_identity (projection_stack);
+      _cogl_matrix_stack_flush_to_gl (projection_stack,
+                                      COGL_MATRIX_PROJECTION);
 
-      _cogl_matrix_stack_push (ctx->modelview_stack);
-      _cogl_matrix_stack_load_identity (ctx->modelview_stack);
+      _cogl_matrix_stack_push (modelview_stack);
+      _cogl_matrix_stack_load_identity (modelview_stack);
+      _cogl_matrix_stack_flush_to_gl (modelview_stack,
+                                      COGL_MATRIX_MODELVIEW);
 
       cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
       cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
+      /* Make sure these rectangles hit the stencil buffer before we
+       * restore the stencil op/func. */
+      _cogl_journal_flush ();
 
-      _cogl_matrix_stack_pop (ctx->modelview_stack);
-      _cogl_matrix_stack_pop (ctx->projection_stack);
+      _cogl_matrix_stack_pop (modelview_stack);
+      _cogl_matrix_stack_pop (projection_stack);
     }
 
   GE( glStencilMask (~(GLuint) 0) );
@@ -250,6 +302,21 @@ _cogl_path_fill_nodes_scanlines (CoglPathNode *path,
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
+  /* We are going to use GL to draw directly so make sure any
+   * previously batched geometry gets to GL before we start...
+   */
+  _cogl_journal_flush ();
+
+  /* NB: _cogl_draw_buffer_flush_state may disrupt various state (such
+   * as the material state) when flushing the clip stack, so should
+   * always be done first when preparing to draw. */
+  _cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0);
+
+  _cogl_material_flush_gl_state (ctx->source_material, NULL);
+
+  cogl_enable (COGL_ENABLE_VERTEX_ARRAY
+               | (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0));
+
   /* clear scanline intersection lists */
   for (i=0; i < bounds_h; i++)
     scanlines[i]=NULL;
@@ -386,8 +453,6 @@ _cogl_path_fill_nodes_scanlines (CoglPathNode *path,
       }
 
     /* render triangles */
-    cogl_enable (COGL_ENABLE_VERTEX_ARRAY
-                 | (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0));
     GE ( glVertexPointer (2, GL_FLOAT, 0, coords ) );
     GE ( glDrawArrays (GL_TRIANGLES, 0, spans * 2 * 3));
     g_free (coords);
@@ -395,7 +460,7 @@ _cogl_path_fill_nodes_scanlines (CoglPathNode *path,
 }
 
 void
-_cogl_path_fill_nodes ()
+_cogl_path_fill_nodes (void)
 {
   float bounds_x;
   float bounds_y;
@@ -409,19 +474,27 @@ _cogl_path_fill_nodes ()
 
   if (cogl_features_available (COGL_FEATURE_STENCIL_BUFFER))
     {
+      CoglHandle draw_buffer;
+      CoglClipStackState *clip_state;
+
+      _cogl_journal_flush ();
+
+      draw_buffer = _cogl_get_draw_buffer ();
+      clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer);
+
       _cogl_add_path_to_stencil_buffer (ctx->path_nodes_min,
                                         ctx->path_nodes_max,
                                         ctx->path_nodes->len,
                                         &g_array_index (ctx->path_nodes,
                                                         CoglPathNode, 0),
-                                        ctx->clip.stencil_used);
+                                        clip_state->stencil_used);
 
       cogl_rectangle (bounds_x, bounds_y,
                       bounds_x + bounds_w, bounds_y + bounds_h);
 
       /* The stencil buffer now contains garbage so the clip area needs to
          be rebuilt */
-      ctx->clip.stack_dirty = TRUE;
+      _cogl_clip_stack_state_dirty (clip_state);
     }
   else
     {
index aa7da6e..565ff0f 100644 (file)
 #include "cogl-internal.h"
 #include "cogl-context.h"
 
+typedef struct _CoglGLSymbolTableEntry
+{
+  const char *name;
+  void *ptr;
+} CoglGLSymbolTableEntry;
+
+gboolean
+cogl_check_extension (const gchar *name, const gchar *ext)
+{
+  gchar *end;
+  gint name_len, n;
+
+  if (name == NULL || ext == NULL)
+    return FALSE;
+
+  end = (gchar*)(ext + strlen(ext));
+
+  name_len = strlen(name);
+
+  while (ext < end)
+    {
+      n = strcspn(ext, " ");
+
+      if ((name_len == n) && (!strncmp(name, ext, n)))
+       return TRUE;
+      ext += (n + 1);
+    }
+
+  return FALSE;
+}
+
+gboolean
+_cogl_resolve_gl_symbols (CoglGLSymbolTableEntry *symbol_table,
+                          const char *suffix)
+{
+  int i;
+  gboolean status = TRUE;
+  for (i = 0; symbol_table[i].name; i++)
+    {
+      char *full_name = g_strdup_printf ("%s%s", symbol_table[i].name, suffix);
+      *((CoglFuncPtr *)symbol_table[i].ptr) = cogl_get_proc_address (full_name);
+      g_free (full_name);
+      if (!*((CoglFuncPtr *)symbol_table[i].ptr))
+        {
+          status = FALSE;
+          break;
+        }
+    }
+  return status;
+}
 
 
 void
@@ -39,9 +89,34 @@ _cogl_features_init (void)
   CoglFeatureFlags flags = 0;
   int              max_clip_planes = 0;
   GLint            num_stencil_bits = 0;
+  const char      *gl_extensions;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
+  gl_extensions = (const char*) glGetString (GL_EXTENSIONS);
+
+  if (cogl_check_extension ("GL_OES_framebuffer_object", gl_extensions))
+    {
+      g_assert (0);
+      CoglGLSymbolTableEntry symbol_table[] = {
+            {"glGenRenderbuffers", &ctx->drv.pf_glGenRenderbuffers},
+            {"glDeleteRenderbuffers", &ctx->drv.pf_glDeleteRenderbuffers},
+            {"glBindRenderbuffer", &ctx->drv.pf_glBindRenderbuffer},
+            {"glRenderbufferStorage", &ctx->drv.pf_glRenderbufferStorage},
+            {"glGenFramebuffers", &ctx->drv.pf_glGenFramebuffers},
+            {"glBindFramebuffer", &ctx->drv.pf_glBindFramebuffer},
+            {"glFramebufferTexture2D", &ctx->drv.pf_glFramebufferTexture2D},
+            {"glFramebufferRenderbuffer", &ctx->drv.pf_glFramebufferRenderbuffer},
+            {"glCheckFramebufferStatus", &ctx->drv.pf_glCheckFramebufferStatus},
+            {"glDeleteFramebuffers", &ctx->drv.pf_glDeleteFramebuffers},
+            {"glGenerateMipmap", &ctx->drv.pf_glGenerateMipmap},
+            {NULL, NULL}
+      };
+
+      if (_cogl_resolve_gl_symbols (symbol_table, "OES"))
+        flags |= COGL_FEATURE_OFFSCREEN;
+    }
+
   GE( glGetIntegerv (GL_STENCIL_BITS, &num_stencil_bits) );
   /* We need at least three stencil bits to combine clips */
   if (num_stencil_bits > 2)