[Cogl] [PATCH] Replace cogl_path_{stroke, fill} with framebuffer API
Robert Bragg
robert at sixbynine.org
Wed Apr 18 08:46:51 PDT 2012
this looks good to me; thanks.
Reviewed-by: Robert Bragg <robert at linux.intel.com>
On Wed, Apr 18, 2012 at 4:37 PM, Neil Roberts <neil at linux.intel.com> wrote:
> 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
>
> _______________________________________________
> Cogl mailing list
> Cogl at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/cogl
More information about the Cogl
mailing list