[cogl] framebuffer: Add cogl_framebuffer draw methods



commit 92c306301492a619037a8d13c8da8e4c5c1ebf94
Author: Robert Bragg <robert linux intel com>
Date:   Sun Jan 8 02:59:04 2012 +0000

    framebuffer: Add cogl_framebuffer draw methods
    
    This adds cogl_framebuffer_ apis for drawing attributes and primitives
    that replace corresponding apis that depend on the default CoglContext.
    This is part of the on going effort to adapt the Cogl api so it no
    longer depends on a global context variable.
    
    All the new drawing functions also take an explicit pipeline argument
    since we are also aiming to avoid being a stateful api like Cairo and
    OpenGL. Being stateless makes it easier for orthogonal components to
    share access to the GPU. Being stateless should also minimize any
    impedance miss-match for those wanting to build higher level stateless
    apis on top of Cogl.
    
    Note: none of the legacy, global state options such as
    cogl_set_depth_test_enabled(), cogl_set_backface_culling_enabled() or
    cogl_program_use() are supported by these new drawing apis and if set
    will simply be silently ignored.
    
    Reviewed-by: Neil Roberts <neil linux intel com>

 cogl-pango/cogl-pango-display-list.c               |    4 +-
 cogl/cogl-attribute-private.h                      |   25 +-
 cogl/cogl-attribute.c                              |  512 ++------------------
 cogl/cogl-attribute.h                              |   28 --
 cogl/cogl-clip-stack.c                             |   45 +-
 cogl/cogl-framebuffer-private.h                    |   31 ++
 cogl/cogl-framebuffer.c                            |  487 +++++++++++++++++++
 cogl/cogl-framebuffer.h                            |  210 ++++++++
 cogl/cogl-journal.c                                |   62 ++--
 cogl/cogl-primitive.c                              |   28 --
 cogl/cogl-primitive.h                              |   12 -
 cogl/cogl-primitives-private.h                     |    4 +-
 cogl/cogl-primitives.c                             |   41 ++-
 cogl/cogl-vertex-buffer.c                          |   11 +-
 cogl/cogl2-path.c                                  |   29 +-
 .../cogl-2.0-experimental-docs.xml.in              |    5 -
 .../cogl-2.0-experimental-sections.txt             |   17 +-
 examples/cogl-crate.c                              |   12 +-
 examples/cogl-hello.c                              |    8 +-
 examples/cogl-msaa.c                               |    7 +-
 examples/cogl-sdl-hello.c                          |    8 +-
 examples/cogl-x11-foreign.c                        |    5 +-
 examples/cogland.c                                 |    5 +-
 tests/conform/test-custom-attributes.c             |   78 ++--
 tests/conform/test-primitive.c                     |    8 +-
 25 files changed, 958 insertions(+), 724 deletions(-)
---
diff --git a/cogl-pango/cogl-pango-display-list.c b/cogl-pango/cogl-pango-display-list.c
index 9cc0166..005b478 100644
--- a/cogl-pango/cogl-pango-display-list.c
+++ b/cogl-pango/cogl-pango-display-list.c
@@ -364,7 +364,9 @@ emit_vertex_buffer_geometry (CoglPangoDisplayListNode *node)
       cogl_object_unref (attributes[1]);
     }
 
-  cogl_primitive_draw (node->d.texture.primitive);
+  cogl_framebuffer_draw_primitive (cogl_get_draw_framebuffer (),
+                                   cogl_get_source (),
+                                   node->d.texture.primitive);
 }
 
 static void
diff --git a/cogl/cogl-attribute-private.h b/cogl/cogl-attribute-private.h
index 68ed52d..d977376 100644
--- a/cogl/cogl-attribute-private.h
+++ b/cogl/cogl-attribute-private.h
@@ -69,13 +69,14 @@ typedef enum
   COGL_DRAW_SKIP_JOURNAL_FLUSH = 1 << 0,
   COGL_DRAW_SKIP_PIPELINE_VALIDATION = 1 << 1,
   COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH = 1 << 2,
+  COGL_DRAW_SKIP_LEGACY_STATE = 1 << 3,
   /* By default the vertex attribute drawing code will assume that if
      there is a color attribute array enabled then we can't determine
      if the colors will be opaque so we need to enabling
      blending. However when drawing from the journal we know what the
      contents of the color array is so we can override this by passing
      this flag. */
-  COGL_DRAW_COLOR_ATTRIBUTE_IS_OPAQUE = 1 << 3
+  COGL_DRAW_COLOR_ATTRIBUTE_IS_OPAQUE = 1 << 4
 } CoglDrawFlags;
 
 /* During CoglContext initialization we register the "cogl_color_in"
@@ -95,24 +96,14 @@ void
 _cogl_attribute_immutable_unref (CoglAttribute *attribute);
 
 void
-_cogl_draw_attributes (CoglVerticesMode mode,
-                       int first_vertex,
-                       int n_vertices,
-                       CoglAttribute **attributes,
-                       int n_attributes,
-                       CoglDrawFlags flags);
-
-void
-_cogl_draw_indexed_attributes (CoglVerticesMode mode,
-                               int first_vertex,
-                               int n_vertices,
-                               CoglIndices *indices,
-                               CoglAttribute **attributes,
-                               int n_attributes,
-                               CoglDrawFlags flags);
+_cogl_attribute_disable_cached_arrays (void);
 
 void
-_cogl_attribute_disable_cached_arrays (void);
+_cogl_flush_attributes_state (CoglFramebuffer *framebuffer,
+                              CoglPipeline *pipeline,
+                              CoglDrawFlags flags,
+                              CoglAttribute **attributes,
+                              int n_attributes);
 
 #endif /* __COGL_ATTRIBUTE_PRIVATE_H */
 
diff --git a/cogl/cogl-attribute.c b/cogl/cogl-attribute.c
index e8654df..ddc3596 100644
--- a/cogl/cogl-attribute.c
+++ b/cogl/cogl-attribute.c
@@ -538,32 +538,31 @@ apply_attribute_enable_updates (CoglContext *context,
                                 &changed_bits_state);
 }
 
-static CoglPipeline *
-flush_state (CoglDrawFlags flags,
-             CoglAttribute **attributes,
-             int n_attributes,
-             ValidateLayerState *state)
+void
+_cogl_flush_attributes_state (CoglFramebuffer *framebuffer,
+                              CoglPipeline *pipeline,
+                              CoglDrawFlags flags,
+                              CoglAttribute **attributes,
+                              int n_attributes)
 {
-  CoglFramebuffer *framebuffer = cogl_get_draw_framebuffer ();
   int i;
   gboolean skip_gl_color = FALSE;
-  CoglPipeline *source = cogl_get_source ();
   CoglPipeline *copy = NULL;
   int n_tex_coord_attribs = 0;
-
-  _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
+  ValidateLayerState layers_state;
+  CoglContext *ctx = framebuffer->context;
 
   if (!(flags & COGL_DRAW_SKIP_JOURNAL_FLUSH))
     _cogl_journal_flush (framebuffer->journal, framebuffer);
 
-  state->unit = 0;
-  state->options.flags = 0;
-  state->fallback_layers = 0;
+  layers_state.unit = 0;
+  layers_state.options.flags = 0;
+  layers_state.fallback_layers = 0;
 
   if (!(flags & COGL_DRAW_SKIP_PIPELINE_VALIDATION))
-    cogl_pipeline_foreach_layer (cogl_get_source (),
+    cogl_pipeline_foreach_layer (pipeline,
                                  validate_layer_cb,
-                                 state);
+                                 &layers_state);
 
   /* NB: _cogl_framebuffer_flush_state may disrupt various state (such
    * as the pipeline state) when flushing the clip stack, so should
@@ -572,8 +571,8 @@ flush_state (CoglDrawFlags flags,
    * stack can cause some drawing which would change the array
    * pointers. */
   if (!(flags & COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH))
-    _cogl_framebuffer_flush_state (cogl_get_draw_framebuffer (),
-                                   _cogl_get_read_framebuffer (),
+    _cogl_framebuffer_flush_state (framebuffer,
+                                   framebuffer,
                                    COGL_FRAMEBUFFER_STATE_ALL);
 
   /* In cogl_read_pixels we have a fast-path when reading a single
@@ -590,13 +589,13 @@ flush_state (CoglDrawFlags flags,
       {
       case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
         if ((flags & COGL_DRAW_COLOR_ATTRIBUTE_IS_OPAQUE) == 0 &&
-            !_cogl_pipeline_get_real_blend_enabled (source))
+            !_cogl_pipeline_get_real_blend_enabled (pipeline))
           {
             CoglPipelineBlendEnable blend_enable =
               COGL_PIPELINE_BLEND_ENABLE_ENABLED;
-            copy = cogl_pipeline_copy (source);
+            copy = cogl_pipeline_copy (pipeline);
             _cogl_pipeline_set_blend_enabled (copy, blend_enable);
-            source = copy;
+            pipeline = copy;
           }
         skip_gl_color = TRUE;
         break;
@@ -609,15 +608,15 @@ flush_state (CoglDrawFlags flags,
         break;
       }
 
-  if (G_UNLIKELY (state->options.flags))
+  if (G_UNLIKELY (layers_state.options.flags))
     {
       /* If we haven't already created a derived pipeline... */
       if (!copy)
         {
-          copy = cogl_pipeline_copy (source);
-          source = copy;
+          copy = cogl_pipeline_copy (pipeline);
+          pipeline = copy;
         }
-      _cogl_pipeline_apply_overrides (source, &state->options);
+      _cogl_pipeline_apply_overrides (pipeline, &layers_state.options);
 
       /* TODO:
        * overrides = cogl_pipeline_get_data (pipeline,
@@ -640,7 +639,7 @@ flush_state (CoglDrawFlags flags,
        *   {
        *     overrides = g_slice_new (Overrides);
        *     overrides->weak_pipeline =
-       *       cogl_pipeline_weak_copy (cogl_get_source ());
+       *       cogl_pipeline_weak_copy (pipeline);
        *     _cogl_pipeline_apply_overrides (overrides->weak_pipeline,
        *                                     &options);
        *
@@ -649,23 +648,24 @@ flush_state (CoglDrawFlags flags,
        *                             free_overrides_cb,
        *                             NULL);
        *   }
-       * source = overrides->weak_pipeline;
+       * pipeline = overrides->weak_pipeline;
        */
     }
 
-  if (G_UNLIKELY (ctx->legacy_state_set) &&
+  if (G_UNLIKELY (!(flags & COGL_DRAW_SKIP_LEGACY_STATE)) &&
+      G_UNLIKELY (ctx->legacy_state_set) &&
       _cogl_get_enable_legacy_state ())
     {
       /* If we haven't already created a derived pipeline... */
       if (!copy)
         {
-          copy = cogl_pipeline_copy (source);
-          source = copy;
+          copy = cogl_pipeline_copy (pipeline);
+          pipeline = copy;
         }
-      _cogl_pipeline_apply_legacy_state (source);
+      _cogl_pipeline_apply_legacy_state (pipeline);
     }
 
-  _cogl_pipeline_flush_gl_state (source, skip_gl_color, n_tex_coord_attribs);
+  _cogl_pipeline_flush_gl_state (pipeline, skip_gl_color, n_tex_coord_attribs);
 
   _cogl_bitmask_clear_all (&ctx->enable_builtin_attributes_tmp);
   _cogl_bitmask_clear_all (&ctx->enable_texcoord_attributes_tmp);
@@ -691,7 +691,7 @@ flush_state (CoglDrawFlags flags,
         case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
 #ifdef HAVE_COGL_GLES2
           if (ctx->driver == COGL_DRIVER_GLES2)
-            setup_generic_attribute (ctx, source, attribute, base);
+            setup_generic_attribute (ctx, pipeline, attribute, base);
           else
 #endif
             {
@@ -706,7 +706,7 @@ flush_state (CoglDrawFlags flags,
         case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY:
 #ifdef HAVE_COGL_GLES2
           if (ctx->driver == COGL_DRIVER_GLES2)
-            setup_generic_attribute (ctx, source, attribute, base);
+            setup_generic_attribute (ctx, pipeline, attribute, base);
           else
 #endif
             {
@@ -720,7 +720,7 @@ flush_state (CoglDrawFlags flags,
         case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
 #ifdef HAVE_COGL_GLES2
           if (ctx->driver == COGL_DRIVER_GLES2)
-            setup_generic_attribute (ctx, source, attribute, base);
+            setup_generic_attribute (ctx, pipeline, attribute, base);
           else
 #endif
             {
@@ -738,7 +738,7 @@ flush_state (CoglDrawFlags flags,
         case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
 #ifdef HAVE_COGL_GLES2
           if (ctx->driver == COGL_DRIVER_GLES2)
-            setup_generic_attribute (ctx, source, attribute, base);
+            setup_generic_attribute (ctx, pipeline, attribute, base);
           else
 #endif
             {
@@ -753,7 +753,7 @@ flush_state (CoglDrawFlags flags,
         case COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY:
 #ifdef COGL_PIPELINE_PROGEND_GLSL
           if (ctx->driver != COGL_DRIVER_GLES1)
-            setup_generic_attribute (ctx, source, attribute, base);
+            setup_generic_attribute (ctx, pipeline, attribute, base);
 #endif
           break;
         default:
@@ -763,9 +763,10 @@ flush_state (CoglDrawFlags flags,
       _cogl_buffer_unbind (buffer);
     }
 
-  apply_attribute_enable_updates (ctx, source);
+  apply_attribute_enable_updates (ctx, pipeline);
 
-  return source;
+  if (copy)
+    cogl_object_unref (copy);
 }
 
 void
@@ -782,440 +783,3 @@ _cogl_attribute_disable_cached_arrays (void)
    * attributes. */
   apply_attribute_enable_updates (ctx, NULL);
 }
-
-#ifdef COGL_ENABLE_DEBUG
-static int
-get_index (void *indices,
-           CoglIndicesType type,
-           int _index)
-{
-  if (!indices)
-    return _index;
-
-  switch (type)
-    {
-    case COGL_INDICES_TYPE_UNSIGNED_BYTE:
-      return ((guint8 *)indices)[_index];
-    case COGL_INDICES_TYPE_UNSIGNED_SHORT:
-      return ((guint16 *)indices)[_index];
-    case COGL_INDICES_TYPE_UNSIGNED_INT:
-      return ((guint32 *)indices)[_index];
-    }
-
-  g_return_val_if_reached (0);
-}
-
-static void
-add_line (void *vertices,
-          void *indices,
-          CoglIndicesType indices_type,
-          CoglAttribute *attribute,
-          int start,
-          int end,
-          CoglVertexP3 *lines,
-          int *n_line_vertices)
-{
-  int start_index = get_index (indices, indices_type, start);
-  int end_index = get_index (indices, indices_type, end);
-  float *v0 = (float *)((guint8 *)vertices + start_index * attribute->stride);
-  float *v1 = (float *)((guint8 *)vertices + end_index * attribute->stride);
-  float *o = (float *)(&lines[*n_line_vertices]);
-  int i;
-
-  for (i = 0; i < attribute->n_components; i++)
-    *(o++) = *(v0++);
-  for (;i < 3; i++)
-    *(o++) = 0;
-
-  for (i = 0; i < attribute->n_components; i++)
-    *(o++) = *(v1++);
-  for (;i < 3; i++)
-    *(o++) = 0;
-
-  *n_line_vertices += 2;
-}
-
-static CoglVertexP3 *
-get_wire_lines (CoglAttribute *attribute,
-                CoglVerticesMode mode,
-                int n_vertices_in,
-                int *n_vertices_out,
-                CoglIndices *_indices)
-{
-  CoglAttributeBuffer *attribute_buffer = cogl_attribute_get_buffer (attribute);
-  void *vertices;
-  CoglIndexBuffer *index_buffer;
-  void *indices;
-  CoglIndicesType indices_type;
-  int i;
-  int n_lines;
-  CoglVertexP3 *out = NULL;
-
-  vertices = cogl_buffer_map (COGL_BUFFER (attribute_buffer),
-                              COGL_BUFFER_ACCESS_READ, 0);
-  if (_indices)
-    {
-      index_buffer = cogl_indices_get_buffer (_indices);
-      indices = cogl_buffer_map (COGL_BUFFER (index_buffer),
-                                 COGL_BUFFER_ACCESS_READ, 0);
-      indices_type = cogl_indices_get_type (_indices);
-    }
-  else
-    {
-      index_buffer = NULL;
-      indices = NULL;
-      indices_type = COGL_INDICES_TYPE_UNSIGNED_BYTE;
-    }
-
-  *n_vertices_out = 0;
-
-  if (mode == COGL_VERTICES_MODE_TRIANGLES &&
-      (n_vertices_in % 3) == 0)
-    {
-      n_lines = n_vertices_in;
-      out = g_new (CoglVertexP3, n_lines * 2);
-      for (i = 0; i < n_vertices_in; i += 3)
-        {
-          add_line (vertices, indices, indices_type, attribute,
-                    i, i+1, out, n_vertices_out);
-          add_line (vertices, indices, indices_type, attribute,
-                    i+1, i+2, out, n_vertices_out);
-          add_line (vertices, indices, indices_type, attribute,
-                    i+2, i, out, n_vertices_out);
-        }
-    }
-  else if (mode == COGL_VERTICES_MODE_TRIANGLE_FAN &&
-           n_vertices_in >= 3)
-    {
-      n_lines = 2 * n_vertices_in - 3;
-      out = g_new (CoglVertexP3, n_lines * 2);
-
-      add_line (vertices, indices, indices_type, attribute,
-                0, 1, out, n_vertices_out);
-      add_line (vertices, indices, indices_type, attribute,
-                1, 2, out, n_vertices_out);
-      add_line (vertices, indices, indices_type, attribute,
-                0, 2, out, n_vertices_out);
-
-      for (i = 3; i < n_vertices_in; i++)
-        {
-          add_line (vertices, indices, indices_type, attribute,
-                    i - 1, i, out, n_vertices_out);
-          add_line (vertices, indices, indices_type, attribute,
-                    0, i, out, n_vertices_out);
-        }
-    }
-  else if (mode == COGL_VERTICES_MODE_TRIANGLE_STRIP &&
-           n_vertices_in >= 3)
-    {
-      n_lines = 2 * n_vertices_in - 3;
-      out = g_new (CoglVertexP3, n_lines * 2);
-
-      add_line (vertices, indices, indices_type, attribute,
-                0, 1, out, n_vertices_out);
-      add_line (vertices, indices, indices_type, attribute,
-                1, 2, out, n_vertices_out);
-      add_line (vertices, indices, indices_type, attribute,
-                0, 2, out, n_vertices_out);
-
-      for (i = 3; i < n_vertices_in; i++)
-        {
-          add_line (vertices, indices, indices_type, attribute,
-                    i - 1, i, out, n_vertices_out);
-          add_line (vertices, indices, indices_type, attribute,
-                    i - 2, i, out, n_vertices_out);
-        }
-    }
-    /* In the journal we are a bit sneaky and actually use GL_QUADS
-     * which isn't actually a valid CoglVerticesMode! */
-#ifdef HAVE_COGL_GL
-  else if (mode == GL_QUADS && (n_vertices_in % 4) == 0)
-    {
-      n_lines = n_vertices_in;
-      out = g_new (CoglVertexP3, n_lines * 2);
-
-      for (i = 0; i < n_vertices_in; i += 4)
-        {
-          add_line (vertices, indices, indices_type, attribute,
-                    i, i + 1, out, n_vertices_out);
-          add_line (vertices, indices, indices_type, attribute,
-                    i + 1, i + 2, out, n_vertices_out);
-          add_line (vertices, indices, indices_type, attribute,
-                    i + 2, i + 3, out, n_vertices_out);
-          add_line (vertices, indices, indices_type, attribute,
-                    i + 3, i, out, n_vertices_out);
-        }
-    }
-#endif
-
-  if (vertices != NULL)
-    cogl_buffer_unmap (COGL_BUFFER (attribute_buffer));
-
-  if (indices != NULL)
-    cogl_buffer_unmap (COGL_BUFFER (index_buffer));
-
-  return out;
-}
-
-static void
-draw_wireframe (CoglVerticesMode mode,
-                int first_vertex,
-                int n_vertices,
-                CoglAttribute **attributes,
-                int n_attributes,
-                CoglIndices *indices)
-{
-  CoglAttribute *position = NULL;
-  int i;
-  int n_line_vertices;
-  static CoglPipeline *wire_pipeline;
-  CoglAttribute *wire_attribute[1];
-  CoglVertexP3 *lines;
-  CoglAttributeBuffer *attribute_buffer;
-
-  for (i = 0; i < n_attributes; i++)
-    {
-      if (attributes[i]->name_state->name_id ==
-          COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY)
-        {
-          position = attributes[i];
-          break;
-        }
-    }
-  if (!position)
-    return;
-
-  lines = get_wire_lines (position,
-                          mode,
-                          n_vertices,
-                          &n_line_vertices,
-                          indices);
-  attribute_buffer =
-    cogl_attribute_buffer_new (sizeof (CoglVertexP3) * n_line_vertices,
-                               lines);
-  wire_attribute[0] =
-    cogl_attribute_new (attribute_buffer, "cogl_position_in",
-                        sizeof (CoglVertexP3),
-                        0,
-                        3,
-                        COGL_ATTRIBUTE_TYPE_FLOAT);
-  cogl_object_unref (attribute_buffer);
-
-  if (!wire_pipeline)
-    {
-      wire_pipeline = cogl_pipeline_new ();
-      cogl_pipeline_set_color4ub (wire_pipeline,
-                                  0x00, 0xff, 0x00, 0xff);
-    }
-
-  _cogl_push_source (wire_pipeline, FALSE);
-
-  /* temporarily disable the wireframe to avoid recursion! */
-  COGL_DEBUG_CLEAR_FLAG (COGL_DEBUG_WIREFRAME);
-  _cogl_draw_attributes (COGL_VERTICES_MODE_LINES,
-                         0,
-                         n_line_vertices,
-                         wire_attribute,
-                         1,
-                         COGL_DRAW_SKIP_JOURNAL_FLUSH |
-                         COGL_DRAW_SKIP_PIPELINE_VALIDATION |
-                         COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH);
-
-  COGL_DEBUG_SET_FLAG (COGL_DEBUG_WIREFRAME);
-
-  cogl_pop_source ();
-
-  cogl_object_unref (wire_attribute[0]);
-}
-#endif
-
-/* This can be called directly by the CoglJournal to draw attributes
- * skipping the implicit journal flush, the framebuffer flush and
- * pipeline validation. */
-void
-_cogl_draw_attributes (CoglVerticesMode mode,
-                       int first_vertex,
-                       int n_vertices,
-                       CoglAttribute **attributes,
-                       int n_attributes,
-                       CoglDrawFlags flags)
-{
-  ValidateLayerState state;
-  CoglPipeline *source;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  source = flush_state (flags, attributes, n_attributes, &state);
-
-  GE (ctx, glDrawArrays ((GLenum)mode, first_vertex, n_vertices));
-
-  if (G_UNLIKELY (source != cogl_get_source ()))
-    cogl_object_unref (source);
-
-#ifdef COGL_ENABLE_DEBUG
-  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WIREFRAME)))
-    draw_wireframe (mode, first_vertex, n_vertices,
-                    attributes, n_attributes, NULL);
-#endif
-}
-
-void
-cogl_draw_attributes (CoglVerticesMode mode,
-                      int first_vertex,
-                      int n_vertices,
-                      CoglAttribute **attributes,
-                      int n_attributes)
-{
-  _cogl_draw_attributes (mode, first_vertex,
-                         n_vertices,
-                         attributes, n_attributes,
-                         0 /* no flags */);
-}
-
-void
-cogl_vdraw_attributes (CoglVerticesMode mode,
-                       int first_vertex,
-                       int n_vertices,
-                       ...)
-{
-  va_list ap;
-  int n_attributes;
-  CoglAttribute *attribute;
-  CoglAttribute **attributes;
-  int i;
-
-  va_start (ap, n_vertices);
-  for (n_attributes = 0; va_arg (ap, CoglAttribute *); n_attributes++)
-    ;
-  va_end (ap);
-
-  attributes = g_alloca (sizeof (CoglAttribute *) * n_attributes);
-
-  va_start (ap, n_vertices);
-  for (i = 0; (attribute = va_arg (ap, CoglAttribute *)); i++)
-    attributes[i] = attribute;
-  va_end (ap);
-
-  cogl_draw_attributes (mode, first_vertex, n_vertices,
-                        attributes, n_attributes);
-}
-
-static size_t
-sizeof_index_type (CoglIndicesType type)
-{
-  switch (type)
-    {
-    case COGL_INDICES_TYPE_UNSIGNED_BYTE:
-      return 1;
-    case COGL_INDICES_TYPE_UNSIGNED_SHORT:
-      return 2;
-    case COGL_INDICES_TYPE_UNSIGNED_INT:
-      return 4;
-    }
-  g_return_val_if_reached (0);
-}
-
-void
-_cogl_draw_indexed_attributes (CoglVerticesMode mode,
-                               int first_vertex,
-                               int n_vertices,
-                               CoglIndices *indices,
-                               CoglAttribute **attributes,
-                               int n_attributes,
-                               CoglDrawFlags flags)
-{
-  ValidateLayerState state;
-  CoglPipeline *source;
-  CoglBuffer *buffer;
-  guint8 *base;
-  size_t buffer_offset;
-  size_t index_size;
-  GLenum indices_gl_type = 0;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  source = flush_state (flags, attributes, n_attributes, &state);
-
-  buffer = COGL_BUFFER (cogl_indices_get_buffer (indices));
-  base = _cogl_buffer_bind (buffer, COGL_BUFFER_BIND_TARGET_INDEX_BUFFER);
-  buffer_offset = cogl_indices_get_offset (indices);
-  index_size = sizeof_index_type (cogl_indices_get_type (indices));
-
-  switch (cogl_indices_get_type (indices))
-    {
-    case COGL_INDICES_TYPE_UNSIGNED_BYTE:
-      indices_gl_type = GL_UNSIGNED_BYTE;
-      break;
-    case COGL_INDICES_TYPE_UNSIGNED_SHORT:
-      indices_gl_type = GL_UNSIGNED_SHORT;
-      break;
-    case COGL_INDICES_TYPE_UNSIGNED_INT:
-      indices_gl_type = GL_UNSIGNED_INT;
-      break;
-    }
-
-  GE (ctx, glDrawElements ((GLenum)mode,
-                           n_vertices,
-                           indices_gl_type,
-                           base + buffer_offset + index_size * first_vertex));
-
-  _cogl_buffer_unbind (buffer);
-
-  if (G_UNLIKELY (source != cogl_get_source ()))
-    cogl_object_unref (source);
-
-#ifdef COGL_ENABLE_DEBUG
-  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WIREFRAME)))
-    draw_wireframe (mode, first_vertex, n_vertices,
-                    attributes, n_attributes, indices);
-#endif
-}
-
-void
-cogl_draw_indexed_attributes (CoglVerticesMode mode,
-                              int first_vertex,
-                              int n_vertices,
-                              CoglIndices *indices,
-                              CoglAttribute **attributes,
-                              int n_attributes)
-{
-  _cogl_draw_indexed_attributes (mode, first_vertex,
-                                 n_vertices, indices,
-                                 attributes, n_attributes,
-                                 0 /* no flags */);
-}
-
-void
-cogl_vdraw_indexed_attributes (CoglVerticesMode mode,
-                               int first_vertex,
-                               int n_vertices,
-                               CoglIndices *indices,
-                               ...)
-{
-  va_list ap;
-  int n_attributes;
-  CoglAttribute **attributes;
-  int i;
-  CoglAttribute *attribute;
-
-  va_start (ap, indices);
-  for (n_attributes = 0; va_arg (ap, CoglAttribute *); n_attributes++)
-    ;
-  va_end (ap);
-
-  attributes = g_alloca (sizeof (CoglAttribute *) * n_attributes);
-
-  va_start (ap, indices);
-  for (i = 0; (attribute = va_arg (ap, CoglAttribute *)); i++)
-    attributes[i] = attribute;
-  va_end (ap);
-
-  cogl_draw_indexed_attributes (mode,
-                                first_vertex,
-                                n_vertices,
-                                indices,
-                                attributes,
-                                n_attributes);
-}
-
-
diff --git a/cogl/cogl-attribute.h b/cogl/cogl-attribute.h
index c12990b..a9ec03e 100644
--- a/cogl/cogl-attribute.h
+++ b/cogl/cogl-attribute.h
@@ -213,34 +213,6 @@ cogl_attribute_set_buffer (CoglAttribute *attribute,
 gboolean
 cogl_is_attribute (void *object);
 
-void
-cogl_vdraw_attributes (CoglVerticesMode mode,
-                       int first_vertex,
-                       int n_vertices,
-                       ...) G_GNUC_NULL_TERMINATED;
-
-void
-cogl_draw_attributes (CoglVerticesMode mode,
-                      int first_vertex,
-                      int n_vertices,
-                      CoglAttribute **attributes,
-                      int n_attributes);
-
-void
-cogl_vdraw_indexed_attributes (CoglVerticesMode mode,
-                               int first_vertex,
-                               int n_vertices,
-                               CoglIndices *indices,
-                               ...) G_GNUC_NULL_TERMINATED;
-
-void
-cogl_draw_indexed_attributes (CoglVerticesMode mode,
-                              int first_vertex,
-                              int n_vertices,
-                              CoglIndices *indices,
-                              CoglAttribute **attributes,
-                              int n_attributes);
-
 G_END_DECLS
 
 #endif /* __COGL_ATTRIBUTE_H__ */
diff --git a/cogl/cogl-clip-stack.c b/cogl/cogl-clip-stack.c
index 5cc4981..418debb 100644
--- a/cogl/cogl-clip-stack.c
+++ b/cogl/cogl-clip-stack.c
@@ -218,9 +218,6 @@ add_stencil_clip_rectangle (CoglFramebuffer *framebuffer,
     _cogl_framebuffer_get_projection_stack (framebuffer);
   CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
 
-  /* temporarily swap in our special stenciling pipeline */
-  _cogl_push_source (ctx->stencil_pipeline, FALSE);
-
   /* This can be called from the journal code which doesn't flush
      the matrix stacks between calls so we need to ensure they're
      flushed now */
@@ -239,7 +236,9 @@ add_stencil_clip_rectangle (CoglFramebuffer *framebuffer,
       GE( ctx, glStencilFunc (GL_NEVER, 0x1, 0x1) );
       GE( ctx, glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE) );
 
-      _cogl_rectangle_immediate (x_1, y_1, x_2, y_2);
+      _cogl_rectangle_immediate (framebuffer,
+                                 ctx->stencil_pipeline,
+                                 x_1, y_1, x_2, y_2);
     }
   else
     {
@@ -247,7 +246,9 @@ add_stencil_clip_rectangle (CoglFramebuffer *framebuffer,
 	 rectangle */
       GE( ctx, glStencilFunc (GL_NEVER, 0x1, 0x3) );
       GE( ctx, glStencilOp (GL_INCR, GL_INCR, GL_INCR) );
-      _cogl_rectangle_immediate (x_1, y_1, x_2, y_2);
+      _cogl_rectangle_immediate (framebuffer,
+                                 ctx->stencil_pipeline,
+                                 x_1, y_1, x_2, y_2);
 
       /* Subtract one from all pixels in the stencil buffer so that
 	 only pixels where both the original stencil buffer and the
@@ -263,7 +264,9 @@ add_stencil_clip_rectangle (CoglFramebuffer *framebuffer,
       _cogl_context_set_current_projection (ctx, projection_stack);
       _cogl_context_set_current_modelview (ctx, modelview_stack);
 
-      _cogl_rectangle_immediate (-1.0, -1.0, 1.0, 1.0);
+      _cogl_rectangle_immediate (framebuffer,
+                                 ctx->stencil_pipeline,
+                                 -1.0, -1.0, 1.0, 1.0);
 
       _cogl_matrix_stack_pop (modelview_stack);
       _cogl_matrix_stack_pop (projection_stack);
@@ -272,9 +275,6 @@ add_stencil_clip_rectangle (CoglFramebuffer *framebuffer,
   /* Restore the stencil mode */
   GE( ctx, glStencilFunc (GL_EQUAL, 0x1, 0x1) );
   GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
-
-  /* restore the original source pipeline */
-  cogl_pop_source ();
 }
 
 typedef void (*SilhouettePaintCallback) (void *user_data);
@@ -302,9 +302,6 @@ add_stencil_clip_silhouette (CoglFramebuffer *framebuffer,
   _cogl_context_set_current_projection (ctx, projection_stack);
   _cogl_context_set_current_modelview (ctx, modelview_stack);
 
-  /* Just setup a simple pipeline that doesn't use texturing... */
-  _cogl_push_source (ctx->stencil_pipeline, FALSE);
-
   _cogl_pipeline_flush_gl_state (ctx->stencil_pipeline, FALSE, 0);
 
   GE( ctx, glEnable (GL_STENCIL_TEST) );
@@ -337,7 +334,9 @@ add_stencil_clip_silhouette (CoglFramebuffer *framebuffer,
           /* Just clear the bounding box */
           GE( ctx, glStencilMask (~(GLuint) 0) );
           GE( ctx, glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) );
-          _cogl_rectangle_immediate (bounds_x1, bounds_y1,
+          _cogl_rectangle_immediate (framebuffer,
+                                     ctx->stencil_pipeline,
+                                     bounds_x1, bounds_y1,
                                      bounds_x2, bounds_y2);
         }
       GE (ctx, glStencilMask (1));
@@ -364,8 +363,10 @@ add_stencil_clip_silhouette (CoglFramebuffer *framebuffer,
       _cogl_matrix_stack_push (modelview_stack);
       _cogl_matrix_stack_load_identity (modelview_stack);
 
-      _cogl_rectangle_immediate (-1.0, -1.0, 1.0, 1.0);
-      _cogl_rectangle_immediate (-1.0, -1.0, 1.0, 1.0);
+      _cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline,
+                                 -1.0, -1.0, 1.0, 1.0);
+      _cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline,
+                                 -1.0, -1.0, 1.0, 1.0);
 
       _cogl_matrix_stack_pop (modelview_stack);
       _cogl_matrix_stack_pop (projection_stack);
@@ -377,9 +378,6 @@ add_stencil_clip_silhouette (CoglFramebuffer *framebuffer,
 
   GE (ctx, glStencilFunc (GL_EQUAL, 0x1, 0x1));
   GE (ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP));
-
-  /* restore the original pipeline */
-  cogl_pop_source ();
 }
 
 static void
@@ -414,10 +412,13 @@ add_stencil_clip_path (CoglFramebuffer *framebuffer,
 static void
 paint_primitive_silhouette (void *user_data)
 {
-  _cogl_primitive_draw (user_data,
-                        COGL_DRAW_SKIP_JOURNAL_FLUSH |
-                        COGL_DRAW_SKIP_PIPELINE_VALIDATION |
-                        COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH);
+  _cogl_framebuffer_draw_primitive (cogl_get_draw_framebuffer (),
+                                    cogl_get_source (),
+                                    user_data,
+                                    COGL_DRAW_SKIP_JOURNAL_FLUSH |
+                                    COGL_DRAW_SKIP_PIPELINE_VALIDATION |
+                                    COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH |
+                                    COGL_DRAW_SKIP_LEGACY_STATE);
 }
 
 void
diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h
index 7e1f97d..137ba87 100644
--- a/cogl/cogl-framebuffer-private.h
+++ b/cogl/cogl-framebuffer-private.h
@@ -29,6 +29,7 @@
 #include "cogl-clip-state-private.h"
 #include "cogl-journal-private.h"
 #include "cogl-winsys-private.h"
+#include "cogl-attribute-private.h"
 
 #ifdef COGL_HAS_XLIB_SUPPORT
 #include <X11/Xlib.h>
@@ -367,4 +368,34 @@ _cogl_framebuffer_restore_clip_stack (CoglFramebuffer *framebuffer);
 void
 _cogl_framebuffer_unref (CoglFramebuffer *framebuffer);
 
+void
+_cogl_framebuffer_draw_primitive (CoglFramebuffer *framebuffer,
+                                  CoglPipeline *pipeline,
+                                  CoglPrimitive *primitive,
+                                  CoglDrawFlags flags);
+
+/* This can be called directly by the CoglJournal to draw attributes
+ * skipping the implicit journal flush, the framebuffer flush and
+ * pipeline validation. */
+void
+_cogl_framebuffer_draw_attributes (CoglFramebuffer *framebuffer,
+                                   CoglPipeline *pipeline,
+                                   CoglVerticesMode mode,
+                                   int first_vertex,
+                                   int n_vertices,
+                                   CoglAttribute **attributes,
+                                   int n_attributes,
+                                   CoglDrawFlags flags);
+
+void
+_cogl_framebuffer_draw_indexed_attributes (CoglFramebuffer *framebuffer,
+                                           CoglPipeline *pipeline,
+                                           CoglVerticesMode mode,
+                                           int first_vertex,
+                                           int n_vertices,
+                                           CoglIndices *indices,
+                                           CoglAttribute **attributes,
+                                           int n_attributes,
+                                           CoglDrawFlags flags);
+
 #endif /* __COGL_FRAMEBUFFER_PRIVATE_H */
diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c
index c82ad4f..b3d1753 100644
--- a/cogl/cogl-framebuffer.c
+++ b/cogl/cogl-framebuffer.c
@@ -41,6 +41,7 @@
 #include "cogl-winsys-private.h"
 #include "cogl-pipeline-state-private.h"
 #include "cogl-matrix-private.h"
+#include "cogl-primitive-private.h"
 
 #ifndef GL_FRAMEBUFFER
 #define GL_FRAMEBUFFER		0x8D40
@@ -2416,3 +2417,489 @@ _cogl_framebuffer_unref (CoglFramebuffer *framebuffer)
   /* Chain-up */
   _cogl_object_default_unref (framebuffer);
 }
+
+#ifdef COGL_ENABLE_DEBUG
+static int
+get_index (void *indices,
+           CoglIndicesType type,
+           int _index)
+{
+  if (!indices)
+    return _index;
+
+  switch (type)
+    {
+    case COGL_INDICES_TYPE_UNSIGNED_BYTE:
+      return ((guint8 *)indices)[_index];
+    case COGL_INDICES_TYPE_UNSIGNED_SHORT:
+      return ((guint16 *)indices)[_index];
+    case COGL_INDICES_TYPE_UNSIGNED_INT:
+      return ((guint32 *)indices)[_index];
+    }
+
+  g_return_val_if_reached (0);
+}
+
+static void
+add_line (void *vertices,
+          void *indices,
+          CoglIndicesType indices_type,
+          CoglAttribute *attribute,
+          int start,
+          int end,
+          CoglVertexP3 *lines,
+          int *n_line_vertices)
+{
+  int start_index = get_index (indices, indices_type, start);
+  int end_index = get_index (indices, indices_type, end);
+  float *v0 = (float *)((guint8 *)vertices + start_index * attribute->stride);
+  float *v1 = (float *)((guint8 *)vertices + end_index * attribute->stride);
+  float *o = (float *)(&lines[*n_line_vertices]);
+  int i;
+
+  for (i = 0; i < attribute->n_components; i++)
+    *(o++) = *(v0++);
+  for (;i < 3; i++)
+    *(o++) = 0;
+
+  for (i = 0; i < attribute->n_components; i++)
+    *(o++) = *(v1++);
+  for (;i < 3; i++)
+    *(o++) = 0;
+
+  *n_line_vertices += 2;
+}
+
+static CoglVertexP3 *
+get_wire_lines (CoglAttribute *attribute,
+                CoglVerticesMode mode,
+                int n_vertices_in,
+                int *n_vertices_out,
+                CoglIndices *_indices)
+{
+  CoglAttributeBuffer *attribute_buffer = cogl_attribute_get_buffer (attribute);
+  void *vertices;
+  CoglIndexBuffer *index_buffer;
+  void *indices;
+  CoglIndicesType indices_type;
+  int i;
+  int n_lines;
+  CoglVertexP3 *out = NULL;
+
+  vertices = cogl_buffer_map (COGL_BUFFER (attribute_buffer),
+                              COGL_BUFFER_ACCESS_READ, 0);
+  if (_indices)
+    {
+      index_buffer = cogl_indices_get_buffer (_indices);
+      indices = cogl_buffer_map (COGL_BUFFER (index_buffer),
+                                 COGL_BUFFER_ACCESS_READ, 0);
+      indices_type = cogl_indices_get_type (_indices);
+    }
+  else
+    {
+      index_buffer = NULL;
+      indices = NULL;
+      indices_type = COGL_INDICES_TYPE_UNSIGNED_BYTE;
+    }
+
+  *n_vertices_out = 0;
+
+  if (mode == COGL_VERTICES_MODE_TRIANGLES &&
+      (n_vertices_in % 3) == 0)
+    {
+      n_lines = n_vertices_in;
+      out = g_new (CoglVertexP3, n_lines * 2);
+      for (i = 0; i < n_vertices_in; i += 3)
+        {
+          add_line (vertices, indices, indices_type, attribute,
+                    i, i+1, out, n_vertices_out);
+          add_line (vertices, indices, indices_type, attribute,
+                    i+1, i+2, out, n_vertices_out);
+          add_line (vertices, indices, indices_type, attribute,
+                    i+2, i, out, n_vertices_out);
+        }
+    }
+  else if (mode == COGL_VERTICES_MODE_TRIANGLE_FAN &&
+           n_vertices_in >= 3)
+    {
+      n_lines = 2 * n_vertices_in - 3;
+      out = g_new (CoglVertexP3, n_lines * 2);
+
+      add_line (vertices, indices, indices_type, attribute,
+                0, 1, out, n_vertices_out);
+      add_line (vertices, indices, indices_type, attribute,
+                1, 2, out, n_vertices_out);
+      add_line (vertices, indices, indices_type, attribute,
+                0, 2, out, n_vertices_out);
+
+      for (i = 3; i < n_vertices_in; i++)
+        {
+          add_line (vertices, indices, indices_type, attribute,
+                    i - 1, i, out, n_vertices_out);
+          add_line (vertices, indices, indices_type, attribute,
+                    0, i, out, n_vertices_out);
+        }
+    }
+  else if (mode == COGL_VERTICES_MODE_TRIANGLE_STRIP &&
+           n_vertices_in >= 3)
+    {
+      n_lines = 2 * n_vertices_in - 3;
+      out = g_new (CoglVertexP3, n_lines * 2);
+
+      add_line (vertices, indices, indices_type, attribute,
+                0, 1, out, n_vertices_out);
+      add_line (vertices, indices, indices_type, attribute,
+                1, 2, out, n_vertices_out);
+      add_line (vertices, indices, indices_type, attribute,
+                0, 2, out, n_vertices_out);
+
+      for (i = 3; i < n_vertices_in; i++)
+        {
+          add_line (vertices, indices, indices_type, attribute,
+                    i - 1, i, out, n_vertices_out);
+          add_line (vertices, indices, indices_type, attribute,
+                    i - 2, i, out, n_vertices_out);
+        }
+    }
+    /* In the journal we are a bit sneaky and actually use GL_QUADS
+     * which isn't actually a valid CoglVerticesMode! */
+#ifdef HAVE_COGL_GL
+  else if (mode == GL_QUADS && (n_vertices_in % 4) == 0)
+    {
+      n_lines = n_vertices_in;
+      out = g_new (CoglVertexP3, n_lines * 2);
+
+      for (i = 0; i < n_vertices_in; i += 4)
+        {
+          add_line (vertices, indices, indices_type, attribute,
+                    i, i + 1, out, n_vertices_out);
+          add_line (vertices, indices, indices_type, attribute,
+                    i + 1, i + 2, out, n_vertices_out);
+          add_line (vertices, indices, indices_type, attribute,
+                    i + 2, i + 3, out, n_vertices_out);
+          add_line (vertices, indices, indices_type, attribute,
+                    i + 3, i, out, n_vertices_out);
+        }
+    }
+#endif
+
+  if (vertices != NULL)
+    cogl_buffer_unmap (COGL_BUFFER (attribute_buffer));
+
+  if (indices != NULL)
+    cogl_buffer_unmap (COGL_BUFFER (index_buffer));
+
+  return out;
+}
+
+static void
+draw_wireframe (CoglFramebuffer *framebuffer,
+                CoglPipeline *pipeline,
+                CoglVerticesMode mode,
+                int first_vertex,
+                int n_vertices,
+                CoglAttribute **attributes,
+                int n_attributes,
+                CoglIndices *indices)
+{
+  CoglAttribute *position = NULL;
+  int i;
+  int n_line_vertices;
+  static CoglPipeline *wire_pipeline;
+  CoglAttribute *wire_attribute[1];
+  CoglVertexP3 *lines;
+  CoglAttributeBuffer *attribute_buffer;
+
+  for (i = 0; i < n_attributes; i++)
+    {
+      if (attributes[i]->name_state->name_id ==
+          COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY)
+        {
+          position = attributes[i];
+          break;
+        }
+    }
+  if (!position)
+    return;
+
+  lines = get_wire_lines (position,
+                          mode,
+                          n_vertices,
+                          &n_line_vertices,
+                          indices);
+  attribute_buffer =
+    cogl_attribute_buffer_new (sizeof (CoglVertexP3) * n_line_vertices,
+                               lines);
+  wire_attribute[0] =
+    cogl_attribute_new (attribute_buffer, "cogl_position_in",
+                        sizeof (CoglVertexP3),
+                        0,
+                        3,
+                        COGL_ATTRIBUTE_TYPE_FLOAT);
+  cogl_object_unref (attribute_buffer);
+
+  if (!wire_pipeline)
+    {
+      wire_pipeline = cogl_pipeline_new ();
+      cogl_pipeline_set_color4ub (wire_pipeline,
+                                  0x00, 0xff, 0x00, 0xff);
+    }
+
+  /* temporarily disable the wireframe to avoid recursion! */
+  COGL_DEBUG_CLEAR_FLAG (COGL_DEBUG_WIREFRAME);
+  _cogl_framebuffer_draw_attributes (framebuffer,
+                                     wire_pipeline,
+                                     COGL_VERTICES_MODE_LINES,
+                                     0,
+                                     n_line_vertices,
+                                     wire_attribute,
+                                     1,
+                                     COGL_DRAW_SKIP_JOURNAL_FLUSH |
+                                     COGL_DRAW_SKIP_PIPELINE_VALIDATION |
+                                     COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH |
+                                     COGL_DRAW_SKIP_LEGACY_STATE);
+
+  COGL_DEBUG_SET_FLAG (COGL_DEBUG_WIREFRAME);
+
+  cogl_object_unref (wire_attribute[0]);
+}
+#endif
+
+/* This can be called directly by the CoglJournal to draw attributes
+ * skipping the implicit journal flush, the framebuffer flush and
+ * pipeline validation. */
+void
+_cogl_framebuffer_draw_attributes (CoglFramebuffer *framebuffer,
+                                   CoglPipeline *pipeline,
+                                   CoglVerticesMode mode,
+                                   int first_vertex,
+                                   int n_vertices,
+                                   CoglAttribute **attributes,
+                                   int n_attributes,
+                                   CoglDrawFlags flags)
+{
+  _cogl_flush_attributes_state (framebuffer, pipeline, flags,
+                                attributes, n_attributes);
+
+  GE (framebuffer->context,
+      glDrawArrays ((GLenum)mode, first_vertex, n_vertices));
+
+#ifdef COGL_ENABLE_DEBUG
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WIREFRAME)))
+    draw_wireframe (framebuffer, pipeline,
+                    mode, first_vertex, n_vertices,
+                    attributes, n_attributes, NULL);
+#endif
+}
+
+void
+cogl_framebuffer_draw_attributes (CoglFramebuffer *framebuffer,
+                                  CoglPipeline *pipeline,
+                                  CoglVerticesMode mode,
+                                  int first_vertex,
+                                  int n_vertices,
+                                  CoglAttribute **attributes,
+                                  int n_attributes)
+{
+  _cogl_framebuffer_draw_attributes (framebuffer,
+                                     pipeline,
+                                     mode,
+                                     first_vertex,
+                                     n_vertices,
+                                     attributes, n_attributes,
+                                     COGL_DRAW_SKIP_LEGACY_STATE);
+}
+
+void
+cogl_framebuffer_vdraw_attributes (CoglFramebuffer *framebuffer,
+                                   CoglPipeline *pipeline,
+                                   CoglVerticesMode mode,
+                                   int first_vertex,
+                                   int n_vertices,
+                                   ...)
+{
+  va_list ap;
+  int n_attributes;
+  CoglAttribute *attribute;
+  CoglAttribute **attributes;
+  int i;
+
+  va_start (ap, n_vertices);
+  for (n_attributes = 0; va_arg (ap, CoglAttribute *); n_attributes++)
+    ;
+  va_end (ap);
+
+  attributes = g_alloca (sizeof (CoglAttribute *) * n_attributes);
+
+  va_start (ap, n_vertices);
+  for (i = 0; (attribute = va_arg (ap, CoglAttribute *)); i++)
+    attributes[i] = attribute;
+  va_end (ap);
+
+  _cogl_framebuffer_draw_attributes (framebuffer,
+                                     pipeline,
+                                     mode, first_vertex, n_vertices,
+                                     attributes, n_attributes,
+                                     COGL_DRAW_SKIP_LEGACY_STATE);
+}
+
+static size_t
+sizeof_index_type (CoglIndicesType type)
+{
+  switch (type)
+    {
+    case COGL_INDICES_TYPE_UNSIGNED_BYTE:
+      return 1;
+    case COGL_INDICES_TYPE_UNSIGNED_SHORT:
+      return 2;
+    case COGL_INDICES_TYPE_UNSIGNED_INT:
+      return 4;
+    }
+  g_return_val_if_reached (0);
+}
+
+void
+_cogl_framebuffer_draw_indexed_attributes (CoglFramebuffer *framebuffer,
+                                           CoglPipeline *pipeline,
+                                           CoglVerticesMode mode,
+                                           int first_vertex,
+                                           int n_vertices,
+                                           CoglIndices *indices,
+                                           CoglAttribute **attributes,
+                                           int n_attributes,
+                                           CoglDrawFlags flags)
+{
+  CoglBuffer *buffer;
+  guint8 *base;
+  size_t buffer_offset;
+  size_t index_size;
+  GLenum indices_gl_type = 0;
+
+  _cogl_flush_attributes_state (framebuffer, pipeline, flags,
+                                attributes, n_attributes);
+
+  buffer = COGL_BUFFER (cogl_indices_get_buffer (indices));
+  base = _cogl_buffer_bind (buffer, COGL_BUFFER_BIND_TARGET_INDEX_BUFFER);
+  buffer_offset = cogl_indices_get_offset (indices);
+  index_size = sizeof_index_type (cogl_indices_get_type (indices));
+
+  switch (cogl_indices_get_type (indices))
+    {
+    case COGL_INDICES_TYPE_UNSIGNED_BYTE:
+      indices_gl_type = GL_UNSIGNED_BYTE;
+      break;
+    case COGL_INDICES_TYPE_UNSIGNED_SHORT:
+      indices_gl_type = GL_UNSIGNED_SHORT;
+      break;
+    case COGL_INDICES_TYPE_UNSIGNED_INT:
+      indices_gl_type = GL_UNSIGNED_INT;
+      break;
+    }
+
+  GE (framebuffer->context,
+      glDrawElements ((GLenum)mode,
+                      n_vertices,
+                      indices_gl_type,
+                      base + buffer_offset + index_size * first_vertex));
+
+  _cogl_buffer_unbind (buffer);
+
+#ifdef COGL_ENABLE_DEBUG
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WIREFRAME)))
+    draw_wireframe (framebuffer, pipeline,
+                    mode, first_vertex, n_vertices,
+                    attributes, n_attributes, indices);
+#endif
+}
+
+void
+cogl_framebuffer_draw_indexed_attributes (CoglFramebuffer *framebuffer,
+                                          CoglPipeline *pipeline,
+                                          CoglVerticesMode mode,
+                                          int first_vertex,
+                                          int n_vertices,
+                                          CoglIndices *indices,
+                                          CoglAttribute **attributes,
+                                          int n_attributes)
+{
+  _cogl_framebuffer_draw_indexed_attributes (framebuffer,
+                                             pipeline,
+                                             mode, first_vertex,
+                                             n_vertices, indices,
+                                             attributes, n_attributes,
+                                             COGL_DRAW_SKIP_LEGACY_STATE);
+}
+
+void
+cogl_vdraw_indexed_attributes (CoglFramebuffer *framebuffer,
+                               CoglPipeline *pipeline,
+                               CoglVerticesMode mode,
+                               int first_vertex,
+                               int n_vertices,
+                               CoglIndices *indices,
+                               ...)
+{
+  va_list ap;
+  int n_attributes;
+  CoglAttribute **attributes;
+  int i;
+  CoglAttribute *attribute;
+
+  va_start (ap, indices);
+  for (n_attributes = 0; va_arg (ap, CoglAttribute *); n_attributes++)
+    ;
+  va_end (ap);
+
+  attributes = g_alloca (sizeof (CoglAttribute *) * n_attributes);
+
+  va_start (ap, indices);
+  for (i = 0; (attribute = va_arg (ap, CoglAttribute *)); i++)
+    attributes[i] = attribute;
+  va_end (ap);
+
+  _cogl_framebuffer_draw_indexed_attributes (framebuffer,
+                                             pipeline,
+                                             mode,
+                                             first_vertex,
+                                             n_vertices,
+                                             indices,
+                                             attributes,
+                                             n_attributes,
+                                             COGL_DRAW_SKIP_LEGACY_STATE);
+}
+
+void
+_cogl_framebuffer_draw_primitive (CoglFramebuffer *framebuffer,
+                                  CoglPipeline *pipeline,
+                                  CoglPrimitive *primitive,
+                                  CoglDrawFlags flags)
+{
+  if (primitive->indices)
+    _cogl_framebuffer_draw_indexed_attributes (framebuffer,
+                                               pipeline,
+                                               primitive->mode,
+                                               primitive->first_vertex,
+                                               primitive->n_vertices,
+                                               primitive->indices,
+                                               primitive->attributes,
+                                               primitive->n_attributes,
+                                               flags);
+  else
+    _cogl_framebuffer_draw_attributes (framebuffer,
+                                       pipeline,
+                                       primitive->mode,
+                                       primitive->first_vertex,
+                                       primitive->n_vertices,
+                                       primitive->attributes,
+                                       primitive->n_attributes,
+                                       flags);
+}
+
+void
+cogl_framebuffer_draw_primitive (CoglFramebuffer *framebuffer,
+                                 CoglPipeline *pipeline,
+                                 CoglPrimitive *primitive)
+{
+  _cogl_framebuffer_draw_primitive (framebuffer, pipeline, primitive,
+                                    COGL_DRAW_SKIP_LEGACY_STATE);
+}
diff --git a/cogl/cogl-framebuffer.h b/cogl/cogl-framebuffer.h
index 1c1d0bd..5579ad1 100644
--- a/cogl/cogl-framebuffer.h
+++ b/cogl/cogl-framebuffer.h
@@ -973,6 +973,216 @@ cogl_framebuffer_clear4f (CoglFramebuffer *framebuffer,
                           float blue,
                           float alpha);
 
+/**
+ * cogl_framebuffer_draw_primitive:
+ * @framebuffer: A destination #CoglFramebuffer
+ * @pipeline: A #CoglPipeline state object
+ * @primitive: A #CoglPrimitive geometry object
+ *
+ * Draws the given @primitive geometry to the specified destination
+ * @framebuffer using the graphics processing pipeline described by @pipeline.
+ *
+ * <note>This api doesn't support any of the legacy global state options such
+ * as cogl_set_depth_test_enabled(), cogl_set_backface_culling_enabled() or
+ * cogl_program_use()</note>
+ *
+ * Stability: unstable
+ * Since: 1.10
+ */
+void
+cogl_framebuffer_draw_primitive (CoglFramebuffer *framebuffer,
+                                 CoglPipeline *pipeline,
+                                 CoglPrimitive *primitive);
+
+/**
+ * cogl_framebuffer_vdraw_attributes:
+ * @framebuffer: A destination #CoglFramebuffer
+ * @pipeline: A #CoglPipeline state object
+ * @mode: The #CoglVerticesMode defining the topology of vertices
+ * @first_vertex: The vertex offset within the given attributes to draw from
+ * @n_vertices: The number of vertices to draw from the given attributes
+ * @...: A set of vertex #CoglAttribute<!-- -->s defining vertex geometry
+ *
+ * First defines a geometry primitive by grouping a set of vertex attributes;
+ * specifying a @first_vertex; a number of vertices (@n_vertices) and
+ * specifying  what kind of topology the vertices have via @mode.
+ *
+ * Then the function draws the given @primitive geometry to the specified
+ * destination @framebuffer using the graphics processing pipeline described by
+ * @pipeline.
+ *
+ * The list of #CoglAttribute<!-- -->s define the attributes of the vertices to
+ * be drawn, such as positions, colors and normals and should be %NULL
+ * terminated.
+ *
+ * Stability: unstable
+ * Since: 1.10
+ */
+void
+cogl_framebuffer_vdraw_attributes (CoglFramebuffer *framebuffer,
+                                   CoglPipeline *pipeline,
+                                   CoglVerticesMode mode,
+                                   int first_vertex,
+                                   int n_vertices,
+                                   ...) G_GNUC_NULL_TERMINATED;
+
+/**
+ * cogl_framebuffer_draw_attributes:
+ * @framebuffer: A destination #CoglFramebuffer
+ * @pipeline: A #CoglPipeline state object
+ * @mode: The #CoglVerticesMode defining the topology of vertices
+ * @first_vertex: The vertex offset within the given attributes to draw from
+ * @n_vertices: The number of vertices to draw from the given attributes
+ * @attributes: An array of pointers to #CoglAttribute<-- -->s defining vertex
+ *              geometry
+ * @n_attributes: The number of attributes in the @attributes array.
+ *
+ * First defines a geometry primitive by grouping a set of vertex @attributes;
+ * specifying a @first_vertex; a number of vertices (@n_vertices) and
+ * specifying  what kind of topology the vertices have via @mode.
+ *
+ * Then the function draws the given @primitive geometry to the specified
+ * destination @framebuffer using the graphics processing pipeline described by
+ * @pipeline.
+ *
+ * The list of #CoglAttribute<!-- -->s define the attributes of the vertices to
+ * be drawn, such as positions, colors and normals and the number of attributes
+ * is given as @n_attributes.
+ *
+ * <note>This api doesn't support any of the legacy global state options such
+ * as cogl_set_depth_test_enabled(), cogl_set_backface_culling_enabled() or
+ * cogl_program_use()</note>
+ *
+ * Stability: unstable
+ * Since: 1.10
+ */
+void
+cogl_framebuffer_draw_attributes (CoglFramebuffer *framebuffer,
+                                  CoglPipeline *pipeline,
+                                  CoglVerticesMode mode,
+                                  int first_vertex,
+                                  int n_vertices,
+                                  CoglAttribute **attributes,
+                                  int n_attributes);
+
+/**
+ * cogl_framebuffer_vdraw_indexed_attributes:
+ * @framebuffer: A destination #CoglFramebuffer
+ * @pipeline: A #CoglPipeline state object
+ * @mode: The #CoglVerticesMode defining the topology of vertices
+ * @first_vertex: The vertex offset within the given attributes to draw from
+ * @n_vertices: The number of vertices to draw from the given attributes
+ * @indices: The array of indices used by the GPU to lookup attribute
+ *           data for each vertex.
+ * @...: A set of vertex #CoglAttribute<!-- -->s defining vertex geometry
+ *
+ * Behaves the same as cogl_framebuffer_vdraw_attributes() except that
+ * instead of reading vertex data sequentially from the specified
+ * attributes the @indices provide an indirection for how the data
+ * should be indexed allowing a random access order to be
+ * specified.
+ *
+ * For example an indices array of [0, 1, 2, 0, 2, 3] could be used
+ * used to draw two triangles (@mode = %COGL_VERTICES_MODE_TRIANGLES +
+ * @n_vertices = 6) but only provide attribute data for the 4 corners
+ * of a rectangle. When the GPU needs to read in each of the 6
+ * vertices it will read the @indices array for each vertex in
+ * sequence and use the index to look up the vertex attribute data. So
+ * here you can see that first and fourth vertex will point to the
+ * same data and third and fifth vertex will also point to shared
+ * data.
+ *
+ * Drawing with indices can be a good way of minimizing the size of a
+ * mesh by allowing you to avoid data for duplicate vertices because
+ * multiple entries in the index array can refer back to a single
+ * shared vertex.
+ *
+ * <note>The @indices array must at least be as long @first_vertex +
+ * @n_vertices otherwise the GPU will overrun the indices array when
+ * looking up vertex data.</note>
+ *
+ * Since it's very common to want to draw a run of rectangles using
+ * indices to avoid duplicating vertex data you can use
+ * cogl_get_rectangle_indices() to get a set of indices that can be
+ * shared.
+ *
+ * <note>This api doesn't support any of the legacy global state
+ * options such as cogl_set_depth_test_enabled(),
+ * cogl_set_backface_culling_enabled() or cogl_program_use()</note>
+ *
+ * Stability: unstable
+ * Since: 1.10
+ */
+void
+cogl_framebuffer_vdraw_indexed_attributes (CoglFramebuffer *framebuffer,
+                                           CoglPipeline *pipeline,
+                                           CoglVerticesMode mode,
+                                           int first_vertex,
+                                           int n_vertices,
+                                           CoglIndices *indices,
+                                           ...) G_GNUC_NULL_TERMINATED;
+
+/**
+ * cogl_framebuffer_draw_indexed_attributes:
+ * @framebuffer: A destination #CoglFramebuffer
+ * @pipeline: A #CoglPipeline state object
+ * @mode: The #CoglVerticesMode defining the topology of vertices
+ * @first_vertex: The vertex offset within the given attributes to draw from
+ * @n_vertices: The number of vertices to draw from the given attributes
+ * @indices: The array of indices used by the GPU to lookup attribute
+ *           data for each vertex.
+ * @attributes: An array of pointers to #CoglAttribute<-- -->s defining vertex
+ *              geometry
+ * @n_attributes: The number of attributes in the @attributes array.
+ *
+ * Behaves the same as cogl_framebuffer_draw_attributes() except that
+ * instead of reading vertex data sequentially from the specified
+ * @attributes the @indices provide an indirection for how the data
+ * should be indexed allowing a random access order to be
+ * specified.
+ *
+ * For example an indices array of [0, 1, 2, 0, 2, 3] could be used
+ * used to draw two triangles (@mode = %COGL_VERTICES_MODE_TRIANGLES +
+ * @n_vertices = 6) but only provide attribute data for the 4 corners
+ * of a rectangle. When the GPU needs to read in each of the 6
+ * vertices it will read the @indices array for each vertex in
+ * sequence and use the index to look up the vertex attribute data. So
+ * here you can see that first and fourth vertex will point to the
+ * same data and third and fifth vertex will also point to shared
+ * data.
+ *
+ * Drawing with indices can be a good way of minimizing the size of a
+ * mesh by allowing you to avoid data for duplicate vertices because
+ * multiple entries in the index array can refer back to a single
+ * shared vertex.
+ *
+ * <note>The @indices array must at least be as long @first_vertex +
+ * @n_vertices otherwise the GPU will overrun the indices array when
+ * looking up vertex data.</note>
+ *
+ * Since it's very common to want to draw a run of rectangles using
+ * indices to avoid duplicating vertex data you can use
+ * cogl_get_rectangle_indices() to get a set of indices that can be
+ * shared.
+ *
+ * <note>This api doesn't support any of the legacy global state
+ * options such as cogl_set_depth_test_enabled(),
+ * cogl_set_backface_culling_enabled() or cogl_program_use()</note>
+ *
+ * Stability: unstable
+ * Since: 1.10
+ */
+void
+cogl_framebuffer_draw_indexed_attributes (CoglFramebuffer *framebuffer,
+                                          CoglPipeline *pipeline,
+                                          CoglVerticesMode mode,
+                                          int first_vertex,
+                                          int n_vertices,
+                                          CoglIndices *indices,
+                                          CoglAttribute **attributes,
+                                          int n_attributes);
+
+
 /* XXX: Should we take an n_buffers + buffer id array instead of using
  * the CoglBufferBits type which doesn't seem future proof? */
 /**
diff --git a/cogl/cogl-journal.c b/cogl/cogl-journal.c
index 5a67aa1..27a9351 100644
--- a/cogl/cogl-journal.c
+++ b/cogl/cogl-journal.c
@@ -273,7 +273,8 @@ _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
   CoglAttribute **attributes;
   CoglDrawFlags draw_flags = (COGL_DRAW_SKIP_JOURNAL_FLUSH |
                               COGL_DRAW_SKIP_PIPELINE_VALIDATION |
-                              COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH);
+                              COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH |
+                              COGL_DRAW_SKIP_LEGACY_STATE);
 
   COGL_STATIC_TIMER (time_flush_modelview_and_entries,
                      "flush: pipeline+entries", /* parent */
@@ -296,7 +297,6 @@ _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
     }
 
   attributes = (CoglAttribute **)state->attributes->data;
-  _cogl_push_source (state->source, FALSE);
 
   if (!_cogl_pipeline_get_real_blend_enabled (state->source))
     draw_flags |= COGL_DRAW_COLOR_ATTRIBUTE_IS_OPAQUE;
@@ -305,33 +305,40 @@ _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
   if (ctx->driver == COGL_DRIVER_GL)
     {
       /* XXX: it's rather evil that we sneak in the GL_QUADS enum here... */
-      _cogl_draw_attributes (GL_QUADS,
-                             state->current_vertex, batch_len * 4,
-                             attributes,
-                             state->attributes->len,
-                             draw_flags);
+      _cogl_framebuffer_draw_attributes (state->framebuffer,
+                                         state->source,
+                                         GL_QUADS,
+                                         state->current_vertex, batch_len * 4,
+                                         attributes,
+                                         state->attributes->len,
+                                         draw_flags);
     }
   else
 #endif /* HAVE_COGL_GL */
     {
       if (batch_len > 1)
         {
-          _cogl_draw_indexed_attributes (COGL_VERTICES_MODE_TRIANGLES,
-                                         state->current_vertex * 6 / 4,
-                                         batch_len * 6,
-                                         state->indices,
-                                         attributes,
-                                         state->attributes->len,
-                                         draw_flags);
-
+          CoglVerticesMode mode = COGL_VERTICES_MODE_TRIANGLES;
+          int first_vertex = state->current_vertex * 6 / 4;
+          _cogl_framebuffer_draw_indexed_attributes (state->framebuffer,
+                                                     state->source,
+                                                     mode,
+                                                     first_vertex,
+                                                     batch_len * 6,
+                                                     state->indices,
+                                                     attributes,
+                                                     state->attributes->len,
+                                                     draw_flags);
         }
       else
         {
-          _cogl_draw_attributes (COGL_VERTICES_MODE_TRIANGLE_FAN,
-                                 state->current_vertex, 4,
-                                 attributes,
-                                 state->attributes->len,
-                                 draw_flags);
+          _cogl_framebuffer_draw_attributes (state->framebuffer,
+                                             state->source,
+                                             COGL_VERTICES_MODE_TRIANGLE_FAN,
+                                             state->current_vertex, 4,
+                                             attributes,
+                                             state->attributes->len,
+                                             draw_flags);
         }
     }
 
@@ -369,15 +376,16 @@ _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
                                   (ctxt->journal_rectangles_color & 4) ?
                                   color_intensity : 0,
                                   0xff);
-      cogl_set_source (outline);
 
       loop_attributes[0] = attributes[0]; /* we just want the position */
       for (i = 0; i < batch_len; i++)
-        _cogl_draw_attributes (COGL_VERTICES_MODE_LINE_LOOP,
-                               4 * i + state->current_vertex, 4,
-                               loop_attributes,
-                               1,
-                               draw_flags);
+        _cogl_framebuffer_draw_attributes (state->framebuffer,
+                                           outline,
+                                           COGL_VERTICES_MODE_LINE_LOOP,
+                                           4 * i + state->current_vertex, 4,
+                                           loop_attributes,
+                                           1,
+                                           draw_flags);
 
       /* Go to the next color */
       do
@@ -390,8 +398,6 @@ _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
 
   state->current_vertex += (4 * batch_len);
 
-  cogl_pop_source ();
-
   COGL_TIMER_STOP (_cogl_uprof_context, time_flush_modelview_and_entries);
 }
 
diff --git a/cogl/cogl-primitive.c b/cogl/cogl-primitive.c
index bef50a7..b6a3abd 100644
--- a/cogl/cogl-primitive.c
+++ b/cogl/cogl-primitive.c
@@ -576,34 +576,6 @@ _cogl_primitive_immutable_unref (CoglPrimitive *primitive)
 }
 
 void
-_cogl_primitive_draw (CoglPrimitive *primitive,
-                      CoglDrawFlags flags)
-{
-  if (primitive->indices)
-    _cogl_draw_indexed_attributes (primitive->mode,
-                                   primitive->first_vertex,
-                                   primitive->n_vertices,
-                                   primitive->indices,
-                                   primitive->attributes,
-                                   primitive->n_attributes,
-                                   flags);
-  else
-    _cogl_draw_attributes (primitive->mode,
-                           primitive->first_vertex,
-                           primitive->n_vertices,
-                           primitive->attributes,
-                           primitive->n_attributes,
-                           flags);
-}
-
-/* XXX: cogl_draw_primitive() ? */
-void
-cogl_primitive_draw (CoglPrimitive *primitive)
-{
-  _cogl_primitive_draw (primitive, 0 /* no flags */);
-}
-
-void
 cogl_primitive_foreach_attribute (CoglPrimitive *primitive,
                                   CoglPrimitiveAttributeCallback callback,
                                   void *user_data)
diff --git a/cogl/cogl-primitive.h b/cogl/cogl-primitive.h
index fa54fc6..fea8fd6 100644
--- a/cogl/cogl-primitive.h
+++ b/cogl/cogl-primitive.h
@@ -803,18 +803,6 @@ CoglPrimitive *
 cogl_primitive_copy (CoglPrimitive *primitive);
 
 /**
- * cogl_primitive_draw:
- * @primitive: A #CoglPrimitive object
- *
- * Draw the given @primitive with the current source material.
- *
- * Since: 1.6
- * Stability: Unstable
- */
-void
-cogl_primitive_draw (CoglPrimitive *primitive);
-
-/**
  * cogl_is_primitive:
  * @object: A #CoglObject
  *
diff --git a/cogl/cogl-primitives-private.h b/cogl/cogl-primitives-private.h
index debd90c..4933396 100644
--- a/cogl/cogl-primitives-private.h
+++ b/cogl/cogl-primitives-private.h
@@ -33,7 +33,9 @@ G_BEGIN_DECLS
    where the code may be called while the journal is already being
    flushed. In that case using the journal would go wrong */
 void
-_cogl_rectangle_immediate (float x_1,
+_cogl_rectangle_immediate (CoglFramebuffer *framebuffer,
+                           CoglPipeline *pipeline,
+                           float x_1,
                            float y_1,
                            float x_2,
                            float y_2);
diff --git a/cogl/cogl-primitives.c b/cogl/cogl-primitives.c
index 4a40916..d8328b0 100644
--- a/cogl/cogl-primitives.c
+++ b/cogl/cogl-primitives.c
@@ -38,6 +38,7 @@
 #include "cogl-attribute-private.h"
 #include "cogl-private.h"
 #include "cogl-meta-texture.h"
+#include "cogl-framebuffer-private.h"
 
 #include <string.h>
 #include <math.h>
@@ -839,7 +840,9 @@ cogl_rectangle (float x_1,
 }
 
 void
-_cogl_rectangle_immediate (float x_1,
+_cogl_rectangle_immediate (CoglFramebuffer *framebuffer,
+                           CoglPipeline *pipeline,
+                           float x_1,
                            float y_1,
                            float x_2,
                            float y_2)
@@ -866,14 +869,17 @@ _cogl_rectangle_immediate (float x_1,
                                       2, /* n_components */
                                       COGL_ATTRIBUTE_TYPE_FLOAT);
 
-  _cogl_draw_attributes (COGL_VERTICES_MODE_TRIANGLE_STRIP,
-                         0, /* first_index */
-                         4, /* n_vertices */
-                         attributes,
-                         1,
-                         COGL_DRAW_SKIP_JOURNAL_FLUSH |
-                         COGL_DRAW_SKIP_PIPELINE_VALIDATION |
-                         COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH);
+  _cogl_framebuffer_draw_attributes (framebuffer,
+                                     pipeline,
+                                     COGL_VERTICES_MODE_TRIANGLE_STRIP,
+                                     0, /* first_index */
+                                     4, /* n_vertices */
+                                     attributes,
+                                     1,
+                                     COGL_DRAW_SKIP_JOURNAL_FLUSH |
+                                     COGL_DRAW_SKIP_PIPELINE_VALIDATION |
+                                     COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH |
+                                     COGL_DRAW_SKIP_LEGACY_STATE);
 
 
   cogl_object_unref (attributes[0]);
@@ -1093,12 +1099,21 @@ cogl_polygon (const CoglTextureVertex *vertices,
                         v,
                         ctx->polygon_vertices->len * sizeof (float));
 
+  /* XXX: although this may seem redundant, we need to do this since
+   * cogl_polygon() can be used with legacy state and its the source stack
+   * which track whether legacy state is enabled.
+   *
+   * (We only have a CoglDrawFlag to disable legacy state not one
+   *  to enable it) */
   cogl_push_source (pipeline);
 
-  cogl_draw_attributes (COGL_VERTICES_MODE_TRIANGLE_FAN,
-                        0, n_vertices,
-                        attributes,
-                        n_attributes);
+  _cogl_framebuffer_draw_attributes (cogl_get_draw_framebuffer (),
+                                     pipeline,
+                                     COGL_VERTICES_MODE_TRIANGLE_FAN,
+                                     0, n_vertices,
+                                     attributes,
+                                     n_attributes,
+                                     0 /* no draw flags */);
 
   cogl_pop_source ();
 
diff --git a/cogl/cogl-vertex-buffer.c b/cogl/cogl-vertex-buffer.c
index be8c819..ff795a1 100644
--- a/cogl/cogl-vertex-buffer.c
+++ b/cogl/cogl-vertex-buffer.c
@@ -1618,9 +1618,18 @@ update_primitive_and_draw (CoglVertexBuffer *buffer,
                                    pipeline_priv);
     }
 
+  /* XXX: although this may seem redundant, we need to do this since
+   * CoglVertexBuffers can be used with legacy state and its the source stack
+   * which track whether legacy state is enabled.
+   *
+   * (We only have a CoglDrawFlag to disable legacy state not one
+   *  to enable it) */
   cogl_push_source (pipeline_priv->real_source);
 
-  cogl_primitive_draw (buffer->primitive);
+  _cogl_framebuffer_draw_primitive (cogl_get_draw_framebuffer (),
+                                    pipeline_priv->real_source,
+                                    buffer->primitive,
+                                    0 /* no draw flags */);
 
   cogl_pop_source ();
 }
diff --git a/cogl/cogl2-path.c b/cogl/cogl2-path.c
index 781b884..cd7e453 100644
--- a/cogl/cogl2-path.c
+++ b/cogl/cogl2-path.c
@@ -230,10 +230,12 @@ _cogl_path_stroke_nodes (CoglPath *path)
     {
       node = &g_array_index (data->path_nodes, CoglPathNode, path_start);
 
-      cogl_vdraw_attributes (COGL_VERTICES_MODE_LINE_STRIP,
-                             0, node->path_size,
-                             data->stroke_attributes[path_num],
-                             NULL);
+      cogl_framebuffer_vdraw_attributes (cogl_get_draw_framebuffer (),
+                                         source,
+                                         COGL_VERTICES_MODE_LINE_STRIP,
+                                         0, node->path_size,
+                                         data->stroke_attributes[path_num],
+                                         NULL);
 
       path_num++;
     }
@@ -322,8 +324,9 @@ void
 _cogl_path_fill_nodes (CoglPath *path, CoglDrawFlags flags)
 {
   gboolean needs_fallback = FALSE;
+  CoglPipeline *pipeline = cogl_get_source ();
 
-  _cogl_pipeline_foreach_layer_internal (cogl_get_source (),
+  _cogl_pipeline_foreach_layer_internal (pipeline,
                                          validate_layer_cb, &needs_fallback);
   if (needs_fallback)
     {
@@ -333,13 +336,15 @@ _cogl_path_fill_nodes (CoglPath *path, CoglDrawFlags flags)
 
   _cogl_path_build_fill_attribute_buffer (path);
 
-  _cogl_draw_indexed_attributes (COGL_VERTICES_MODE_TRIANGLES,
-                                 0, /* first_vertex */
-                                 path->data->fill_vbo_n_indices,
-                                 path->data->fill_vbo_indices,
-                                 path->data->fill_attributes,
-                                 COGL_PATH_N_ATTRIBUTES,
-                                 flags);
+  _cogl_framebuffer_draw_indexed_attributes (cogl_get_draw_framebuffer (),
+                                             pipeline,
+                                             COGL_VERTICES_MODE_TRIANGLES,
+                                             0, /* first_vertex */
+                                             path->data->fill_vbo_n_indices,
+                                             path->data->fill_vbo_indices,
+                                             path->data->fill_attributes,
+                                             COGL_PATH_N_ATTRIBUTES,
+                                             flags);
 }
 
 void
diff --git a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-docs.xml.in b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-docs.xml.in
index be5b76c..3f49e62 100644
--- a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-docs.xml.in
+++ b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-docs.xml.in
@@ -88,11 +88,6 @@
       <title>Geometry</title>
       <xi:include href="xml/cogl-primitive.xml"/>
       <xi:include href="xml/cogl-paths.xml"/>
-    </section>
-
-    <section id="cogl-drawing-apis">
-      <title>Drawing</title>
-      <xi:include href="xml/cogl-drawing.xml"/>
       <xi:include href="xml/cogl-rectangle.xml"/>
     </section>
 
diff --git a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt
index 50abc6f..36f4919 100644
--- a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt
+++ b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt
@@ -237,7 +237,6 @@ cogl_primitive_set_mode
 cogl_primitive_set_attributes
 cogl_primitive_get_indices
 cogl_primitive_set_indices
-cogl_primitive_draw
 cogl_primitive_copy
 CoglPrimitiveAttributeCallback
 cogl_primitive_foreach_attribute
@@ -307,15 +306,6 @@ cogl_path_stroke
 </SECTION>
 
 <SECTION>
-<FILE>cogl-drawing</FILE>
-<TITLE>Draw Vertex Attributes</TITLE>
-cogl_draw_vertex_attributes
-cogl_draw_vertex_attributes_array
-cogl_draw_indexed_vertex_attributes
-cogl_draw_indexed_vertex_attributes_array
-</SECTION>
-
-<SECTION>
 <FILE>cogl-texture</FILE>
 <TITLE>The Texture Interface</TITLE>
 CoglTexture
@@ -419,6 +409,13 @@ cogl_framebuffer_set_point_samples_per_pixel
 cogl_framebuffer_get_context
 cogl_framebuffer_clear
 cogl_framebuffer_clear4f
+
+<SUBSECTION>
+cogl_framebuffer_draw_primitive
+cogl_framebuffer_draw_attributes
+cogl_framebuffer_draw_indexed_attributes
+
+<SUBSECTION>
 cogl_framebuffer_swap_buffers
 cogl_framebuffer_swap_region
 cogl_framebuffer_add_swap_buffers_callback
diff --git a/examples/cogl-crate.c b/examples/cogl-crate.c
index d157a18..6b76a67 100644
--- a/examples/cogl-crate.c
+++ b/examples/cogl-crate.c
@@ -115,17 +115,7 @@ paint (Data *data)
   cogl_framebuffer_rotate (fb, rotation, 0, 1, 0);
   cogl_framebuffer_rotate (fb, rotation, 1, 0, 0);
 
-  /* Whenever you draw something with Cogl using geometry defined by
-   * one of cogl_rectangle, cogl_polygon, cogl_path or
-   * cogl_vertex_buffer then you have a current pipeline that defines
-   * how that geometry should be processed.
-   *
-   * Here we are making our crate pipeline current which will sample
-   * the crate texture when fragment processing. */
-  cogl_set_source (data->crate_pipeline);
-
-  /* Give Cogl some geometry to draw. */
-  cogl_primitive_draw (data->prim);
+  cogl_framebuffer_draw_primitive (fb, data->crate_pipeline, data->prim);
 
   cogl_set_depth_test_enabled (FALSE);
 
diff --git a/examples/cogl-hello.c b/examples/cogl-hello.c
index 49055e7..5b8b206 100644
--- a/examples/cogl-hello.c
+++ b/examples/cogl-hello.c
@@ -10,6 +10,7 @@ main (int argc, char **argv)
     CoglContext *ctx;
     CoglOnscreen *onscreen;
     CoglFramebuffer *fb;
+    CoglPipeline *pipeline;
     GError *error = NULL;
     CoglVertexP2C4 triangle_vertices[] = {
         {0, 0.7, 0xff, 0x00, 0x00, 0x80},
@@ -26,19 +27,20 @@ main (int argc, char **argv)
 
     onscreen = cogl_onscreen_new (ctx, 640, 480);
     cogl_onscreen_show (onscreen);
-
     fb = COGL_FRAMEBUFFER (onscreen);
-    cogl_push_framebuffer (fb);
 
     triangle = cogl_primitive_new_p2c4 (COGL_VERTICES_MODE_TRIANGLES,
                                         3, triangle_vertices);
+
+    pipeline = cogl_pipeline_new ();
+
     for (;;) {
         CoglPollFD *poll_fds;
         int n_poll_fds;
         gint64 timeout;
 
         cogl_framebuffer_clear4f (fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
-        cogl_primitive_draw (triangle);
+        cogl_framebuffer_draw_primitive (fb, pipeline, triangle);
         cogl_framebuffer_swap_buffers (fb);
 
         cogl_poll_get_info (ctx, &poll_fds, &n_poll_fds, &timeout);
diff --git a/examples/cogl-msaa.c b/examples/cogl-msaa.c
index d89ecfe..7316e53 100644
--- a/examples/cogl-msaa.c
+++ b/examples/cogl-msaa.c
@@ -77,8 +77,6 @@ main (int argc, char **argv)
         cogl_framebuffer_set_samples_per_pixel (offscreen_fb, 0);
       }
 
-    cogl_push_framebuffer (fb);
-
     triangle = cogl_primitive_new_p2c4 (COGL_VERTICES_MODE_TRIANGLES,
                                         3, triangle_vertices);
     pipeline = cogl_pipeline_new ();
@@ -93,12 +91,11 @@ main (int argc, char **argv)
         cogl_framebuffer_push_matrix (fb);
         cogl_framebuffer_scale (fb, 0.5, 1, 1);
         cogl_framebuffer_translate (fb, -1, 0, 0);
-        cogl_set_source (pipeline);
-        cogl_primitive_draw (triangle);
+        cogl_framebuffer_draw_primitive (fb, pipeline, triangle);
         cogl_framebuffer_pop_matrix (fb);
 
         cogl_push_framebuffer (offscreen_fb);
-        cogl_primitive_draw (triangle);
+        cogl_framebuffer_draw_primitive (fb, pipeline, triangle);
         cogl_framebuffer_resolve_samples (offscreen_fb);
         cogl_pop_framebuffer ();
 
diff --git a/examples/cogl-sdl-hello.c b/examples/cogl-sdl-hello.c
index e0ca7aa..db899ab 100644
--- a/examples/cogl-sdl-hello.c
+++ b/examples/cogl-sdl-hello.c
@@ -9,6 +9,7 @@
 typedef struct Data
 {
   CoglPrimitive *triangle;
+  CoglPipeline *pipeline;
   float center_x, center_y;
   CoglFramebuffer *fb;
   gboolean quit;
@@ -24,7 +25,7 @@ redraw (Data *data)
   cogl_framebuffer_push_matrix (fb);
   cogl_framebuffer_translate (fb, data->center_x, -data->center_y, 0.0f);
 
-  cogl_primitive_draw (data->triangle);
+  cogl_framebuffer_draw_primitive (fb, data->pipeline, data->triangle);
   cogl_framebuffer_pop_matrix (fb);
 
   cogl_framebuffer_swap_buffers (fb);
@@ -147,10 +148,9 @@ main (int argc, char **argv)
 
   cogl_onscreen_show (onscreen);
 
-  cogl_push_framebuffer (data.fb);
-
   data.triangle = cogl_primitive_new_p2c4 (COGL_VERTICES_MODE_TRIANGLES,
                                            3, triangle_vertices);
+  data.pipeline = cogl_pipeline_new ();
   while (!data.quit)
     {
       CoglPollFD *poll_fds;
@@ -173,8 +173,6 @@ main (int argc, char **argv)
       cogl_poll_dispatch (ctx, poll_fds, n_poll_fds);
     }
 
-  cogl_pop_framebuffer ();
-
   cogl_object_unref (ctx);
   cogl_object_unref (display);
   cogl_object_unref (renderer);
diff --git a/examples/cogl-x11-foreign.c b/examples/cogl-x11-foreign.c
index 00dbb1f..0113130 100644
--- a/examples/cogl-x11-foreign.c
+++ b/examples/cogl-x11-foreign.c
@@ -42,6 +42,7 @@ main (int argc, char **argv)
   CoglContext *ctx;
   CoglOnscreen *onscreen;
   CoglFramebuffer *fb;
+  CoglPipeline *pipeline;
   GError *error = NULL;
   guint32 visual;
   XVisualInfo template, *xvisinfo;
@@ -147,10 +148,10 @@ main (int argc, char **argv)
   XMapWindow (xdpy, xwin);
 
   fb = COGL_FRAMEBUFFER (onscreen);
-  cogl_push_framebuffer (fb);
 
   triangle = cogl_primitive_new_p2c4 (COGL_VERTICES_MODE_TRIANGLES,
                                       3, triangle_vertices);
+  pipeline = cogl_pipeline_new ();
   for (;;)
     {
       CoglPollFD *poll_fds;
@@ -170,7 +171,7 @@ main (int argc, char **argv)
           cogl_xlib_renderer_handle_event (renderer, &event);
         }
       cogl_framebuffer_clear4f (fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
-      cogl_primitive_draw (triangle);
+      cogl_framebuffer_draw_primitive (fb, pipeline, triangle);
       cogl_framebuffer_swap_buffers (fb);
 
       cogl_poll_get_info (ctx, &poll_fds, &n_poll_fds, &timeout);
diff --git a/examples/cogland.c b/examples/cogland.c
index a91e3f0..4f37d83 100644
--- a/examples/cogland.c
+++ b/examples/cogland.c
@@ -80,6 +80,7 @@ struct _CoglandCompositor
   GQueue frame_callbacks;
 
   CoglPrimitive *triangle;
+  CoglPipeline *triangle_pipeline;
 
   GSource *wayland_event_source;
 
@@ -512,7 +513,8 @@ paint_cb (void *user_data)
 
       cogl_framebuffer_clear4f (fb, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 1);
 
-      cogl_primitive_draw (compositor->triangle);
+      cogl_framebuffer_draw_primitive (fb, compositor->triangle_pipeline,
+                                       compositor->triangle);
 
       for (l2 = compositor->surfaces; l2; l2 = l2->next)
         {
@@ -751,6 +753,7 @@ main (int argc, char **argv)
 
   compositor.triangle = cogl_primitive_new_p2c4 (COGL_VERTICES_MODE_TRIANGLES,
                                                  3, triangle_vertices);
+  compositor.triangle_pipeline = cogl_pipeline_new ();
 
   g_timeout_add (16, paint_cb, &compositor);
 
diff --git a/tests/conform/test-custom-attributes.c b/tests/conform/test-custom-attributes.c
index bc3d09f..adbb4f0 100644
--- a/tests/conform/test-custom-attributes.c
+++ b/tests/conform/test-custom-attributes.c
@@ -6,6 +6,7 @@
 
 typedef struct _TestState
 {
+  CoglFramebuffer *fb;
   CoglPipeline *pipeline;
 } TestState;
 
@@ -57,21 +58,19 @@ test_float_verts (TestState *state, int offset_x, int offset_y)
                                       4, /* n_components */
                                       COGL_ATTRIBUTE_TYPE_FLOAT);
 
-  cogl_push_source (state->pipeline);
-
   cogl_push_matrix ();
   cogl_translate (offset_x, offset_y, 0.0f);
 
-  cogl_draw_attributes (COGL_VERTICES_MODE_TRIANGLES,
-                        0, /* first_vertex */
-                        6, /* n_vertices */
-                        attributes,
-                        2 /* n_attributes */);
+  cogl_framebuffer_draw_attributes (state->fb,
+                                    state->pipeline,
+                                    COGL_VERTICES_MODE_TRIANGLES,
+                                    0, /* first_vertex */
+                                    6, /* n_vertices */
+                                    attributes,
+                                    2 /* n_attributes */);
 
   cogl_pop_matrix ();
 
-  cogl_pop_source ();
-
   cogl_object_unref (attributes[1]);
   cogl_object_unref (attributes[0]);
   cogl_object_unref (buffer);
@@ -119,16 +118,16 @@ test_byte_verts (TestState *state, int offset_x, int offset_y)
                                       COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
   cogl_attribute_set_normalized (attributes[1], TRUE);
 
-  cogl_push_source (state->pipeline);
-
   cogl_push_matrix ();
   cogl_translate (offset_x, offset_y, 0.0f);
 
-  cogl_draw_attributes (COGL_VERTICES_MODE_TRIANGLES,
-                        0, /* first_vertex */
-                        6, /* n_vertices */
-                        attributes,
-                        2 /* n_attributes */);
+  cogl_framebuffer_draw_attributes (state->fb,
+                                    state->pipeline,
+                                    COGL_VERTICES_MODE_TRIANGLES,
+                                    0, /* first_vertex */
+                                    6, /* n_vertices */
+                                    attributes,
+                                    2 /* n_attributes */);
 
   cogl_object_unref (attributes[1]);
 
@@ -144,16 +143,16 @@ test_byte_verts (TestState *state, int offset_x, int offset_y)
 
   cogl_translate (20, 0, 0);
 
-  cogl_draw_attributes (COGL_VERTICES_MODE_TRIANGLES,
-                        0, /* first_vertex */
-                        3, /* n_vertices */
-                        attributes,
-                        2 /* n_attributes */);
+  cogl_framebuffer_draw_attributes (state->fb,
+                                    state->pipeline,
+                                    COGL_VERTICES_MODE_TRIANGLES,
+                                    0, /* first_vertex */
+                                    3, /* n_vertices */
+                                    attributes,
+                                    2 /* n_attributes */);
 
   cogl_pop_matrix ();
 
-  cogl_pop_source ();
-
   cogl_object_unref (attributes[0]);
   cogl_object_unref (attributes[1]);
   cogl_object_unref (buffer);
@@ -200,21 +199,19 @@ test_short_verts (TestState *state, int offset_x, int offset_y)
                                       2, /* n_components */
                                       COGL_ATTRIBUTE_TYPE_SHORT);
 
-  cogl_push_source (pipeline);
-
   cogl_push_matrix ();
   cogl_translate (offset_x + 10.0f, offset_y + 10.0f, 0.0f);
 
-  cogl_draw_attributes (COGL_VERTICES_MODE_TRIANGLES,
-                        0, /* first_vertex */
-                        3, /* n_vertices */
-                        attributes,
-                        1 /* n_attributes */);
+  cogl_framebuffer_draw_attributes (state->fb,
+                                    pipeline,
+                                    COGL_VERTICES_MODE_TRIANGLES,
+                                    0, /* first_vertex */
+                                    3, /* n_vertices */
+                                    attributes,
+                                    1 /* n_attributes */);
 
   cogl_pop_matrix ();
 
-  cogl_pop_source ();
-
   cogl_object_unref (attributes[0]);
 
   /* Test again treating the attribute as unsigned */
@@ -228,21 +225,19 @@ test_short_verts (TestState *state, int offset_x, int offset_y)
   pipeline2 = cogl_pipeline_copy (pipeline);
   cogl_pipeline_set_color4ub (pipeline2, 0, 255, 0, 255);
 
-  cogl_push_source (pipeline2);
-
   cogl_push_matrix ();
   cogl_translate (offset_x + 10.0f - 65525.0f, offset_y - 65525, 0.0f);
 
-  cogl_draw_attributes (COGL_VERTICES_MODE_TRIANGLES,
-                        0, /* first_vertex */
-                        3, /* n_vertices */
-                        attributes,
-                        1 /* n_attributes */);
+  cogl_framebuffer_draw_attributes (state->fb,
+                                    pipeline2,
+                                    COGL_VERTICES_MODE_TRIANGLES,
+                                    0, /* first_vertex */
+                                    3, /* n_vertices */
+                                    attributes,
+                                    1 /* n_attributes */);
 
   cogl_pop_matrix ();
 
-  cogl_pop_source ();
-
   cogl_object_unref (attributes[0]);
 
   cogl_object_unref (pipeline2);
@@ -277,6 +272,7 @@ test_cogl_custom_attributes (TestUtilsGTestFixture *fixture,
     {
       CoglSnippet *snippet;
       TestState state;
+      state.fb = shared_state->fb;
 
       cogl_ortho (/* left, right */
                   0, cogl_framebuffer_get_width (shared_state->fb),
diff --git a/tests/conform/test-primitive.c b/tests/conform/test-primitive.c
index e24e7e3..bed5c1d 100644
--- a/tests/conform/test-primitive.c
+++ b/tests/conform/test-primitive.c
@@ -177,9 +177,7 @@ test_paint (TestState *state)
                               (PRIM_COLOR >> 8) & 0xff,
                               (PRIM_COLOR >> 0) & 0xff);
   cogl_pipeline_set_layer_texture (pipeline, 0, tex);
-  cogl_handle_unref (tex);
-  cogl_set_source (pipeline);
-  cogl_object_unref (pipeline);
+  cogl_object_unref (tex);
 
   for (i = 0; i < G_N_ELEMENTS (test_prim_funcs); i++)
     {
@@ -190,13 +188,15 @@ test_paint (TestState *state)
 
       cogl_push_matrix ();
       cogl_translate (i * 10, 0, 0);
-      cogl_primitive_draw (prim);
+      cogl_framebuffer_draw_primitive (state->fb, pipeline, prim);
       cogl_pop_matrix ();
 
       test_utils_check_pixel (i * 10 + 2, 2, expected_color);
 
       cogl_object_unref (prim);
     }
+
+  cogl_object_unref (pipeline);
 }
 
 static gboolean



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]