diff options
author | M Joonas Pihlaja <jpihlaja@cc.helsinki.fi> | 2009-09-26 18:26:32 +0300 |
---|---|---|
committer | M Joonas Pihlaja <jpihlaja@cc.helsinki.fi> | 2009-09-26 18:26:32 +0300 |
commit | 30abaec81d661bf1764388dbb7b8f687bd15f1cd (patch) | |
tree | 5543ddf4751878ae41356d44fc57ed371a6a5616 | |
parent | 5863d97b430c0be36065d27d0694bfdd0247061b (diff) |
[XXX] Amalgamate composite rects.wip/tiled-span-renderer
-rw-r--r-- | src/cairo-tiled-span-renderer.c | 235 |
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 ( |