mirror of
https://github.com/brl/mutter.git
synced 2024-11-10 16:16:20 -05:00
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.
This commit is contained in:
parent
82a30d8e0b
commit
9cba5b83bd
@ -445,9 +445,22 @@ _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;
|
||||
|
||||
_cogl_path_get_bounds (path, &x_1, &y_1, &x_2, &y_2);
|
||||
|
||||
/* 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 = _cogl_clip_stack_push_entry (stack,
|
||||
sizeof (CoglClipStackPath),
|
||||
COGL_CLIP_STACK_PATH);
|
||||
@ -456,13 +469,12 @@ _cogl_clip_stack_push_from_path (CoglClipStack *stack,
|
||||
|
||||
entry->matrix = *modelview_matrix;
|
||||
|
||||
_cogl_path_get_bounds (path, &x_1, &y_1, &x_2, &y_2);
|
||||
|
||||
_cogl_clip_stack_entry_set_bounds ((CoglClipStack *) entry,
|
||||
x_1, y_1, x_2, y_2, modelview_matrix);
|
||||
|
||||
return (CoglClipStack *) entry;
|
||||
}
|
||||
}
|
||||
|
||||
CoglClipStack *
|
||||
_cogl_clip_stack_ref (CoglClipStack *entry)
|
||||
|
@ -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 */
|
||||
|
@ -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,6 +471,19 @@ cogl2_path_fill (CoglPath *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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
framebuffer = _cogl_get_draw_buffer ();
|
||||
|
||||
_cogl_framebuffer_flush_journal (framebuffer);
|
||||
@ -479,6 +497,7 @@ cogl2_path_fill (CoglPath *path)
|
||||
|
||||
_cogl_path_fill_nodes (path);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cogl2_path_stroke (CoglPath *path)
|
||||
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user