[Cogl] [PATCH] Replace cogl_path_{stroke, fill} with framebuffer API

Neil Roberts neil at linux.intel.com
Wed Apr 18 08:37:52 PDT 2012


The existing functions for stroking and filling a path depend on the
global framebuffer and source stacks. These are now replaced with
cogl_framebuffer_{stroke,fill}_path which get explicitly passed the
framebuffer and pipeline.
---
 cogl-pango/cogl-pango-display-list.c   |    3 +-
 cogl/cogl-clip-stack.c                 |   20 ++++--
 cogl/cogl-framebuffer.c                |   25 ++++++
 cogl/cogl-framebuffer.h                |   41 ++++++++++
 cogl/cogl-path-private.h               |   10 ++-
 cogl/cogl-path.c                       |  126 +++++++++++++++-----------------
 cogl/cogl-path.h                       |   37 +---------
 doc/reference/cogl2/cogl2-sections.txt |    4 +-
 tests/conform/test-path.c              |   31 ++++----
 9 files changed, 167 insertions(+), 130 deletions(-)

diff --git a/cogl-pango/cogl-pango-display-list.c b/cogl-pango/cogl-pango-display-list.c
index 5802ef9..28b5351 100644
--- a/cogl-pango/cogl-pango-display-list.c
+++ b/cogl-pango/cogl-pango-display-list.c
@@ -437,6 +437,7 @@ _cogl_pango_display_list_render (CoglPangoDisplayList *dl,
 
         case COGL_PANGO_DISPLAY_LIST_TRAPEZOID:
           {
+            CoglFramebuffer *framebuffer = cogl_get_draw_framebuffer ();
             float points[8];
             CoglPath *path;
 
@@ -453,7 +454,7 @@ _cogl_pango_display_list_render (CoglPangoDisplayList *dl,
 
             path = cogl_path_new (ctx);
             cogl_path_polygon (path, points, 4);
-            cogl_path_fill (path);
+            cogl_framebuffer_fill_path (framebuffer, node->pipeline, path);
             cogl_object_unref (path);
           }
           break;
diff --git a/cogl/cogl-clip-stack.c b/cogl/cogl-clip-stack.c
index 6bdd023..1de2960 100644
--- a/cogl/cogl-clip-stack.c
+++ b/cogl/cogl-clip-stack.c
@@ -278,7 +278,9 @@ add_stencil_clip_rectangle (CoglFramebuffer *framebuffer,
   GE( ctx, glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
 }
 
-typedef void (*SilhouettePaintCallback) (void *user_data);
+typedef void (*SilhouettePaintCallback) (CoglFramebuffer *framebuffer,
+                                         CoglPipeline *pipeline,
+                                         void *user_data);
 
 static void
 add_stencil_clip_silhouette (CoglFramebuffer *framebuffer,
@@ -346,7 +348,7 @@ add_stencil_clip_silhouette (CoglFramebuffer *framebuffer,
 
   GE (ctx, glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT));
 
-  silhouette_callback (user_data);
+  silhouette_callback (framebuffer, ctx->stencil_pipeline, user_data);
 
   if (merge)
     {
@@ -382,11 +384,15 @@ add_stencil_clip_silhouette (CoglFramebuffer *framebuffer,
 }
 
 static void
-paint_path_silhouette (void *user_data)
+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);
@@ -411,10 +417,12 @@ add_stencil_clip_path (CoglFramebuffer *framebuffer,
 }
 
 static void
-paint_primitive_silhouette (void *user_data)
+paint_primitive_silhouette (CoglFramebuffer *framebuffer,
+                            CoglPipeline *pipeline,
+                            void *user_data)
 {
-  _cogl_framebuffer_draw_primitive (cogl_get_draw_framebuffer (),
-                                    cogl_get_source (),
+  _cogl_framebuffer_draw_primitive (framebuffer,
+                                    pipeline,
                                     user_data,
                                     COGL_DRAW_SKIP_JOURNAL_FLUSH |
                                     COGL_DRAW_SKIP_PIPELINE_VALIDATION |
diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c
index 3918636..c099506 100644
--- a/cogl/cogl-framebuffer.c
+++ b/cogl/cogl-framebuffer.c
@@ -47,6 +47,7 @@
 #include "cogl1-context.h"
 #include "cogl-private.h"
 #include "cogl-primitives-private.h"
+#include "cogl-path-private.h"
 
 #ifndef GL_FRAMEBUFFER
 #define GL_FRAMEBUFFER		0x8D40
@@ -3500,3 +3501,27 @@ cogl_framebuffer_draw_textured_rectangles (CoglFramebuffer *framebuffer,
                                                    rects,
                                                    n_rectangles);
 }
+
+void
+cogl_framebuffer_fill_path (CoglFramebuffer *framebuffer,
+                            CoglPipeline *pipeline,
+                            CoglPath *path)
+{
+  _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (framebuffer));
+  _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
+  _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+  _cogl_path_fill_nodes (path, framebuffer, pipeline, 0 /* flags */);
+}
+
+void
+cogl_framebuffer_stroke_path (CoglFramebuffer *framebuffer,
+                              CoglPipeline *pipeline,
+                              CoglPath *path)
+{
+  _COGL_RETURN_IF_FAIL (cogl_is_framebuffer (framebuffer));
+  _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
+  _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+
+  _cogl_path_stroke_nodes (path, framebuffer, pipeline);
+}
diff --git a/cogl/cogl-framebuffer.h b/cogl/cogl-framebuffer.h
index bccde36..0b030a2 100644
--- a/cogl/cogl-framebuffer.h
+++ b/cogl/cogl-framebuffer.h
@@ -1470,6 +1470,47 @@ cogl_framebuffer_draw_textured_rectangles (CoglFramebuffer *framebuffer,
                                            const float *coordinates,
                                            unsigned int n_rectangles);
 
+/**
+ * cogl_framebuffer_fill_path:
+ * @framebuffer: A #CoglFramebuffer
+ * @pipeline: A #CoglPipeline to render with
+ * @path: The #CoglPath to fill
+ *
+ * Fills the interior of the path using the fragment operations
+ * defined by the pipeline.
+ *
+ * The interior of the shape is determined using the fill rule of the
+ * path. See %CoglPathFillRule for details.
+ *
+ * <note>The result of referencing sliced textures in your current
+ * pipeline when filling a path are undefined. You should pass
+ * the %COGL_TEXTURE_NO_SLICING flag when loading any texture you will
+ * use while filling a path.</note>
+ *
+ * Since: 2.0
+ */
+void
+cogl_framebuffer_fill_path (CoglFramebuffer *framebuffer,
+                            CoglPipeline *pipeline,
+                            CoglPath *path);
+
+/**
+ * cogl_framebuffer_stroke_path:
+ * @framebuffer: A #CoglFramebuffer
+ * @pipeline: A #CoglPipeline to render with
+ * @path: The #CoglPath to stroke
+ *
+ * Strokes the edge of the path using the fragment operations defined
+ * by the pipeline. The stroke line will have a width of 1 pixel
+ * regardless of the current transformation matrix.
+ *
+ * Since: 2.0
+ */
+void
+cogl_framebuffer_stroke_path (CoglFramebuffer *framebuffer,
+                              CoglPipeline *pipeline,
+                              CoglPath *path);
+
 /* 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-path-private.h b/cogl/cogl-path-private.h
index c7e94a8..cc0b65c 100644
--- a/cogl/cogl-path-private.h
+++ b/cogl/cogl-path-private.h
@@ -116,6 +116,14 @@ CoglBool
 _cogl_path_is_rectangle (CoglPath *path);
 
 void
-_cogl_path_fill_nodes (CoglPath *path, CoglDrawFlags flags);
+_cogl_path_stroke_nodes (CoglPath *path,
+                         CoglFramebuffer *framebuffer,
+                         CoglPipeline *pipeline);
+
+void
+_cogl_path_fill_nodes (CoglPath *path,
+                       CoglFramebuffer *framebuffer,
+                       CoglPipeline *pipeline,
+                       CoglDrawFlags flags);
 
 #endif /* __COGL_PATH_PRIVATE_H */
diff --git a/cogl/cogl-path.c b/cogl/cogl-path.c
index b849345..f14d8c1 100644
--- a/cogl/cogl-path.c
+++ b/cogl/cogl-path.c
@@ -202,37 +202,37 @@ _cogl_path_add_node (CoglPath *path,
   data->is_rectangle = FALSE;
 }
 
-static void
-_cogl_path_stroke_nodes (CoglPath *path)
+void
+_cogl_path_stroke_nodes (CoglPath *path,
+                         CoglFramebuffer *framebuffer,
+                         CoglPipeline *pipeline)
 {
   CoglPathData *data = path->data;
   CoglPipeline *copy = NULL;
-  CoglPipeline *source;
   unsigned int path_start;
   int path_num = 0;
   CoglPathNode *node;
 
-  source = cogl_get_source ();
+  if (data->path_nodes->len == 0)
+    return;
 
-  if (cogl_pipeline_get_n_layers (source) != 0)
+  if (cogl_pipeline_get_n_layers (pipeline) != 0)
     {
-      copy = cogl_pipeline_copy (source);
+      copy = cogl_pipeline_copy (pipeline);
       _cogl_pipeline_prune_to_n_layers (copy, 0);
-      source = copy;
+      pipeline = copy;
     }
 
   _cogl_path_build_stroke_attribute_buffer (path);
 
-  cogl_push_source (source);
-
   for (path_start = 0;
        path_start < data->path_nodes->len;
        path_start += node->path_size)
     {
       node = &g_array_index (data->path_nodes, CoglPathNode, path_start);
 
-      cogl_framebuffer_vdraw_attributes (cogl_get_draw_framebuffer (),
-                                         source,
+      cogl_framebuffer_vdraw_attributes (framebuffer,
+                                         pipeline,
                                          COGL_VERTICES_MODE_LINE_STRIP,
                                          0, node->path_size,
                                          data->stroke_attributes[path_num],
@@ -241,8 +241,6 @@ _cogl_path_stroke_nodes (CoglPath *path)
       path_num++;
     }
 
-  cogl_pop_source ();
-
   if (copy)
     cogl_object_unref (copy);
 }
@@ -273,10 +271,10 @@ _cogl_path_get_bounds (CoglPath *path,
 }
 
 static void
-_cogl_path_fill_nodes_with_clipped_rectangle (CoglPath *path)
+_cogl_path_fill_nodes_with_clipped_rectangle (CoglPath *path,
+                                              CoglFramebuffer *framebuffer,
+                                              CoglPipeline *pipeline)
 {
-  CoglFramebuffer *fb;
-
   if (!(path->data->context->private_feature_flags &
         COGL_PRIVATE_FEATURE_STENCIL_BUFFER))
     {
@@ -291,13 +289,14 @@ _cogl_path_fill_nodes_with_clipped_rectangle (CoglPath *path)
         }
     }
 
-  fb = cogl_get_draw_framebuffer ();
-  cogl_framebuffer_push_path_clip (fb, path);
-  cogl_rectangle (path->data->path_nodes_min.x,
-                  path->data->path_nodes_min.y,
-                  path->data->path_nodes_max.x,
-                  path->data->path_nodes_max.y);
-  cogl_framebuffer_pop_clip (fb);
+  cogl_framebuffer_push_path_clip (framebuffer, path);
+  cogl_framebuffer_draw_rectangle (framebuffer,
+                                   pipeline,
+                                   path->data->path_nodes_min.x,
+                                   path->data->path_nodes_min.y,
+                                   path->data->path_nodes_max.x,
+                                   path->data->path_nodes_max.y);
+  cogl_framebuffer_pop_clip (framebuffer);
 }
 
 static CoglBool
@@ -321,64 +320,55 @@ validate_layer_cb (CoglPipelineLayer *layer, void *user_data)
 }
 
 void
-_cogl_path_fill_nodes (CoglPath *path, CoglDrawFlags flags)
-{
-  CoglBool needs_fallback = FALSE;
-  CoglPipeline *pipeline = cogl_get_source ();
-
-  _cogl_pipeline_foreach_layer_internal (pipeline,
-                                         validate_layer_cb, &needs_fallback);
-  if (needs_fallback)
-    {
-      _cogl_path_fill_nodes_with_clipped_rectangle (path);
-      return;
-    }
-
-  _cogl_path_build_fill_attribute_buffer (path);
-
-  _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
-cogl_path_fill (CoglPath *path)
+_cogl_path_fill_nodes (CoglPath *path,
+                       CoglFramebuffer *framebuffer,
+                       CoglPipeline *pipeline,
+                       CoglDrawFlags flags)
 {
-  _COGL_RETURN_IF_FAIL (cogl_is_path (path));
-
   if (path->data->path_nodes->len == 0)
     return;
 
   /* If the path is a simple rectangle then we can divert to using
-     cogl_rectangle which should be faster because it can go through
-     the journal instead of uploading the geometry just for two
-     triangles */
-  if (path->data->is_rectangle)
+     cogl_framebuffer_draw_rectangle which should be faster because it
+     can go through the journal instead of uploading the geometry just
+     for two triangles */
+  if (path->data->is_rectangle && flags == 0)
     {
       float x_1, y_1, x_2, y_2;
 
       _cogl_path_get_bounds (path, &x_1, &y_1, &x_2, &y_2);
-      cogl_rectangle (x_1, y_1, x_2, y_2);
+      cogl_framebuffer_draw_rectangle (framebuffer,
+                                       pipeline,
+                                       x_1, y_1,
+                                       x_2, y_2);
     }
   else
-    _cogl_path_fill_nodes (path, 0);
-}
-
-void
-cogl_path_stroke (CoglPath *path)
-{
-  _COGL_RETURN_IF_FAIL (cogl_is_path (path));
+    {
+      CoglBool needs_fallback = FALSE;
 
-  if (path->data->path_nodes->len == 0)
-    return;
+      _cogl_pipeline_foreach_layer_internal (pipeline,
+                                             validate_layer_cb,
+                                             &needs_fallback);
+      if (needs_fallback)
+        {
+          _cogl_path_fill_nodes_with_clipped_rectangle (path,
+                                                        framebuffer,
+                                                        pipeline);
+          return;
+        }
 
-  _cogl_path_stroke_nodes (path);
+      _cogl_path_build_fill_attribute_buffer (path);
+
+      _cogl_framebuffer_draw_indexed_attributes (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/cogl/cogl-path.h b/cogl/cogl-path.h
index fa2b707..8e2b234 100644
--- a/cogl/cogl-path.h
+++ b/cogl/cogl-path.h
@@ -430,10 +430,8 @@ typedef enum {
  * @fill_rule: The new fill rule.
  *
  * Sets the fill rule of the current path to @fill_rule. This will
- * affect how the path is filled when cogl_path_fill() is later
- * called. Note that the fill rule state is attached to the path so
- * calling cogl_get_path() will preserve the fill rule and calling
- * cogl_path_new() will reset the fill rule back to the default.
+ * affect how the path is filled when cogl_framebuffer_fill_path() is
+ * later called.
  *
  * Since: 2.0
  */
@@ -452,37 +450,6 @@ cogl_path_set_fill_rule (CoglPath *path, CoglPathFillRule fill_rule);
 CoglPathFillRule
 cogl_path_get_fill_rule (CoglPath *path);
 
-/**
- * cogl_path_fill:
- *
- * Fills the interior of the constructed shape using the current
- * drawing color.
- *
- * The interior of the shape is determined using the fill rule of the
- * path. See %CoglPathFillRule for details.
- *
- * <note>The result of referencing sliced textures in your current
- * pipeline when filling a path are undefined. You should pass
- * the %COGL_TEXTURE_NO_SLICING flag when loading any texture you will
- * use while filling a path.</note>
- *
- * Since: 2.0
- */
-void
-cogl_path_fill (CoglPath *path);
-
-/**
- * cogl_path_stroke:
- *
- * Strokes the constructed shape using the current drawing color and a
- * width of 1 pixel (regardless of the current transformation
- * matrix).
- *
- * Since: 2.0
- */
-void
-cogl_path_stroke (CoglPath *path);
-
 G_END_DECLS
 
 #endif /* __COGL_PATH_H__ */
diff --git a/doc/reference/cogl2/cogl2-sections.txt b/doc/reference/cogl2/cogl2-sections.txt
index baebaa4..9c10d68 100644
--- a/doc/reference/cogl2/cogl2-sections.txt
+++ b/doc/reference/cogl2/cogl2-sections.txt
@@ -285,8 +285,6 @@ cogl_path_ellipse
 CoglPathFillRule
 cogl_path_set_fill_rule
 cogl_path_get_fill_rule
-cogl_path_fill
-cogl_path_stroke
 </SECTION>
 
 <SECTION>
@@ -424,6 +422,8 @@ cogl_framebuffer_draw_textured_rectangle
 cogl_framebuffer_draw_multitextured_rectangle
 cogl_framebuffer_draw_rectangles
 cogl_framebuffer_draw_textured_rectangles
+cogl_framebuffer_stroke_path
+cogl_framebuffer_fill_path
 
 <SUBSECTION>
 cogl_framebuffer_swap_buffers
diff --git a/tests/conform/test-path.c b/tests/conform/test-path.c
index 47dc3af..bf1e267 100644
--- a/tests/conform/test-path.c
+++ b/tests/conform/test-path.c
@@ -15,15 +15,12 @@ typedef struct _TestState
 } TestState;
 
 static void
-draw_path_at (CoglPath *path, int x, int y)
+draw_path_at (CoglPath *path, CoglPipeline *pipeline, int x, int y)
 {
   cogl_framebuffer_push_matrix (test_fb);
   cogl_framebuffer_translate (test_fb, x * BLOCK_SIZE, y * BLOCK_SIZE, 0.0f);
 
-  /* FIXME: we need some cogl_framebuffer_fill_path() api */
-  cogl_push_framebuffer (test_fb);
-  cogl_path_fill (path);
-  cogl_pop_framebuffer ();
+  cogl_framebuffer_fill_path (test_fb, pipeline, path);
 
   cogl_framebuffer_pop_matrix (test_fb);
 }
@@ -83,19 +80,19 @@ paint (TestState *state)
   cogl_path_rectangle (path_a,
                        BLOCK_SIZE / 2, BLOCK_SIZE / 2,
                        BLOCK_SIZE * 3 / 4, BLOCK_SIZE);
-  draw_path_at (path_a, 0, 0);
+  draw_path_at (path_a, white, 0, 0);
 
   /* Create another path filling the whole block */
   path_b = cogl_path_new (test_ctx);
   cogl_path_rectangle (path_b, 0, 0, BLOCK_SIZE, BLOCK_SIZE);
-  draw_path_at (path_b, 1, 0);
+  draw_path_at (path_b, white, 1, 0);
 
   /* Draw the first path again */
-  draw_path_at (path_a, 2, 0);
+  draw_path_at (path_a, white, 2, 0);
 
   /* Draw a copy of path a */
   path_c = cogl_path_copy (path_a);
-  draw_path_at (path_c, 3, 0);
+  draw_path_at (path_c, white, 3, 0);
 
   /* Add another rectangle to path a. We'll use line_to's instead of
      cogl_rectangle so that we don't create another sub-path because
@@ -104,10 +101,10 @@ paint (TestState *state)
   cogl_path_line_to (path_a, 0, 0);
   cogl_path_line_to (path_a, BLOCK_SIZE / 2, 0);
   cogl_path_line_to (path_a, BLOCK_SIZE / 2, BLOCK_SIZE / 2);
-  draw_path_at (path_a, 4, 0);
+  draw_path_at (path_a, white, 4, 0);
 
   /* Draw the copy again. It should not have changed */
-  draw_path_at (path_c, 5, 0);
+  draw_path_at (path_c, white, 5, 0);
 
   /* Add another rectangle to path c. It will be added in two halves,
      one as an extension of the previous path and the other as a new
@@ -118,10 +115,10 @@ paint (TestState *state)
   cogl_path_line_to (path_c, BLOCK_SIZE / 2, BLOCK_SIZE / 2);
   cogl_path_rectangle (path_c,
                        BLOCK_SIZE * 3 / 4, 0, BLOCK_SIZE, BLOCK_SIZE / 2);
-  draw_path_at (path_c, 6, 0);
+  draw_path_at (path_c, white, 6, 0);
 
   /* Draw the original path again. It should not have changed */
-  draw_path_at (path_a, 7, 0);
+  draw_path_at (path_a, white, 7, 0);
 
   cogl_object_unref (path_a);
   cogl_object_unref (path_b);
@@ -135,7 +132,7 @@ paint (TestState *state)
   cogl_path_line_to (path_a, BLOCK_SIZE / 2, BLOCK_SIZE / 2);
   cogl_path_line_to (path_a, BLOCK_SIZE / 2, 0);
   cogl_path_close (path_a);
-  draw_path_at (path_a, 8, 0);
+  draw_path_at (path_a, white, 8, 0);
   cogl_object_unref (path_a);
 
   /* Draw two sub paths. Where the paths intersect it should be
@@ -144,7 +141,7 @@ paint (TestState *state)
   cogl_path_rectangle (path_a, 0, 0, BLOCK_SIZE, BLOCK_SIZE);
   cogl_path_rectangle (path_a,
                        BLOCK_SIZE / 2, BLOCK_SIZE / 2, BLOCK_SIZE, BLOCK_SIZE);
-  draw_path_at (path_a, 9, 0);
+  draw_path_at (path_a, white, 9, 0);
   cogl_object_unref (path_a);
 
   /* Draw a clockwise outer path */
@@ -167,11 +164,11 @@ paint (TestState *state)
   cogl_path_line_to (path_a, BLOCK_SIZE, 0);
   cogl_path_close (path_a);
   /* Retain the path for the next test */
-  draw_path_at (path_a, 10, 0);
+  draw_path_at (path_a, white, 10, 0);
 
   /* Draw the same path again with the other fill rule */
   cogl_path_set_fill_rule (path_a, COGL_PATH_FILL_RULE_NON_ZERO);
-  draw_path_at (path_a, 11, 0);
+  draw_path_at (path_a, white, 11, 0);
 
   cogl_object_unref (path_a);
 }
-- 
1.7.3.16.g9464b



More information about the Cogl mailing list