summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorM Joonas Pihlaja <jpihlaja@cc.helsinki.fi>2009-09-26 18:26:32 +0300
committerM Joonas Pihlaja <jpihlaja@cc.helsinki.fi>2009-09-26 18:26:32 +0300
commit30abaec81d661bf1764388dbb7b8f687bd15f1cd (patch)
tree5543ddf4751878ae41356d44fc57ed371a6a5616
parent5863d97b430c0be36065d27d0694bfdd0247061b (diff)
[XXX] Amalgamate composite rects.wip/tiled-span-renderer
-rw-r--r--src/cairo-tiled-span-renderer.c235
1 files changed, 172 insertions, 63 deletions
diff --git a/src/cairo-tiled-span-renderer.c b/src/cairo-tiled-span-renderer.c
index a6f3517f..2f25b3c4 100644
--- a/src/cairo-tiled-span-renderer.c
+++ b/src/cairo-tiled-span-renderer.c
@@ -3,6 +3,10 @@
#define TILE_WIDTH 32
#define TILE_HEIGHT 32
+#define AMALGAMATE_OPAQUE_COMPOSITE 1
+#define AMALGAMATE_CLEAR_COMPOSITE 1
+#define AMALGAMATE_MASK_COMPOSITE 1
+
#if 0
# define DUMP_SPANS 0
# define dprintf(args) printf args
@@ -25,7 +29,7 @@ typedef union {
struct tile_info {
tile_mark_t mark;
- uint16_t num_pixels;
+ uint16_t num_rows;
};
#define mark_tile_dirty(t) ((t).mark.split.dirty = 1)
@@ -59,8 +63,11 @@ typedef struct _cairo_tiled_span_renderer {
cairo_region_t *clip_region;
- cairo_array_t clear_rects[1];
cairo_bool_t need_to_clear;
+ cairo_array_t clear_rects[1];
+ cairo_array_t opaque_rects[1];
+ cairo_array_t mask_rects[1];
+ cairo_bool_t full_mask_rendering;
cairo_surface_pattern_t mask_pattern;
@@ -77,7 +84,6 @@ fill_dirty_solids (uint8_t *mask_data,
int i, j;
for (i = 0; i < num_tiles; ) {
uint16_t mark = tile_infos[i].mark.full;
- unsigned num_pixels;
unsigned num_rows;
unsigned width;
uint8_t *tile_data;
@@ -87,11 +93,11 @@ fill_dirty_solids (uint8_t *mask_data,
continue;
}
- num_pixels = tile_infos[i].num_pixels;
+ num_rows = tile_infos[i].num_rows;
for (j = i;
j < num_tiles
&& tile_infos[j].mark.full == mark
- && tile_infos[j].num_pixels == num_pixels;
+ && tile_infos[j].num_rows == num_rows;
j++)
{
tile_infos[j].mark.full = DIRTY_MARK;
@@ -99,7 +105,6 @@ fill_dirty_solids (uint8_t *mask_data,
width = TILE_WIDTH * (j-i);
tile_data = mask_data + i*TILE_WIDTH;
- num_rows = num_pixels / TILE_WIDTH;
while (num_rows-- > 0) {
memset (tile_data, mark, width);
tile_data += mask_stride;
@@ -109,6 +114,52 @@ fill_dirty_solids (uint8_t *mask_data,
}
}
+static cairo_status_t
+composite_rectangles_in_region (cairo_tiled_span_renderer_t *renderer,
+ cairo_pattern_t *mask_pattern,
+ int x, int y,
+ cairo_array_t *rects_ary,
+ cairo_region_t *clip_region)
+{
+ cairo_status_t status;
+ const cairo_composite_rectangles_t *composite_rects = &renderer->rects;
+ int num_rects = _cairo_array_size (rects_ary);
+ cairo_region_t *composite_region;
+
+ if (num_rects == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ composite_region = cairo_region_create_rectangles (
+ _cairo_array_index (rects_ary, 0),
+ num_rects);
+ status = cairo_region_status (composite_region);
+ if (unlikely (status))
+ goto unwind;
+
+ if (clip_region != NULL) {
+ status = cairo_region_intersect (composite_region, clip_region);
+ if (unlikely (status))
+ goto unwind;
+ }
+
+ status = _cairo_surface_composite (renderer->op,
+ renderer->src_pattern,
+ mask_pattern,
+ renderer->dst,
+ composite_rects->src.x + x,
+ composite_rects->src.y + y,
+ 0, 0,
+ composite_rects->dst.x + x,
+ composite_rects->dst.y + y,
+ composite_rects->width,
+ composite_rects->height,
+ composite_region);
+
+ unwind:
+ cairo_region_destroy (composite_region);
+ return status;
+}
+
/* Composite all tiles on the current tile row and reset them. The
* tiles occupy rows [top_y, bot_y) of the mask pattern space. */
static cairo_status_t
@@ -130,6 +181,8 @@ composite_tiles (cairo_tiled_span_renderer_t *renderer,
tile_infos,
num_tiles);
+ _cairo_array_truncate (renderer->mask_rects, 0);
+
for (i = 0; i < num_tiles; i = j) {
unsigned width;
uint16_t mark = tile_infos[i].mark.full;
@@ -145,12 +198,12 @@ composite_tiles (cairo_tiled_span_renderer_t *renderer,
width -= tile_x;
if (mark == CLEAR_MARK) {
+ dprintf(("CLEAR %d,%d:%d,%d\n\n",
+ tile_x,
+ tile_y,
+ width, height));
if (renderer->need_to_clear) {
- dprintf(("CLEAR %d,%d:%d,%d\n\n",
- tile_x,
- tile_y,
- width, height));
- if (renderer->clip_region == NULL) {
+ if (renderer->clip_region == NULL && !AMALGAMATE_CLEAR_COMPOSITE) {
status = _cairo_surface_fill_rectangle (renderer->dst,
CAIRO_OPERATOR_CLEAR,
CAIRO_COLOR_TRANSPARENT,
@@ -166,8 +219,6 @@ composite_tiles (cairo_tiled_span_renderer_t *renderer,
r.height = height;
status = _cairo_array_append (renderer->clear_rects, &r);
}
- } else {
- status = CAIRO_STATUS_SUCCESS;
}
}
else if (mark == OPAQUE_MARK) {
@@ -175,40 +226,67 @@ composite_tiles (cairo_tiled_span_renderer_t *renderer,
tile_x,
tile_y,
width, height));
- status = _cairo_surface_composite (renderer->op,
- renderer->src_pattern,
- NULL,
- renderer->dst,
- rects->src.x + tile_x,
- rects->src.y + tile_y,
- 0, 0,
- rects->dst.x + tile_x,
- rects->dst.y + tile_y,
- width,
- height,
- renderer->clip_region);
+ if (!AMALGAMATE_OPAQUE_COMPOSITE) {
+ status = _cairo_surface_composite (renderer->op,
+ renderer->src_pattern,
+ NULL,
+ renderer->dst,
+ rects->src.x + tile_x,
+ rects->src.y + tile_y,
+ 0, 0,
+ rects->dst.x + tile_x,
+ rects->dst.y + tile_y,
+ width,
+ height,
+ renderer->clip_region);
+ } else {
+ cairo_rectangle_int_t r;
+ r.x = rects->dst.x + tile_x;
+ r.y = rects->dst.y + tile_y;
+ r.width = width;
+ r.height = height;
+ status = _cairo_array_append (renderer->opaque_rects, &r);
+ }
}
else {
dprintf(("COMPOSITE %d,%d:%d,%d\n\n",
tile_x,
tile_y,
width, height));
- status = _cairo_surface_composite (renderer->op,
- renderer->src_pattern,
- &renderer->mask_pattern.base,
- renderer->dst,
- rects->src.x + tile_x,
- rects->src.y + tile_y,
- tile_x,
- 0,
- rects->dst.x + tile_x,
- rects->dst.y + tile_y,
- width,
- height,
- renderer->clip_region);
+ if (!AMALGAMATE_MASK_COMPOSITE) {
+ status = _cairo_surface_composite (renderer->op,
+ renderer->src_pattern,
+ &renderer->mask_pattern.base,
+ renderer->dst,
+ rects->src.x + tile_x,
+ rects->src.y + tile_y,
+ tile_x,
+ 0,
+ rects->dst.x + tile_x,
+ rects->dst.y + tile_y,
+ width,
+ height,
+ renderer->clip_region);
+ }
+ else {
+ cairo_rectangle_int_t r;
+ r.x = rects->dst.x + tile_x;
+ r.y = rects->dst.y + tile_y;
+ r.width = width;
+ r.height = height;
+ status = _cairo_array_append (renderer->mask_rects, &r);
+ }
}
}
+ if (AMALGAMATE_MASK_COMPOSITE && status == CAIRO_STATUS_SUCCESS) {
+ status = composite_rectangles_in_region (renderer,
+ &renderer->mask_pattern.base,
+ 0, top_y,
+ renderer->mask_rects,
+ renderer->clip_region);
+ }
+
return status;
}
@@ -227,6 +305,7 @@ flush_tiles (cairo_tiled_span_renderer_t *renderer, unsigned bot_y)
return status;
memset (renderer->tile_infos, 0,
renderer->num_tiles * sizeof(struct tile_info));
+ renderer->full_mask_rendering = FALSE;
}
if (unlikely (renderer->current_y < bot_y)) {
@@ -242,6 +321,7 @@ flush_tiles (cairo_tiled_span_renderer_t *renderer, unsigned bot_y)
return CAIRO_STATUS_SUCCESS;
}
+#if SKIP_EMPTY_SCANS
static void
dirty_empty_rows (cairo_tiled_span_renderer_t *renderer, unsigned to_y)
{
@@ -259,7 +339,7 @@ dirty_empty_rows (cairo_tiled_span_renderer_t *renderer, unsigned to_y)
uint8_t *row;
if (tile_infos[i].mark.full == CLEAR_MARK) {
- tile_infos[i].num_pixels += TILE_WIDTH;
+ tile_infos[i].num_rows++;
j = i + 1;
continue;
}
@@ -279,8 +359,9 @@ dirty_empty_rows (cairo_tiled_span_renderer_t *renderer, unsigned to_y)
}
}
}
+#endif /* SKIP_EMPTY_SCANS */
-static inline void
+static void
render_to_tiles_first_row_span (struct tile_info *tile_infos,
uint8_t *row,
unsigned span_alpha,
@@ -318,7 +399,7 @@ render_to_tiles_first_row_span (struct tile_info *tile_infos,
while (length >= TILE_WIDTH) {
tile_infos[i].mark.full = span_alpha;
- tile_infos[i].num_pixels = TILE_WIDTH;
+ tile_infos[i].num_rows = 1;
tile += TILE_WIDTH;
length -= TILE_WIDTH;
i++;
@@ -394,20 +475,10 @@ render_to_tiles_next_row_spans (
while (start_x < width) {
unsigned thresh_x;
- dprintf(("span [%u,%u] %x\n", start_x, end_x, alpha));
- dprintf(("tile %u %x %d\n",
- tile_i,
- tile_infos[tile_i].mark.full,
- tile_infos[tile_i].num_pixels ));
-
while (tile_infos[tile_i].mark.full == alpha
&& end_x >= start_x + TILE_WIDTH)
{
- dprintf(("tile %u %x %d (cont)\n",
- tile_i,
- tile_infos[tile_i].mark.full,
- tile_infos[tile_i].num_pixels ));
- tile_infos[tile_i++].num_pixels += TILE_WIDTH;
+ tile_infos[tile_i++].num_rows++;
start_x += TILE_WIDTH;
}
@@ -417,13 +488,7 @@ render_to_tiles_next_row_spans (
mark_tile_dirty(tile_infos[tile_i]);
- dprintf(("tile %u %x %d (dirty)\n",
- tile_i,
- tile_infos[tile_i].mark.full,
- tile_infos[tile_i].num_pixels ));
-
while (1) {
- dprintf(("span [%u,%u] %x\n", start_x, end_x, alpha));
if (end_x < thresh_x) {
if (end_x == start_x + 1) {
row[start_x] = alpha;
@@ -462,7 +527,7 @@ render_to_mask_spans (uint8_t *row,
for (i = 0; i < num_spans; i++) {
unsigned end_x = spans[i].x;
-
+
if (end_x == start_x + 1) {
row[start_x] = alpha;
}
@@ -516,6 +581,18 @@ dump_spans(unsigned y,
#endif
}
+static cairo_bool_t
+check_fallback_to_full_mask (const struct tile_info *tile_infos,
+ unsigned num_tiles)
+{
+ unsigned i;
+ cairo_bool_t all_dirty = TRUE;
+ for (i = 0; all_dirty && i < num_tiles; i++) {
+ all_dirty = is_tile_dirty (tile_infos[i]);
+ }
+ return all_dirty;
+}
+
static cairo_status_t
_cairo_tiled_span_renderer_render_row (void *abstract_renderer,
int row_y,
@@ -530,8 +607,10 @@ _cairo_tiled_span_renderer_render_row (void *abstract_re
unsigned tile_y;
uint8_t *row;
+#if SKIP_EMPTY_SCANS
if (unlikely (num_spans == 0))
return CAIRO_STATUS_SUCCESS;
+#endif
if (unlikely (y >= renderer->bot_y)) {
status = flush_tiles (renderer, y);
@@ -539,14 +618,21 @@ _cairo_tiled_span_renderer_render_row (void *abstract_re
return status;
}
+#if SKIP_EMPTY_SCANS
if (unlikely (renderer->current_y < y))
dirty_empty_rows (renderer, y);
+#endif
tile_y = y - renderer->top_y;
row = renderer->mask_first_row + tile_y*renderer->mask_stride;
dump_spans(tile_y, spans, num_spans, rects->width);
+ if (renderer->full_mask_rendering) {
+ render_to_mask_spans (row, spans, num_spans, rects);
+ goto out;
+ }
+
if (likely (tile_y != 0)) {
render_to_tiles_next_row_spans (row,
tile_infos,
@@ -562,6 +648,13 @@ _cairo_tiled_span_renderer_render_row (void *abstract_re
rects);
}
+ if ((tile_y % 4) == 0) {
+ renderer->full_mask_rendering =
+ check_fallback_to_full_mask (tile_infos,
+ renderer->num_tiles);
+ }
+
+ out:
renderer->current_y = y+1;
return CAIRO_STATUS_SUCCESS;
}
@@ -587,9 +680,11 @@ clear_rectangles_in_region (cairo_surface_t *dst,
if (unlikely (status))
goto unwind;
- status = cairo_region_intersect (clear_region, clip_region);
- if (unlikely (status))
- goto unwind;
+ if (clip_region != NULL) {
+ status = cairo_region_intersect (clear_region, clip_region);
+ if (unlikely (status))
+ goto unwind;
+ }
num_rects = cairo_region_num_rectangles (clear_region);
_cairo_array_truncate (rects_ary, 0);
@@ -614,7 +709,6 @@ clear_rectangles_in_region (cairo_surface_t *dst,
return status;
}
-
static cairo_status_t
_cairo_tiled_span_renderer_finish (void *abstract_renderer)
{
@@ -627,6 +721,17 @@ _cairo_tiled_span_renderer_finish (void *abstract_renderer)
status = clear_rectangles_in_region (renderer->dst,
renderer->clear_rects,
renderer->clip_region);
+ if (unlikely (status))
+ goto out;
+
+#if AMALGAMATE_OPAQUE_COMPOSITE
+ status = composite_rectangles_in_region (renderer,
+ NULL,
+ 0, 0,
+ renderer->opaque_rects,
+ renderer->clip_region);
+#endif
+
out:
if (unlikely (status))
return _cairo_span_renderer_set_error (renderer, status);
@@ -645,6 +750,8 @@ _cairo_tiled_span_renderer_destroy (void *abstract_renderer)
cairo_surface_destroy (renderer->mask);
_cairo_array_fini (renderer->clear_rects);
+ _cairo_array_fini (renderer->opaque_rects);
+ _cairo_array_fini (renderer->mask_rects);
cairo_region_destroy (renderer->clip_region);
free (renderer);
@@ -683,6 +790,8 @@ _cairo_tiled_span_renderer_create (cairo_operator_t op,
renderer->clip_region = cairo_region_reference (clip_region);
_cairo_array_init (renderer->clear_rects, sizeof (cairo_rectangle_int_t));
+ _cairo_array_init (renderer->opaque_rects, sizeof (cairo_rectangle_int_t));
+ _cairo_array_init (renderer->mask_rects, sizeof (cairo_rectangle_int_t));
renderer->need_to_clear = ! _cairo_operator_bounded_by_mask (op);
renderer->mask = cairo_image_surface_create (