mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-08 13:48:02 +02:00
Optimize filling of a path that is a single device-axis-aligned rectangle.
It turns out that this case is extremely common and worth avoiding the overhead of the path iteration and tessellation code. The optimization here works only for device-axis-aligned rectangles It should be possible to generalize this to catch more cases, (such as any convex quadrilateral with 4 or fewer points). This fix results in a 1.4-1.8x speedup for the rectangles perf case: image-rgb rectangles-512 7.80 1.22% -> 4.35 1.62%: 1.79x speedup ▊ image-rgba rectangles-512 7.71 4.77% -> 4.37 0.30%: 1.77x speedup ▊ xlib-rgba rectangles-512 8.78 5.02% -> 5.58 5.54%: 1.57x speedup ▋ xlib-rgb rectangles-512 11.87 2.71% -> 8.75 0.08%: 1.36x speedup ▍ Which conveniently overcomes the ~ 1.3x slowdown we had been seeing for this case since 1.2. Now, compared to 1.2.6 we see only a speedup: image-rgba rectangles-512 6.19 0.29% -> 4.37 0.30%: 1.42x speedup ▎ image-rgb rectangles-512 6.12 1.68% -> 4.35 1.62%: 1.41x speedup ▎ xlib-rgba rectangles-512 7.48 1.07% -> 5.58 5.54%: 1.34x speedup ▏ xlib-rgb rectangles-512 10.35 1.03% -> 8.75 0.08%: 1.18x speedup ▏
This commit is contained in:
parent
e15bb8efe6
commit
aa883123d2
1 changed files with 93 additions and 0 deletions
|
|
@ -35,6 +35,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cairoint.h"
|
#include "cairoint.h"
|
||||||
|
#include "cairo-path-fixed-private.h"
|
||||||
|
|
||||||
typedef struct cairo_filler {
|
typedef struct cairo_filler {
|
||||||
double tolerance;
|
double tolerance;
|
||||||
|
|
@ -169,6 +170,10 @@ _cairo_filler_close_path (void *closure)
|
||||||
return CAIRO_STATUS_SUCCESS;
|
return CAIRO_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cairo_int_status_t
|
||||||
|
_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
|
||||||
|
cairo_traps_t *traps);
|
||||||
|
|
||||||
cairo_status_t
|
cairo_status_t
|
||||||
_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
|
_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
|
||||||
cairo_fill_rule_t fill_rule,
|
cairo_fill_rule_t fill_rule,
|
||||||
|
|
@ -178,6 +183,12 @@ _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
|
||||||
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
cairo_status_t status = CAIRO_STATUS_SUCCESS;
|
||||||
cairo_filler_t filler;
|
cairo_filler_t filler;
|
||||||
|
|
||||||
|
/* Before we do anything else, we use a special-case filler for
|
||||||
|
* a device-axis aligned rectangle if possible. */
|
||||||
|
status = _cairo_path_fixed_fill_rectangle (path, traps);
|
||||||
|
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
||||||
|
return status;
|
||||||
|
|
||||||
_cairo_filler_init (&filler, tolerance, traps);
|
_cairo_filler_init (&filler, tolerance, traps);
|
||||||
|
|
||||||
status = _cairo_path_fixed_interpret (path,
|
status = _cairo_path_fixed_interpret (path,
|
||||||
|
|
@ -205,3 +216,85 @@ BAIL:
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This special-case filler supports only a path that describes a
|
||||||
|
* device-axis aligned rectangle. It exists to avoid the overhead of
|
||||||
|
* the general tessellator when drawing very common rectangles.
|
||||||
|
*
|
||||||
|
* If the path described anything but a device-axis aligned rectangle,
|
||||||
|
* this function will return CAIRO_INT_STATUS_UNSUPPORTED.
|
||||||
|
*/
|
||||||
|
static cairo_int_status_t
|
||||||
|
_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
|
||||||
|
cairo_traps_t *traps)
|
||||||
|
{
|
||||||
|
cairo_path_op_buf_t *op = path->op_buf_head;
|
||||||
|
cairo_path_arg_buf_t *arg = path->arg_buf_head;
|
||||||
|
int final;
|
||||||
|
|
||||||
|
/* Ensure the path has the operators we expect for a rectangular path.
|
||||||
|
*/
|
||||||
|
if (op == NULL || op->num_ops < 5)
|
||||||
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||||
|
|
||||||
|
if (op->op[0] != CAIRO_PATH_OP_MOVE_TO ||
|
||||||
|
op->op[1] != CAIRO_PATH_OP_LINE_TO ||
|
||||||
|
op->op[2] != CAIRO_PATH_OP_LINE_TO ||
|
||||||
|
op->op[3] != CAIRO_PATH_OP_LINE_TO)
|
||||||
|
{
|
||||||
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now, there are choices. The rectangle might end with a LINE_TO
|
||||||
|
* (to the original point), but this isn't required. If it
|
||||||
|
* doesn't, then it must end with a CLOSE_PATH. */
|
||||||
|
if (op->op[4] == CAIRO_PATH_OP_LINE_TO) {
|
||||||
|
if (arg->points[4].x != arg->points[0].x ||
|
||||||
|
arg->points[4].y != arg->points[0].y)
|
||||||
|
{
|
||||||
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
} else if (op->op[4] != CAIRO_PATH_OP_CLOSE_PATH) {
|
||||||
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finally, a trailing CLOSE_PATH or MOVE_TO after the rectangle
|
||||||
|
* is fine. But anything more than that means we must return
|
||||||
|
* unsupported. */
|
||||||
|
final = 5;
|
||||||
|
if (final < op->num_ops &&
|
||||||
|
op->op[final] == CAIRO_PATH_OP_CLOSE_PATH)
|
||||||
|
{
|
||||||
|
final++;
|
||||||
|
}
|
||||||
|
if (final < op->num_ops &&
|
||||||
|
op->op[final] == CAIRO_PATH_OP_MOVE_TO)
|
||||||
|
{
|
||||||
|
final++;
|
||||||
|
}
|
||||||
|
if (final < op->num_ops)
|
||||||
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||||
|
|
||||||
|
/* Now that we've verified the operators, we must ensure that the
|
||||||
|
* path coordinates are consistent with a rectangle. There are two
|
||||||
|
* choices here. */
|
||||||
|
if (arg->points[0].y == arg->points[1].y &&
|
||||||
|
arg->points[1].x == arg->points[2].x &&
|
||||||
|
arg->points[2].y == arg->points[3].y &&
|
||||||
|
arg->points[3].x == arg->points[0].x)
|
||||||
|
{
|
||||||
|
return _cairo_traps_tessellate_convex_quad (traps,
|
||||||
|
arg->points);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg->points[0].x == arg->points[1].x &&
|
||||||
|
arg->points[1].y == arg->points[2].y &&
|
||||||
|
arg->points[2].x == arg->points[3].x &&
|
||||||
|
arg->points[3].y == arg->points[0].y)
|
||||||
|
{
|
||||||
|
return _cairo_traps_tessellate_convex_quad (traps,
|
||||||
|
arg->points);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue