summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeil Roberts <neil@linux.intel.com>2011-03-09 17:46:23 +0000
committerNeil Roberts <neil@linux.intel.com>2011-03-09 18:28:48 +0000
commit9cba5b83bde0857d606d9668ea420b702378d6a8 (patch)
tree8a81d4ef2d2c893515a81d5960d7e1fb1b4a0a12
parent82a30d8e0b4198918086622ecedcbf2ab11a2ab1 (diff)
downloadclutter-9cba5b83bde0857d606d9668ea420b702378d6a8.tar.gz
cogl-path: Optimise paths that are just a rectangle
Drawing and clipping to paths is generally quite expensive because the geometry has to be tessellated into triangles in a single VBO which breaks up the journal batching. If we can detect when the path contains just a single rectangle then we can instead divert to calling cogl_rectangle which will take advantage of the journal, or by pushing a rectangle clip which usually ends up just using the scissor. This patch adds a boolean to each path to mark when it is a rectangle. It gets cleared whenever a node is added or gets set to TRUE whenever cogl2_path_rectangle is called. This doesn't try to catch cases where a rectangle is composed by cogl_path_line_to and cogl_path_move_to commands.
-rw-r--r--clutter/cogl/cogl/cogl-clip-stack.c32
-rw-r--r--clutter/cogl/cogl/cogl-path-private.h11
-rw-r--r--clutter/cogl/cogl/cogl2-path.c55
3 files changed, 79 insertions, 19 deletions
diff --git a/clutter/cogl/cogl/cogl-clip-stack.c b/clutter/cogl/cogl/cogl-clip-stack.c
index c8685d98b..fc8edcaa2 100644
--- a/clutter/cogl/cogl/cogl-clip-stack.c
+++ b/clutter/cogl/cogl/cogl-clip-stack.c
@@ -445,23 +445,35 @@ _cogl_clip_stack_push_from_path (CoglClipStack *stack,
CoglPath *path,
const CoglMatrix *modelview_matrix)
{
- CoglClipStackPath *entry;
float x_1, y_1, x_2, y_2;
- entry = _cogl_clip_stack_push_entry (stack,
- sizeof (CoglClipStackPath),
- COGL_CLIP_STACK_PATH);
+ _cogl_path_get_bounds (path, &x_1, &y_1, &x_2, &y_2);
- entry->path = cogl_path_copy (path);
+ /* If the path is a simple rectangle then we can divert to pushing a
+ rectangle clip instead which usually won't involve the stencil
+ buffer */
+ if (_cogl_path_is_rectangle (path))
+ return _cogl_clip_stack_push_rectangle (stack,
+ x_1, y_1,
+ x_2, y_2,
+ modelview_matrix);
+ else
+ {
+ CoglClipStackPath *entry;
- entry->matrix = *modelview_matrix;
+ entry = _cogl_clip_stack_push_entry (stack,
+ sizeof (CoglClipStackPath),
+ COGL_CLIP_STACK_PATH);
- _cogl_path_get_bounds (path, &x_1, &y_1, &x_2, &y_2);
+ entry->path = cogl_path_copy (path);
- _cogl_clip_stack_entry_set_bounds ((CoglClipStack *) entry,
- x_1, y_1, x_2, y_2, modelview_matrix);
+ entry->matrix = *modelview_matrix;
- return (CoglClipStack *) entry;
+ _cogl_clip_stack_entry_set_bounds ((CoglClipStack *) entry,
+ x_1, y_1, x_2, y_2, modelview_matrix);
+
+ return (CoglClipStack *) entry;
+ }
}
CoglClipStack *
diff --git a/clutter/cogl/cogl/cogl-path-private.h b/clutter/cogl/cogl/cogl-path-private.h
index f3ea62299..dbd23f407 100644
--- a/clutter/cogl/cogl/cogl-path-private.h
+++ b/clutter/cogl/cogl/cogl-path-private.h
@@ -87,6 +87,14 @@ struct _CoglPathData
CoglVertexArray *stroke_vbo;
CoglAttribute **stroke_vbo_attributes;
unsigned int stroke_vbo_n_attributes;
+
+ /* This is used as an optimisation for when the path contains a
+ single contour specified using cogl2_path_rectangle. Cogl is more
+ optimised to handle rectangles than paths so we can detect this
+ case and divert to the journal or a rectangle clip. If it is TRUE
+ then the entire path can be described by calling
+ _cogl_path_get_bounds */
+ gboolean is_rectangle;
};
void
@@ -101,4 +109,7 @@ _cogl_path_get_bounds (CoglPath *path,
float *max_x,
float *max_y);
+gboolean
+_cogl_path_is_rectangle (CoglPath *path);
+
#endif /* __COGL_PATH_PRIVATE_H */
diff --git a/clutter/cogl/cogl/cogl2-path.c b/clutter/cogl/cogl/cogl2-path.c
index f1f0e4532..6b79f75cc 100644
--- a/clutter/cogl/cogl/cogl2-path.c
+++ b/clutter/cogl/cogl/cogl2-path.c
@@ -190,6 +190,11 @@ _cogl_path_add_node (CoglPath *path,
if (y > data->path_nodes_max.y)
data->path_nodes_max.y = y;
}
+
+ /* Once the path nodes have been modified then we'll assume it's no
+ longer a rectangle. cogl2_path_rectangle will set this back to
+ TRUE if this has been called from there */
+ data->is_rectangle = FALSE;
}
static void
@@ -466,18 +471,32 @@ cogl2_path_fill (CoglPath *path)
if (path->data->path_nodes->len == 0)
return;
- framebuffer = _cogl_get_draw_buffer ();
+ /* 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)
+ {
+ float x_1, y_1, x_2, y_2;
- _cogl_framebuffer_flush_journal (framebuffer);
+ _cogl_path_get_bounds (path, &x_1, &y_1, &x_2, &y_2);
+ cogl_rectangle (x_1, y_1, x_2, y_2);
+ }
+ else
+ {
+ framebuffer = _cogl_get_draw_buffer ();
+
+ _cogl_framebuffer_flush_journal (framebuffer);
- /* NB: _cogl_framebuffer_flush_state may disrupt various state (such
- * as the pipeline state) when flushing the clip stack, so should
- * always be done first when preparing to draw. */
- _cogl_framebuffer_flush_state (framebuffer,
- _cogl_get_read_buffer (),
- 0);
+ /* NB: _cogl_framebuffer_flush_state may disrupt various state (such
+ * as the pipeline state) when flushing the clip stack, so should
+ * always be done first when preparing to draw. */
+ _cogl_framebuffer_flush_state (framebuffer,
+ _cogl_get_read_buffer (),
+ 0);
- _cogl_path_fill_nodes (path);
+ _cogl_path_fill_nodes (path);
+ }
}
void
@@ -612,11 +631,28 @@ cogl2_path_rectangle (CoglPath *path,
float x_2,
float y_2)
{
+ gboolean is_rectangle;
+
+ /* If the path was previously empty and the rectangle isn't mirrored
+ then we'll record that this is a simple rectangle path so that we
+ can optimise it */
+ is_rectangle = (path->data->path_nodes->len == 0 &&
+ x_2 >= x_1 &&
+ y_2 >= y_1);
+
cogl2_path_move_to (path, x_1, y_1);
cogl2_path_line_to (path, x_2, y_1);
cogl2_path_line_to (path, x_2, y_2);
cogl2_path_line_to (path, x_1, y_2);
cogl2_path_close (path);
+
+ path->data->is_rectangle = is_rectangle;
+}
+
+gboolean
+_cogl_path_is_rectangle (CoglPath *path)
+{
+ return path->data->is_rectangle;
}
static void
@@ -975,6 +1011,7 @@ cogl2_path_new (void)
data->last_path = 0;
data->fill_vbo = COGL_INVALID_HANDLE;
data->stroke_vbo = NULL;
+ data->is_rectangle = FALSE;
return _cogl_path_object_new (path);
}