[cogl/cogl-1.14: 20/174] clip-stack: Splits out opengl specific code



commit ffd2cf8ef8ff5ecf7b46104e2cd2909f468c8c1f
Author: Robert Bragg <robert linux intel com>
Date:   Wed Sep 19 20:37:32 2012 +0100

    clip-stack: Splits out opengl specific code
    
    As part of an on-going effort to enable non-opengl drivers for Cogl this
    splits out the opengl specific code in cogl-clip-stack.c into
    cogl/driver/cogl-clip-stack-gl.c
    
    Reviewed-by: Neil Roberts <neil linux intel com>
    
    (cherry picked from commit acf989f1bb628282c53d1249b2e3fc6f6579f1e9)

 cogl/Makefile.am                            |    2 +
 cogl/cogl-clip-stack.c                      |  605 +-------------------------
 cogl/cogl-driver.h                          |    7 +
 cogl/driver/gl/cogl-clip-stack-gl-private.h |   39 ++
 cogl/driver/gl/cogl-clip-stack-gl.c         |  634 +++++++++++++++++++++++++++
 cogl/driver/gl/gl/cogl-driver-gl.c          |    2 +
 cogl/driver/gl/gles/cogl-driver-gles.c      |    2 +
 7 files changed, 689 insertions(+), 602 deletions(-)
---
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index f693f84..2b53150 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -165,6 +165,8 @@ cogl_driver_sources += \
 	$(srcdir)/driver/gl/cogl-texture-2d-gl.c \
 	$(srcdir)/driver/gl/cogl-attribute-gl-private.h \
 	$(srcdir)/driver/gl/cogl-attribute-gl.c \
+	$(srcdir)/driver/gl/cogl-clip-stack-gl-private.h \
+	$(srcdir)/driver/gl/cogl-clip-stack-gl.c \
 	$(srcdir)/driver/gl/cogl-pipeline-opengl.c \
 	$(srcdir)/driver/gl/cogl-pipeline-opengl-private.h \
 	$(srcdir)/driver/gl/cogl-pipeline-fragend-glsl.c \
diff --git a/cogl/cogl-clip-stack.c b/cogl/cogl-clip-stack.c
index eb3c38b..ad23409 100644
--- a/cogl/cogl-clip-stack.c
+++ b/cogl/cogl-clip-stack.c
@@ -16,7 +16,8 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
  *
  *
  */
@@ -48,430 +49,7 @@
 #include "cogl-offscreen.h"
 #include "cogl-matrix-stack.h"
 
-#ifndef GL_CLIP_PLANE0
-#define GL_CLIP_PLANE0 0x3000
-#define GL_CLIP_PLANE1 0x3001
-#define GL_CLIP_PLANE2 0x3002
-#define GL_CLIP_PLANE3 0x3003
-#define GL_CLIP_PLANE4 0x3004
-#define GL_CLIP_PLANE5 0x3005
-#endif
-
-static void
-project_vertex (const CoglMatrix *modelview_projection,
-		float *vertex)
-{
-  int i;
-
-  cogl_matrix_transform_point (modelview_projection,
-                               &vertex[0], &vertex[1],
-                               &vertex[2], &vertex[3]);
-
-  /* Convert from homogenized coordinates */
-  for (i = 0; i < 4; i++)
-    vertex[i] /= vertex[3];
-}
-
-static void
-set_clip_plane (CoglFramebuffer *framebuffer,
-                GLint plane_num,
-		const float *vertex_a,
-		const float *vertex_b)
-{
-  GLfloat planef[4];
-  double planed[4];
-  GLfloat angle;
-  CoglMatrixStack *modelview_stack =
-    _cogl_framebuffer_get_modelview_stack (framebuffer);
-  CoglMatrixStack *projection_stack =
-    _cogl_framebuffer_get_projection_stack (framebuffer);
-  CoglMatrix inverse_projection;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  _cogl_matrix_stack_get_inverse (projection_stack, &inverse_projection);
-
-  /* Calculate the angle between the axes and the line crossing the
-     two points */
-  angle = atan2f (vertex_b[1] - vertex_a[1],
-                  vertex_b[0] - vertex_a[0]) * (180.0/G_PI);
-
-  _cogl_matrix_stack_push (modelview_stack);
-
-  /* Load the inverse of the projection matrix so we can specify the plane
-   * in screen coordinates */
-  _cogl_matrix_stack_set (modelview_stack, &inverse_projection);
-
-  /* Rotate about point a */
-  _cogl_matrix_stack_translate (modelview_stack,
-                                vertex_a[0], vertex_a[1], vertex_a[2]);
-  /* Rotate the plane by the calculated angle so that it will connect
-     the two points */
-  _cogl_matrix_stack_rotate (modelview_stack, angle, 0.0f, 0.0f, 1.0f);
-  _cogl_matrix_stack_translate (modelview_stack,
-                                -vertex_a[0], -vertex_a[1], -vertex_a[2]);
-
-  /* Clip planes can only be used when a fixed function backend is in
-     use so we know we can directly push this matrix to the builtin
-     state */
-  _cogl_matrix_entry_flush_to_gl_builtins (ctx,
-                                           modelview_stack->last_entry,
-                                           COGL_MATRIX_MODELVIEW,
-                                           framebuffer,
-                                           FALSE /* don't disable flip */);
-
-  planef[0] = 0;
-  planef[1] = -1.0;
-  planef[2] = 0;
-  planef[3] = vertex_a[1];
-
-  switch (ctx->driver)
-    {
-    default:
-      g_assert_not_reached ();
-      break;
-
-    case COGL_DRIVER_GLES1:
-      GE( ctx, glClipPlanef (plane_num, planef) );
-      break;
-
-    case COGL_DRIVER_GL:
-      planed[0] = planef[0];
-      planed[1] = planef[1];
-      planed[2] = planef[2];
-      planed[3] = planef[3];
-      GE( ctx, glClipPlane (plane_num, planed) );
-      break;
-    }
-
-  _cogl_matrix_stack_pop (modelview_stack);
-}
-
-static void
-set_clip_planes (CoglFramebuffer *framebuffer,
-                 CoglMatrixEntry *modelview_entry,
-                 float x_1,
-                 float y_1,
-                 float x_2,
-                 float y_2)
-{
-  CoglMatrix modelview_matrix;
-  CoglMatrixStack *projection_stack =
-    _cogl_framebuffer_get_projection_stack (framebuffer);
-  CoglMatrix projection_matrix;
-  CoglMatrix modelview_projection;
-  float signed_area;
-
-  float vertex_tl[4] = { x_1, y_1, 0, 1.0 };
-  float vertex_tr[4] = { x_2, y_1, 0, 1.0 };
-  float vertex_bl[4] = { x_1, y_2, 0, 1.0 };
-  float vertex_br[4] = { x_2, y_2, 0, 1.0 };
-
-  _cogl_matrix_stack_get (projection_stack, &projection_matrix);
-  _cogl_matrix_entry_get (modelview_entry, &modelview_matrix);
-
-  cogl_matrix_multiply (&modelview_projection,
-                        &projection_matrix,
-                        &modelview_matrix);
-
-  project_vertex (&modelview_projection, vertex_tl);
-  project_vertex (&modelview_projection, vertex_tr);
-  project_vertex (&modelview_projection, vertex_bl);
-  project_vertex (&modelview_projection, vertex_br);
-
-  /* Calculate the signed area of the polygon formed by the four
-     vertices so that we can know its orientation */
-  signed_area = (vertex_tl[0] * (vertex_tr[1] - vertex_bl[1])
-                 + vertex_tr[0] * (vertex_br[1] - vertex_tl[1])
-                 + vertex_br[0] * (vertex_bl[1] - vertex_tr[1])
-                 + vertex_bl[0] * (vertex_tl[1] - vertex_br[1]));
-
-  /* Set the clip planes to form lines between all of the vertices
-     using the same orientation as we calculated */
-  if (signed_area > 0.0f)
-    {
-      /* counter-clockwise */
-      set_clip_plane (framebuffer, GL_CLIP_PLANE0, vertex_tl, vertex_bl);
-      set_clip_plane (framebuffer, GL_CLIP_PLANE1, vertex_bl, vertex_br);
-      set_clip_plane (framebuffer, GL_CLIP_PLANE2, vertex_br, vertex_tr);
-      set_clip_plane (framebuffer, GL_CLIP_PLANE3, vertex_tr, vertex_tl);
-    }
-  else
-    {
-      /* clockwise */
-      set_clip_plane (framebuffer, GL_CLIP_PLANE0, vertex_tl, vertex_tr);
-      set_clip_plane (framebuffer, GL_CLIP_PLANE1, vertex_tr, vertex_br);
-      set_clip_plane (framebuffer, GL_CLIP_PLANE2, vertex_br, vertex_bl);
-      set_clip_plane (framebuffer, GL_CLIP_PLANE3, vertex_bl, vertex_tl);
-    }
-}
-
-static void
-add_stencil_clip_rectangle (CoglFramebuffer *framebuffer,
-                            CoglMatrixEntry *modelview_entry,
-                            float x_1,
-                            float y_1,
-                            float x_2,
-                            float y_2,
-                            CoglBool first)
-{
-  CoglMatrixStack *projection_stack =
-    _cogl_framebuffer_get_projection_stack (framebuffer);
-  CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
-
-  /* NB: This can be called while flushing the journal so we need
-   * to be very conservative with what state we change.
-   */
-
-  _cogl_context_set_current_projection_entry (ctx,
-                                              projection_stack->last_entry);
-  _cogl_context_set_current_modelview_entry (ctx, modelview_entry);
-
-  if (first)
-    {
-      GE( ctx, glEnable (GL_STENCIL_TEST) );
-
-      /* Initially disallow everything */
-      GE( ctx, glClearStencil (0) );
-      GE( ctx, glClear (GL_STENCIL_BUFFER_BIT) );
-
-      /* Punch out a hole to allow the rectangle */
-      GE( ctx, glStencilFunc (GL_NEVER, 0x1, 0x1) );
-      GE( ctx, glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE) );
-
-      _cogl_rectangle_immediate (framebuffer,
-                                 ctx->stencil_pipeline,
-                                 x_1, y_1, x_2, y_2);
-    }
-  else
-    {
-      /* Add one to every pixel of the stencil buffer in the
-	 rectangle */
-      GE( ctx, glStencilFunc (GL_NEVER, 0x1, 0x3) );
-      GE( ctx, glStencilOp (GL_INCR, GL_INCR, GL_INCR) );
-      _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
-	 rectangle are set will be valid */
-      GE( ctx, glStencilOp (GL_DECR, GL_DECR, GL_DECR) );
-
-      _cogl_context_set_current_projection_entry (ctx, &ctx->identity_entry);
-      _cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry);
-
-      _cogl_rectangle_immediate (framebuffer,
-                                 ctx->stencil_pipeline,
-                                 -1.0, -1.0, 1.0, 1.0);
-    }
-
-  /* Restore the stencil mode */
-  GE( ctx, glStencilFunc (GL_EQUAL, 0x1, 0x1) );
-  GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
-}
-
-typedef void (*SilhouettePaintCallback) (CoglFramebuffer *framebuffer,
-                                         CoglPipeline *pipeline,
-                                         void *user_data);
-
-static void
-add_stencil_clip_silhouette (CoglFramebuffer *framebuffer,
-                             SilhouettePaintCallback silhouette_callback,
-                             CoglMatrixEntry *modelview_entry,
-                             float bounds_x1,
-                             float bounds_y1,
-                             float bounds_x2,
-                             float bounds_y2,
-                             CoglBool merge,
-                             CoglBool need_clear,
-                             void *user_data)
-{
-  CoglMatrixStack *projection_stack =
-    _cogl_framebuffer_get_projection_stack (framebuffer);
-  CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
-
-  /* NB: This can be called while flushing the journal so we need
-   * to be very conservative with what state we change.
-   */
-
-  _cogl_context_set_current_projection_entry (ctx,
-                                              projection_stack->last_entry);
-  _cogl_context_set_current_modelview_entry (ctx, modelview_entry);
-
-  _cogl_pipeline_flush_gl_state (ctx->stencil_pipeline, framebuffer, FALSE, 0);
-
-  GE( ctx, glEnable (GL_STENCIL_TEST) );
-
-  GE( ctx, glColorMask (FALSE, FALSE, FALSE, FALSE) );
-  GE( ctx, glDepthMask (FALSE) );
-
-  if (merge)
-    {
-      GE (ctx, glStencilMask (2));
-      GE (ctx, glStencilFunc (GL_LEQUAL, 0x2, 0x6));
-    }
-  else
-    {
-      /* If we're not using the stencil buffer for clipping then we
-         don't need to clear the whole stencil buffer, just the area
-         that will be drawn */
-      if (need_clear)
-        /* If this is being called from the clip stack code then it
-           will have set up a scissor for the minimum bounding box of
-           all of the clips. That box will likely mean that this
-           _cogl_clear won't need to clear the entire
-           buffer. _cogl_framebuffer_clear_without_flush4f is used instead
-           of cogl_clear because it won't try to flush the journal */
-        _cogl_framebuffer_clear_without_flush4f (framebuffer,
-                                                 COGL_BUFFER_BIT_STENCIL,
-                                                 0, 0, 0, 0);
-      else
-        {
-          /* Just clear the bounding box */
-          GE( ctx, glStencilMask (~(GLuint) 0) );
-          GE( ctx, glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) );
-          _cogl_rectangle_immediate (framebuffer,
-                                     ctx->stencil_pipeline,
-                                     bounds_x1, bounds_y1,
-                                     bounds_x2, bounds_y2);
-        }
-      GE (ctx, glStencilMask (1));
-      GE (ctx, glStencilFunc (GL_LEQUAL, 0x1, 0x3));
-    }
-
-  GE (ctx, glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT));
-
-  silhouette_callback (framebuffer, ctx->stencil_pipeline, user_data);
-
-  if (merge)
-    {
-      /* Now we have the new stencil buffer in bit 1 and the old
-         stencil buffer in bit 0 so we need to intersect them */
-      GE (ctx, glStencilMask (3));
-      GE (ctx, glStencilFunc (GL_NEVER, 0x2, 0x3));
-      GE (ctx, glStencilOp (GL_DECR, GL_DECR, GL_DECR));
-      /* Decrement all of the bits twice so that only pixels where the
-         value is 3 will remain */
-
-      _cogl_context_set_current_projection_entry (ctx, &ctx->identity_entry);
-      _cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry);
-
-      _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);
-    }
 
-  GE (ctx, glStencilMask (~(GLuint) 0));
-  GE (ctx, glDepthMask (TRUE));
-  GE (ctx, glColorMask (TRUE, TRUE, TRUE, TRUE));
-
-  GE (ctx, glStencilFunc (GL_EQUAL, 0x1, 0x1));
-  GE (ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP));
-}
-
-static void
-paint_path_silhouette (CoglFramebuffer *framebuffer,
-                       CoglPipeline *pipeline,
-                       void *user_data)
-{
-  CoglPath *path = user_data;
-  if (path->data->path_nodes->len >= 3)
-    _cogl_path_fill_nodes (path,
-                           framebuffer,
-                           pipeline,
-                           COGL_DRAW_SKIP_JOURNAL_FLUSH |
-                           COGL_DRAW_SKIP_PIPELINE_VALIDATION |
-                           COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH);
-}
-
-static void
-add_stencil_clip_path (CoglFramebuffer *framebuffer,
-                       CoglMatrixEntry *modelview_entry,
-                       CoglPath *path,
-                       CoglBool merge,
-                       CoglBool need_clear)
-{
-  CoglPathData *data = path->data;
-  add_stencil_clip_silhouette (framebuffer,
-                               paint_path_silhouette,
-                               modelview_entry,
-                               data->path_nodes_min.x,
-                               data->path_nodes_min.y,
-                               data->path_nodes_max.x,
-                               data->path_nodes_max.y,
-                               merge,
-                               need_clear,
-                               path);
-}
-
-static void
-paint_primitive_silhouette (CoglFramebuffer *framebuffer,
-                            CoglPipeline *pipeline,
-                            void *user_data)
-{
-  _cogl_framebuffer_draw_primitive (framebuffer,
-                                    pipeline,
-                                    user_data,
-                                    COGL_DRAW_SKIP_JOURNAL_FLUSH |
-                                    COGL_DRAW_SKIP_PIPELINE_VALIDATION |
-                                    COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH |
-                                    COGL_DRAW_SKIP_LEGACY_STATE);
-}
-
-static void
-add_stencil_clip_primitive (CoglFramebuffer *framebuffer,
-                            CoglMatrixEntry *modelview_entry,
-                            CoglPrimitive *primitive,
-                            float bounds_x1,
-                            float bounds_y1,
-                            float bounds_x2,
-                            float bounds_y2,
-                            CoglBool merge,
-                            CoglBool need_clear)
-{
-  add_stencil_clip_silhouette (framebuffer,
-                               paint_primitive_silhouette,
-                               modelview_entry,
-                               bounds_x1,
-                               bounds_y1,
-                               bounds_x2,
-                               bounds_y2,
-                               merge,
-                               need_clear,
-                               primitive);
-}
-
-static void
-disable_stencil_buffer (void)
-{
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  GE( ctx, glDisable (GL_STENCIL_TEST) );
-}
-
-static void
-enable_clip_planes (void)
-{
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  GE( ctx, glEnable (GL_CLIP_PLANE0) );
-  GE( ctx, glEnable (GL_CLIP_PLANE1) );
-  GE( ctx, glEnable (GL_CLIP_PLANE2) );
-  GE( ctx, glEnable (GL_CLIP_PLANE3) );
-}
-
-static void
-disable_clip_planes (void)
-{
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  GE( ctx, glDisable (GL_CLIP_PLANE3) );
-  GE( ctx, glDisable (GL_CLIP_PLANE2) );
-  GE( ctx, glDisable (GL_CLIP_PLANE1) );
-  GE( ctx, glDisable (GL_CLIP_PLANE0) );
-}
 
 static void *
 _cogl_clip_stack_push_entry (CoglClipStack *clip_stack,
@@ -881,183 +459,6 @@ _cogl_clip_stack_flush (CoglClipStack *stack,
                         CoglFramebuffer *framebuffer)
 {
   CoglContext *ctx = framebuffer->context;
-  int has_clip_planes;
-  CoglBool using_clip_planes = FALSE;
-  CoglBool using_stencil_buffer = FALSE;
-  int scissor_x0;
-  int scissor_y0;
-  int scissor_x1;
-  int scissor_y1;
-  CoglClipStack *entry;
-  int scissor_y_start;
-
-  /* If we have already flushed this state then we don't need to do
-     anything */
-  if (ctx->current_clip_stack_valid)
-    {
-      if (ctx->current_clip_stack == stack)
-        return;
-
-      _cogl_clip_stack_unref (ctx->current_clip_stack);
-    }
-
-  ctx->current_clip_stack_valid = TRUE;
-  ctx->current_clip_stack = _cogl_clip_stack_ref (stack);
-
-  has_clip_planes =
-    ctx->private_feature_flags & COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES;
-
-  if (has_clip_planes)
-    disable_clip_planes ();
-  disable_stencil_buffer ();
-
-  /* If the stack is empty then there's nothing else to do */
-  if (stack == NULL)
-    {
-      COGL_NOTE (CLIPPING, "Flushed empty clip stack");
-
-      ctx->current_clip_stack_uses_stencil = FALSE;
-      GE (ctx, glDisable (GL_SCISSOR_TEST));
-      return;
-    }
-
-  /* Calculate the scissor rect first so that if we eventually have to
-     clear the stencil buffer then the clear will be clipped to the
-     intersection of all of the bounding boxes. This saves having to
-     clear the whole stencil buffer */
-  _cogl_clip_stack_get_bounds (stack,
-                               &scissor_x0, &scissor_y0,
-                               &scissor_x1, &scissor_y1);
-
-  /* Enable scissoring as soon as possible */
-  if (scissor_x0 >= scissor_x1 || scissor_y0 >= scissor_y1)
-    scissor_x0 = scissor_y0 = scissor_x1 = scissor_y1 = scissor_y_start = 0;
-  else
-    {
-      /* We store the entry coordinates in Cogl coordinate space
-       * but OpenGL requires the window origin to be the bottom
-       * left so we may need to convert the incoming coordinates.
-       *
-       * NB: Cogl forces all offscreen rendering to be done upside
-       * down so in this case no conversion is needed.
-       */
-
-      if (cogl_is_offscreen (framebuffer))
-        scissor_y_start = scissor_y0;
-      else
-        {
-          int framebuffer_height =
-            cogl_framebuffer_get_height (framebuffer);
-
-          scissor_y_start = framebuffer_height - scissor_y1;
-        }
-    }
-
-  COGL_NOTE (CLIPPING, "Flushing scissor to (%i, %i, %i, %i)",
-             scissor_x0, scissor_y0,
-             scissor_x1, scissor_y1);
-
-  GE (ctx, glEnable (GL_SCISSOR_TEST));
-  GE (ctx, glScissor (scissor_x0, scissor_y_start,
-                      scissor_x1 - scissor_x0,
-                      scissor_y1 - scissor_y0));
-
-  /* Add all of the entries. This will end up adding them in the
-     reverse order that they were specified but as all of the clips
-     are intersecting it should work out the same regardless of the
-     order */
-  for (entry = stack; entry; entry = entry->parent)
-    {
-      switch (entry->type)
-        {
-        case COGL_CLIP_STACK_PATH:
-            {
-              CoglClipStackPath *path_entry = (CoglClipStackPath *) entry;
-
-              COGL_NOTE (CLIPPING, "Adding stencil clip for path");
-
-              add_stencil_clip_path (framebuffer,
-                                     path_entry->matrix_entry,
-                                     path_entry->path,
-                                     using_stencil_buffer,
-                                     TRUE);
-
-              using_stencil_buffer = TRUE;
-              break;
-            }
-        case COGL_CLIP_STACK_PRIMITIVE:
-            {
-              CoglClipStackPrimitive *primitive_entry =
-                (CoglClipStackPrimitive *) entry;
-
-              COGL_NOTE (CLIPPING, "Adding stencil clip for primitive");
-
-              add_stencil_clip_primitive (framebuffer,
-                                          primitive_entry->matrix_entry,
-                                          primitive_entry->primitive,
-                                          primitive_entry->bounds_x1,
-                                          primitive_entry->bounds_y1,
-                                          primitive_entry->bounds_x2,
-                                          primitive_entry->bounds_y2,
-                                          using_stencil_buffer,
-                                          TRUE);
-
-              using_stencil_buffer = TRUE;
-              break;
-            }
-        case COGL_CLIP_STACK_RECT:
-            {
-              CoglClipStackRect *rect = (CoglClipStackRect *) entry;
-
-              /* We don't need to do anything extra if the clip for this
-                 rectangle was entirely described by its scissor bounds */
-              if (!rect->can_be_scissor)
-                {
-                  /* If we support clip planes and we haven't already used
-                     them then use that instead */
-                  if (has_clip_planes)
-                    {
-                      COGL_NOTE (CLIPPING,
-                                 "Adding clip planes clip for rectangle");
-
-                      set_clip_planes (framebuffer,
-                                       rect->matrix_entry,
-                                       rect->x0,
-                                       rect->y0,
-                                       rect->x1,
-                                       rect->y1);
-                      using_clip_planes = TRUE;
-                      /* We can't use clip planes a second time */
-                      has_clip_planes = FALSE;
-                    }
-                  else
-                    {
-                      COGL_NOTE (CLIPPING, "Adding stencil clip for rectangle");
-
-                      add_stencil_clip_rectangle (framebuffer,
-                                                  rect->matrix_entry,
-                                                  rect->x0,
-                                                  rect->y0,
-                                                  rect->x1,
-                                                  rect->y1,
-                                                  !using_stencil_buffer);
-                      using_stencil_buffer = TRUE;
-                    }
-                }
-              break;
-            }
-        case COGL_CLIP_STACK_WINDOW_RECT:
-          break;
-          /* We don't need to do anything for window space rectangles because
-           * their functionality is entirely implemented by the entry bounding
-           * box */
-        }
-    }
-
-  /* Enabling clip planes is delayed to now so that they won't affect
-     setting up the stencil buffer */
-  if (using_clip_planes)
-    enable_clip_planes ();
 
-  ctx->current_clip_stack_uses_stencil = using_stencil_buffer;
+  ctx->driver_vtable->clip_stack_flush (stack, framebuffer);
 }
diff --git a/cogl/cogl-driver.h b/cogl/cogl-driver.h
index bea53cd..527e5ff 100644
--- a/cogl/cogl-driver.h
+++ b/cogl/cogl-driver.h
@@ -222,6 +222,13 @@ struct _CoglDriverVtable
                               CoglDrawFlags flags,
                               CoglAttribute **attributes,
                               int n_attributes);
+
+  /* Flushes the clip stack to the GPU using a combination of the
+   * stencil buffer, scissor and clip plane state.
+   */
+  void
+  (* clip_stack_flush) (CoglClipStack *stack, CoglFramebuffer *framebuffer);
+
 };
 
 #endif /* __COGL_DRIVER_H */
diff --git a/cogl/driver/gl/cogl-clip-stack-gl-private.h b/cogl/driver/gl/cogl-clip-stack-gl-private.h
new file mode 100644
index 0000000..2946b3b
--- /dev/null
+++ b/cogl/driver/gl/cogl-clip-stack-gl-private.h
@@ -0,0 +1,39 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ *   Robert Bragg <robert linux intel com>
+ */
+
+#ifndef _COGL_CLIP_STACK_GL_PRIVATE_H_
+#define _COGL_CLIP_STACK_GL_PRIVATE_H_
+
+#include "cogl-types.h"
+#include "cogl-framebuffer.h"
+#include "cogl-clip-stack.h"
+
+void
+_cogl_clip_stack_gl_flush (CoglClipStack *stack,
+                           CoglFramebuffer *framebuffer);
+
+#endif /* _COGL_CLIP_STACK_GL_PRIVATE_H_ */
diff --git a/cogl/driver/gl/cogl-clip-stack-gl.c b/cogl/driver/gl/cogl-clip-stack-gl.c
new file mode 100644
index 0000000..eaf46bc
--- /dev/null
+++ b/cogl/driver/gl/cogl-clip-stack-gl.c
@@ -0,0 +1,634 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2007,2008,2009,2010,2011,2012 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ *  Neil Roberts   <neil linux intel com>
+ *  Robert Bragg   <robert linux intel com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl-context-private.h"
+#include "cogl-primitives-private.h"
+#include "cogl-pipeline-opengl-private.h"
+#include "cogl-path-private.h"
+#include "cogl-clip-stack-gl-private.h"
+
+#ifndef GL_CLIP_PLANE0
+#define GL_CLIP_PLANE0 0x3000
+#define GL_CLIP_PLANE1 0x3001
+#define GL_CLIP_PLANE2 0x3002
+#define GL_CLIP_PLANE3 0x3003
+#define GL_CLIP_PLANE4 0x3004
+#define GL_CLIP_PLANE5 0x3005
+#endif
+
+static void
+project_vertex (const CoglMatrix *modelview_projection,
+		float *vertex)
+{
+  int i;
+
+  cogl_matrix_transform_point (modelview_projection,
+                               &vertex[0], &vertex[1],
+                               &vertex[2], &vertex[3]);
+
+  /* Convert from homogenized coordinates */
+  for (i = 0; i < 4; i++)
+    vertex[i] /= vertex[3];
+}
+
+static void
+set_clip_plane (CoglFramebuffer *framebuffer,
+                int plane_num,
+		const float *vertex_a,
+		const float *vertex_b)
+{
+  CoglContext *ctx = framebuffer->context;
+  float planef[4];
+  double planed[4];
+  float angle;
+  CoglMatrixStack *modelview_stack =
+    _cogl_framebuffer_get_modelview_stack (framebuffer);
+  CoglMatrixStack *projection_stack =
+    _cogl_framebuffer_get_projection_stack (framebuffer);
+  CoglMatrix inverse_projection;
+
+  _cogl_matrix_stack_get_inverse (projection_stack, &inverse_projection);
+
+  /* Calculate the angle between the axes and the line crossing the
+     two points */
+  angle = atan2f (vertex_b[1] - vertex_a[1],
+                  vertex_b[0] - vertex_a[0]) * (180.0/G_PI);
+
+  _cogl_matrix_stack_push (modelview_stack);
+
+  /* Load the inverse of the projection matrix so we can specify the plane
+   * in screen coordinates */
+  _cogl_matrix_stack_set (modelview_stack, &inverse_projection);
+
+  /* Rotate about point a */
+  _cogl_matrix_stack_translate (modelview_stack,
+                                vertex_a[0], vertex_a[1], vertex_a[2]);
+  /* Rotate the plane by the calculated angle so that it will connect
+     the two points */
+  _cogl_matrix_stack_rotate (modelview_stack, angle, 0.0f, 0.0f, 1.0f);
+  _cogl_matrix_stack_translate (modelview_stack,
+                                -vertex_a[0], -vertex_a[1], -vertex_a[2]);
+
+  /* Clip planes can only be used when a fixed function backend is in
+     use so we know we can directly push this matrix to the builtin
+     state */
+  _cogl_matrix_entry_flush_to_gl_builtins (ctx,
+                                           modelview_stack->last_entry,
+                                           COGL_MATRIX_MODELVIEW,
+                                           framebuffer,
+                                           FALSE /* don't disable flip */);
+
+  planef[0] = 0;
+  planef[1] = -1.0;
+  planef[2] = 0;
+  planef[3] = vertex_a[1];
+
+  switch (ctx->driver)
+    {
+    default:
+      g_assert_not_reached ();
+      break;
+
+    case COGL_DRIVER_GLES1:
+      GE( ctx, glClipPlanef (plane_num, planef) );
+      break;
+
+    case COGL_DRIVER_GL:
+      planed[0] = planef[0];
+      planed[1] = planef[1];
+      planed[2] = planef[2];
+      planed[3] = planef[3];
+      GE( ctx, glClipPlane (plane_num, planed) );
+      break;
+    }
+
+  _cogl_matrix_stack_pop (modelview_stack);
+}
+
+static void
+set_clip_planes (CoglFramebuffer *framebuffer,
+                 CoglMatrixEntry *modelview_entry,
+                 float x_1,
+                 float y_1,
+                 float x_2,
+                 float y_2)
+{
+  CoglMatrix modelview_matrix;
+  CoglMatrixStack *projection_stack =
+    _cogl_framebuffer_get_projection_stack (framebuffer);
+  CoglMatrix projection_matrix;
+  CoglMatrix modelview_projection;
+  float signed_area;
+
+  float vertex_tl[4] = { x_1, y_1, 0, 1.0 };
+  float vertex_tr[4] = { x_2, y_1, 0, 1.0 };
+  float vertex_bl[4] = { x_1, y_2, 0, 1.0 };
+  float vertex_br[4] = { x_2, y_2, 0, 1.0 };
+
+  _cogl_matrix_stack_get (projection_stack, &projection_matrix);
+  _cogl_matrix_entry_get (modelview_entry, &modelview_matrix);
+
+  cogl_matrix_multiply (&modelview_projection,
+                        &projection_matrix,
+                        &modelview_matrix);
+
+  project_vertex (&modelview_projection, vertex_tl);
+  project_vertex (&modelview_projection, vertex_tr);
+  project_vertex (&modelview_projection, vertex_bl);
+  project_vertex (&modelview_projection, vertex_br);
+
+  /* Calculate the signed area of the polygon formed by the four
+     vertices so that we can know its orientation */
+  signed_area = (vertex_tl[0] * (vertex_tr[1] - vertex_bl[1])
+                 + vertex_tr[0] * (vertex_br[1] - vertex_tl[1])
+                 + vertex_br[0] * (vertex_bl[1] - vertex_tr[1])
+                 + vertex_bl[0] * (vertex_tl[1] - vertex_br[1]));
+
+  /* Set the clip planes to form lines between all of the vertices
+     using the same orientation as we calculated */
+  if (signed_area > 0.0f)
+    {
+      /* counter-clockwise */
+      set_clip_plane (framebuffer, GL_CLIP_PLANE0, vertex_tl, vertex_bl);
+      set_clip_plane (framebuffer, GL_CLIP_PLANE1, vertex_bl, vertex_br);
+      set_clip_plane (framebuffer, GL_CLIP_PLANE2, vertex_br, vertex_tr);
+      set_clip_plane (framebuffer, GL_CLIP_PLANE3, vertex_tr, vertex_tl);
+    }
+  else
+    {
+      /* clockwise */
+      set_clip_plane (framebuffer, GL_CLIP_PLANE0, vertex_tl, vertex_tr);
+      set_clip_plane (framebuffer, GL_CLIP_PLANE1, vertex_tr, vertex_br);
+      set_clip_plane (framebuffer, GL_CLIP_PLANE2, vertex_br, vertex_bl);
+      set_clip_plane (framebuffer, GL_CLIP_PLANE3, vertex_bl, vertex_tl);
+    }
+}
+
+static void
+add_stencil_clip_rectangle (CoglFramebuffer *framebuffer,
+                            CoglMatrixEntry *modelview_entry,
+                            float x_1,
+                            float y_1,
+                            float x_2,
+                            float y_2,
+                            CoglBool first)
+{
+  CoglMatrixStack *projection_stack =
+    _cogl_framebuffer_get_projection_stack (framebuffer);
+  CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
+
+  /* NB: This can be called while flushing the journal so we need
+   * to be very conservative with what state we change.
+   */
+
+  _cogl_context_set_current_projection_entry (ctx,
+                                              projection_stack->last_entry);
+  _cogl_context_set_current_modelview_entry (ctx, modelview_entry);
+
+  if (first)
+    {
+      GE( ctx, glEnable (GL_STENCIL_TEST) );
+
+      /* Initially disallow everything */
+      GE( ctx, glClearStencil (0) );
+      GE( ctx, glClear (GL_STENCIL_BUFFER_BIT) );
+
+      /* Punch out a hole to allow the rectangle */
+      GE( ctx, glStencilFunc (GL_NEVER, 0x1, 0x1) );
+      GE( ctx, glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE) );
+
+      _cogl_rectangle_immediate (framebuffer,
+                                 ctx->stencil_pipeline,
+                                 x_1, y_1, x_2, y_2);
+    }
+  else
+    {
+      /* Add one to every pixel of the stencil buffer in the
+	 rectangle */
+      GE( ctx, glStencilFunc (GL_NEVER, 0x1, 0x3) );
+      GE( ctx, glStencilOp (GL_INCR, GL_INCR, GL_INCR) );
+      _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
+	 rectangle are set will be valid */
+      GE( ctx, glStencilOp (GL_DECR, GL_DECR, GL_DECR) );
+
+      _cogl_context_set_current_projection_entry (ctx, &ctx->identity_entry);
+      _cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry);
+
+      _cogl_rectangle_immediate (framebuffer,
+                                 ctx->stencil_pipeline,
+                                 -1.0, -1.0, 1.0, 1.0);
+    }
+
+  /* Restore the stencil mode */
+  GE( ctx, glStencilFunc (GL_EQUAL, 0x1, 0x1) );
+  GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
+}
+
+typedef void (*SilhouettePaintCallback) (CoglFramebuffer *framebuffer,
+                                         CoglPipeline *pipeline,
+                                         void *user_data);
+
+static void
+add_stencil_clip_silhouette (CoglFramebuffer *framebuffer,
+                             SilhouettePaintCallback silhouette_callback,
+                             CoglMatrixEntry *modelview_entry,
+                             float bounds_x1,
+                             float bounds_y1,
+                             float bounds_x2,
+                             float bounds_y2,
+                             CoglBool merge,
+                             CoglBool need_clear,
+                             void *user_data)
+{
+  CoglMatrixStack *projection_stack =
+    _cogl_framebuffer_get_projection_stack (framebuffer);
+  CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
+
+  /* NB: This can be called while flushing the journal so we need
+   * to be very conservative with what state we change.
+   */
+
+  _cogl_context_set_current_projection_entry (ctx,
+                                              projection_stack->last_entry);
+  _cogl_context_set_current_modelview_entry (ctx, modelview_entry);
+
+  _cogl_pipeline_flush_gl_state (ctx->stencil_pipeline, framebuffer, FALSE, 0);
+
+  GE( ctx, glEnable (GL_STENCIL_TEST) );
+
+  GE( ctx, glColorMask (FALSE, FALSE, FALSE, FALSE) );
+  GE( ctx, glDepthMask (FALSE) );
+
+  if (merge)
+    {
+      GE (ctx, glStencilMask (2));
+      GE (ctx, glStencilFunc (GL_LEQUAL, 0x2, 0x6));
+    }
+  else
+    {
+      /* If we're not using the stencil buffer for clipping then we
+         don't need to clear the whole stencil buffer, just the area
+         that will be drawn */
+      if (need_clear)
+        /* If this is being called from the clip stack code then it
+           will have set up a scissor for the minimum bounding box of
+           all of the clips. That box will likely mean that this
+           _cogl_clear won't need to clear the entire
+           buffer. _cogl_framebuffer_clear_without_flush4f is used instead
+           of cogl_clear because it won't try to flush the journal */
+        _cogl_framebuffer_clear_without_flush4f (framebuffer,
+                                                 COGL_BUFFER_BIT_STENCIL,
+                                                 0, 0, 0, 0);
+      else
+        {
+          /* Just clear the bounding box */
+          GE( ctx, glStencilMask (~(GLuint) 0) );
+          GE( ctx, glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) );
+          _cogl_rectangle_immediate (framebuffer,
+                                     ctx->stencil_pipeline,
+                                     bounds_x1, bounds_y1,
+                                     bounds_x2, bounds_y2);
+        }
+      GE (ctx, glStencilMask (1));
+      GE (ctx, glStencilFunc (GL_LEQUAL, 0x1, 0x3));
+    }
+
+  GE (ctx, glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT));
+
+  silhouette_callback (framebuffer, ctx->stencil_pipeline, user_data);
+
+  if (merge)
+    {
+      /* Now we have the new stencil buffer in bit 1 and the old
+         stencil buffer in bit 0 so we need to intersect them */
+      GE (ctx, glStencilMask (3));
+      GE (ctx, glStencilFunc (GL_NEVER, 0x2, 0x3));
+      GE (ctx, glStencilOp (GL_DECR, GL_DECR, GL_DECR));
+      /* Decrement all of the bits twice so that only pixels where the
+         value is 3 will remain */
+
+      _cogl_context_set_current_projection_entry (ctx, &ctx->identity_entry);
+      _cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry);
+
+      _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);
+    }
+
+  GE (ctx, glStencilMask (~(GLuint) 0));
+  GE (ctx, glDepthMask (TRUE));
+  GE (ctx, glColorMask (TRUE, TRUE, TRUE, TRUE));
+
+  GE (ctx, glStencilFunc (GL_EQUAL, 0x1, 0x1));
+  GE (ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP));
+}
+
+static void
+paint_path_silhouette (CoglFramebuffer *framebuffer,
+                       CoglPipeline *pipeline,
+                       void *user_data)
+{
+  CoglPath *path = user_data;
+  if (path->data->path_nodes->len >= 3)
+    _cogl_path_fill_nodes (path,
+                           framebuffer,
+                           pipeline,
+                           COGL_DRAW_SKIP_JOURNAL_FLUSH |
+                           COGL_DRAW_SKIP_PIPELINE_VALIDATION |
+                           COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH);
+}
+
+static void
+add_stencil_clip_path (CoglFramebuffer *framebuffer,
+                       CoglMatrixEntry *modelview_entry,
+                       CoglPath *path,
+                       CoglBool merge,
+                       CoglBool need_clear)
+{
+  CoglPathData *data = path->data;
+  add_stencil_clip_silhouette (framebuffer,
+                               paint_path_silhouette,
+                               modelview_entry,
+                               data->path_nodes_min.x,
+                               data->path_nodes_min.y,
+                               data->path_nodes_max.x,
+                               data->path_nodes_max.y,
+                               merge,
+                               need_clear,
+                               path);
+}
+
+static void
+paint_primitive_silhouette (CoglFramebuffer *framebuffer,
+                            CoglPipeline *pipeline,
+                            void *user_data)
+{
+  _cogl_framebuffer_draw_primitive (framebuffer,
+                                    pipeline,
+                                    user_data,
+                                    COGL_DRAW_SKIP_JOURNAL_FLUSH |
+                                    COGL_DRAW_SKIP_PIPELINE_VALIDATION |
+                                    COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH |
+                                    COGL_DRAW_SKIP_LEGACY_STATE);
+}
+
+static void
+add_stencil_clip_primitive (CoglFramebuffer *framebuffer,
+                            CoglMatrixEntry *modelview_entry,
+                            CoglPrimitive *primitive,
+                            float bounds_x1,
+                            float bounds_y1,
+                            float bounds_x2,
+                            float bounds_y2,
+                            CoglBool merge,
+                            CoglBool need_clear)
+{
+  add_stencil_clip_silhouette (framebuffer,
+                               paint_primitive_silhouette,
+                               modelview_entry,
+                               bounds_x1,
+                               bounds_y1,
+                               bounds_x2,
+                               bounds_y2,
+                               merge,
+                               need_clear,
+                               primitive);
+}
+
+static void
+enable_clip_planes (CoglContext *ctx)
+{
+  GE( ctx, glEnable (GL_CLIP_PLANE0) );
+  GE( ctx, glEnable (GL_CLIP_PLANE1) );
+  GE( ctx, glEnable (GL_CLIP_PLANE2) );
+  GE( ctx, glEnable (GL_CLIP_PLANE3) );
+}
+
+static void
+disable_clip_planes (CoglContext *ctx)
+{
+  GE( ctx, glDisable (GL_CLIP_PLANE3) );
+  GE( ctx, glDisable (GL_CLIP_PLANE2) );
+  GE( ctx, glDisable (GL_CLIP_PLANE1) );
+  GE( ctx, glDisable (GL_CLIP_PLANE0) );
+}
+
+void
+_cogl_clip_stack_gl_flush (CoglClipStack *stack,
+                           CoglFramebuffer *framebuffer)
+{
+  CoglContext *ctx = framebuffer->context;
+  int has_clip_planes;
+  CoglBool using_clip_planes = FALSE;
+  CoglBool using_stencil_buffer = FALSE;
+  int scissor_x0;
+  int scissor_y0;
+  int scissor_x1;
+  int scissor_y1;
+  CoglClipStack *entry;
+  int scissor_y_start;
+
+  /* If we have already flushed this state then we don't need to do
+     anything */
+  if (ctx->current_clip_stack_valid)
+    {
+      if (ctx->current_clip_stack == stack)
+        return;
+
+      _cogl_clip_stack_unref (ctx->current_clip_stack);
+    }
+
+  ctx->current_clip_stack_valid = TRUE;
+  ctx->current_clip_stack = _cogl_clip_stack_ref (stack);
+
+  has_clip_planes =
+    ctx->private_feature_flags & COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES;
+
+  if (has_clip_planes)
+    disable_clip_planes (ctx);
+  GE( ctx, glDisable (GL_STENCIL_TEST) );
+
+  /* If the stack is empty then there's nothing else to do */
+  if (stack == NULL)
+    {
+      COGL_NOTE (CLIPPING, "Flushed empty clip stack");
+
+      ctx->current_clip_stack_uses_stencil = FALSE;
+      GE (ctx, glDisable (GL_SCISSOR_TEST));
+      return;
+    }
+
+  /* Calculate the scissor rect first so that if we eventually have to
+     clear the stencil buffer then the clear will be clipped to the
+     intersection of all of the bounding boxes. This saves having to
+     clear the whole stencil buffer */
+  _cogl_clip_stack_get_bounds (stack,
+                               &scissor_x0, &scissor_y0,
+                               &scissor_x1, &scissor_y1);
+
+  /* Enable scissoring as soon as possible */
+  if (scissor_x0 >= scissor_x1 || scissor_y0 >= scissor_y1)
+    scissor_x0 = scissor_y0 = scissor_x1 = scissor_y1 = scissor_y_start = 0;
+  else
+    {
+      /* We store the entry coordinates in Cogl coordinate space
+       * but OpenGL requires the window origin to be the bottom
+       * left so we may need to convert the incoming coordinates.
+       *
+       * NB: Cogl forces all offscreen rendering to be done upside
+       * down so in this case no conversion is needed.
+       */
+
+      if (cogl_is_offscreen (framebuffer))
+        scissor_y_start = scissor_y0;
+      else
+        {
+          int framebuffer_height =
+            cogl_framebuffer_get_height (framebuffer);
+
+          scissor_y_start = framebuffer_height - scissor_y1;
+        }
+    }
+
+  COGL_NOTE (CLIPPING, "Flushing scissor to (%i, %i, %i, %i)",
+             scissor_x0, scissor_y0,
+             scissor_x1, scissor_y1);
+
+  GE (ctx, glEnable (GL_SCISSOR_TEST));
+  GE (ctx, glScissor (scissor_x0, scissor_y_start,
+                      scissor_x1 - scissor_x0,
+                      scissor_y1 - scissor_y0));
+
+  /* Add all of the entries. This will end up adding them in the
+     reverse order that they were specified but as all of the clips
+     are intersecting it should work out the same regardless of the
+     order */
+  for (entry = stack; entry; entry = entry->parent)
+    {
+      switch (entry->type)
+        {
+        case COGL_CLIP_STACK_PATH:
+            {
+              CoglClipStackPath *path_entry = (CoglClipStackPath *) entry;
+
+              COGL_NOTE (CLIPPING, "Adding stencil clip for path");
+
+              add_stencil_clip_path (framebuffer,
+                                     path_entry->matrix_entry,
+                                     path_entry->path,
+                                     using_stencil_buffer,
+                                     TRUE);
+
+              using_stencil_buffer = TRUE;
+              break;
+            }
+        case COGL_CLIP_STACK_PRIMITIVE:
+            {
+              CoglClipStackPrimitive *primitive_entry =
+                (CoglClipStackPrimitive *) entry;
+
+              COGL_NOTE (CLIPPING, "Adding stencil clip for primitive");
+
+              add_stencil_clip_primitive (framebuffer,
+                                          primitive_entry->matrix_entry,
+                                          primitive_entry->primitive,
+                                          primitive_entry->bounds_x1,
+                                          primitive_entry->bounds_y1,
+                                          primitive_entry->bounds_x2,
+                                          primitive_entry->bounds_y2,
+                                          using_stencil_buffer,
+                                          TRUE);
+
+              using_stencil_buffer = TRUE;
+              break;
+            }
+        case COGL_CLIP_STACK_RECT:
+            {
+              CoglClipStackRect *rect = (CoglClipStackRect *) entry;
+
+              /* We don't need to do anything extra if the clip for this
+                 rectangle was entirely described by its scissor bounds */
+              if (!rect->can_be_scissor)
+                {
+                  /* If we support clip planes and we haven't already used
+                     them then use that instead */
+                  if (has_clip_planes)
+                    {
+                      COGL_NOTE (CLIPPING,
+                                 "Adding clip planes clip for rectangle");
+
+                      set_clip_planes (framebuffer,
+                                       rect->matrix_entry,
+                                       rect->x0,
+                                       rect->y0,
+                                       rect->x1,
+                                       rect->y1);
+                      using_clip_planes = TRUE;
+                      /* We can't use clip planes a second time */
+                      has_clip_planes = FALSE;
+                    }
+                  else
+                    {
+                      COGL_NOTE (CLIPPING, "Adding stencil clip for rectangle");
+
+                      add_stencil_clip_rectangle (framebuffer,
+                                                  rect->matrix_entry,
+                                                  rect->x0,
+                                                  rect->y0,
+                                                  rect->x1,
+                                                  rect->y1,
+                                                  !using_stencil_buffer);
+                      using_stencil_buffer = TRUE;
+                    }
+                }
+              break;
+            }
+        case COGL_CLIP_STACK_WINDOW_RECT:
+          break;
+          /* We don't need to do anything for window space rectangles because
+           * their functionality is entirely implemented by the entry bounding
+           * box */
+        }
+    }
+
+  /* Enabling clip planes is delayed to now so that they won't affect
+     setting up the stencil buffer */
+  if (using_clip_planes)
+    enable_clip_planes (ctx);
+
+  ctx->current_clip_stack_uses_stencil = using_stencil_buffer;
+}
diff --git a/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/driver/gl/gl/cogl-driver-gl.c
index 761f87a..6692807 100644
--- a/cogl/driver/gl/gl/cogl-driver-gl.c
+++ b/cogl/driver/gl/gl/cogl-driver-gl.c
@@ -36,6 +36,7 @@
 #include "cogl-framebuffer-gl-private.h"
 #include "cogl-texture-2d-gl-private.h"
 #include "cogl-attribute-gl-private.h"
+#include "cogl-clip-stack-gl-private.h"
 
 static CoglBool
 _cogl_driver_pixel_format_from_gl_internal (CoglContext *context,
@@ -550,4 +551,5 @@ _cogl_driver_gl =
     _cogl_texture_2d_gl_copy_from_bitmap,
     _cogl_texture_2d_gl_get_data,
     _cogl_gl_flush_attributes_state,
+    _cogl_clip_stack_gl_flush,
   };
diff --git a/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/driver/gl/gles/cogl-driver-gles.c
index 02a1676..485e2b1 100644
--- a/cogl/driver/gl/gles/cogl-driver-gles.c
+++ b/cogl/driver/gl/gles/cogl-driver-gles.c
@@ -35,6 +35,7 @@
 #include "cogl-framebuffer-gl-private.h"
 #include "cogl-texture-2d-gl-private.h"
 #include "cogl-attribute-gl-private.h"
+#include "cogl-clip-stack-gl-private.h"
 
 #ifndef GL_UNSIGNED_INT_24_8
 #define GL_UNSIGNED_INT_24_8 0x84FA
@@ -368,4 +369,5 @@ _cogl_driver_gles =
     _cogl_texture_2d_gl_copy_from_bitmap,
     NULL, /* texture_2d_get_data */
     _cogl_gl_flush_attributes_state,
+    _cogl_clip_stack_gl_flush,
   };



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