From bf18ef3a171cec6ef073487ba3208137a1c236e1 Mon Sep 17 00:00:00 2001 From: Tony Cook Date: Sat, 24 Jan 2015 14:08:40 +1100 Subject: [PATCH] [perl #101682] define i_circle_aa_fill() and use it speeds up smaller circle fills considerably, larger circles are dominated by fill time rather than calculation so lose out --- Imager.pm | 10 ++++- Imager.xs | 8 ++++ bench/circlef.pl | 12 ++++++ draw.c | 108 +++++++++++++++++++++++++++++++++++++++-------- imager.h | 1 + 5 files changed, 120 insertions(+), 19 deletions(-) diff --git a/Imager.pm b/Imager.pm index e6137be8..4ff2d740 100644 --- a/Imager.pm +++ b/Imager.pm @@ -2894,8 +2894,14 @@ sub arc { return; } } - i_arc_aa_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'}, - $opts{'d2'}, $opts{fill}{fill}); + if ($opts{d1} == 0 && $opts{d2} == 361) { + i_circle_aa_fill($self->{IMG}, $opts{'x'}, $opts{'y'}, $opts{'r'}, + $opts{fill}{fill}); + } + else { + i_arc_aa_cfill($self->{IMG},$opts{'x'},$opts{'y'},$opts{'r'},$opts{'d1'}, + $opts{'d2'}, $opts{fill}{fill}); + } } elsif ($opts{filled}) { my $color = _color($opts{'color'}); diff --git a/Imager.xs b/Imager.xs index 470dffb8..6847b02b 100644 --- a/Imager.xs +++ b/Imager.xs @@ -1750,6 +1750,14 @@ i_circle_aa(im,x,y,rad,val) double rad Imager::Color val +void +i_circle_aa_fill(im,x,y,rad,fill) + Imager::ImgRaw im + double x + double y + double rad + Imager::FillHandle fill + int i_circle_out(im,x,y,rad,val) Imager::ImgRaw im diff --git a/bench/circlef.pl b/bench/circlef.pl index 077051ee..5a39a9c6 100644 --- a/bench/circlef.pl +++ b/bench/circlef.pl @@ -90,3 +90,15 @@ small_c_aa: 166.8 /s (0.005993 / iter) small_fill_aa: 9.9 /s (0.101373 / iter) tiny_c_aa: 252.1 /s (0.003967 / iter) tiny_fill_aa: 25.7 /s (0.038897 / iter) + +add i_circle_aa_fill() and use it: + +large_c_aa: 1.1 /s (0.948333 / iter) +large_fill_aa: 0.7 /s (1.500000 / iter) +medium_c_aa: 31.0 /s (0.032303 / iter) +medium_fill_aa: 22.1 /s (0.045175 / iter) +small_c_aa: 223.1 /s (0.004482 / iter) +small_fill_aa: 218.1 /s (0.004585 / iter) +tiny_c_aa: 394.4 /s (0.002536 / iter) +tiny_fill_aa: 437.8 /s (0.002284 / iter) + diff --git a/draw.c b/draw.c index 0aa6bb03..9103c78e 100644 --- a/draw.c +++ b/draw.c @@ -424,6 +424,28 @@ i_arc_aa_cfill(i_img *im, double x, double y, double rad, double d1, double d2, typedef i_img_dim frac; static frac float_to_frac(double x) { return (frac)(0.5+x*16.0); } +typedef void +(*flush_render_t)(i_img *im, i_img_dim l, i_img_dim r, i_img_dim y, const i_sample_t *cover, void *ctx); + +static void +i_circle_aa_low(i_img *im, double x, double y, double rad, flush_render_t r, void *ctx); + +static void +scanline_flush_color(i_img *im, i_img_dim l, i_img_dim y, i_img_dim width, const i_sample_t *cover, void *ctx); + +static void +scanline_flush_fill(i_img *im, i_img_dim l, i_img_dim y, i_img_dim width, const i_sample_t *cover, void *ctx); + +typedef struct { + i_render r; + i_color c; +} flush_color_t; + +typedef struct { + i_render r; + i_fill_t *fill; +} flush_fill_t; + /* =item i_circle_aa(im, x, y, rad, color) @@ -435,21 +457,59 @@ color. =cut */ + void i_circle_aa(i_img *im, double x, double y, double rad, const i_color *val) { + flush_color_t fc; + + fc.c = *val; + i_render_init(&fc.r, im, rad * 2 + 1); + + i_circle_aa_low(im, x, y, rad, scanline_flush_color, &fc); + + i_render_done(&fc.r); +} + +/* +=item i_circle_aa_fill(im, x, y, rad, fill) + +=category Drawing +=synopsis i_circle_aa_fill(im, 50, 50, 45, fill); + +Anti-alias fills a circle centered at (x,y) for radius I with +fill. + +=cut +*/ + +void +i_circle_aa_fill(i_img *im, double x, double y, double rad, i_fill_t *fill) { + flush_fill_t ff; + + ff.fill = fill; + i_render_init(&ff.r, im, rad * 2 + 1); + + i_circle_aa_low(im, x, y, rad, scanline_flush_fill, &ff); + + i_render_done(&ff.r); +} + +static void +i_circle_aa_low(i_img *im, double x, double y, double rad, flush_render_t r, + void *ctx) { i_color temp; i_img_dim ly; dIMCTXim(im); i_img_dim first_row = floor(y) - ceil(rad); i_img_dim last_row = ceil(y) + ceil(rad); double r_sqr = rad * rad; - /*i_img_dim max_width = 2 * ceil(rad); - i_sample_t *coverage = NULL; - size_t coverage_size;*/ + i_img_dim max_width = 2 * ceil(rad) + 1; + unsigned char *coverage = NULL; + size_t coverage_size; int sub; - im_log((aIMCTX, 1, "i_circle_aa(im %p, centre(" i_DFp "), rad %.2f, val %p)\n", - im, i_DFcp(x, y), rad, val)); + im_log((aIMCTX, 1, "i_circle_aa_low(im %p, centre(" i_DFp "), rad %.2f, r %p, ctx %p)\n", + im, i_DFcp(x, y), rad, r, ctx)); if (first_row < 0) first_row = 0; @@ -461,9 +521,8 @@ i_circle_aa(i_img *im, double x, double y, double rad, const i_color *val) { return; } - /* coverage_size = sizeof(i_sample_t) * max_width; - coverage = mymalloc(coverage_size);*/ - + coverage_size = max_width; + coverage = mymalloc(coverage_size); for(ly = first_row; ly < last_row; ly++) { frac min_frac_x[16]; @@ -514,12 +573,13 @@ i_circle_aa(i_img *im, double x, double y, double rad, const i_color *val) { i_img_dim right_solid = min_frac_right_x / 16; i_img_dim work_x; i_img_dim frac_work_x; + i_sample_t *cout = coverage; for (work_x = min_x, frac_work_x = min_x * 16; work_x <= max_x; ++work_x, frac_work_x += 16) { if (work_x <= left_solid || work_x >= right_solid) { - int coverage = 0; + int pix_coverage = 0; int ch; double ratio; i_img_dim frac_work_right = frac_work_x + 16; @@ -533,26 +593,40 @@ i_circle_aa(i_img *im, double x, double y, double rad, const i_color *val) { pix_left = frac_work_x; if (pix_right > frac_work_right) pix_right = frac_work_right; - coverage += pix_right - pix_left; + pix_coverage += pix_right - pix_left; } } - assert(coverage <= 256); - ratio = coverage / 256.0; - i_gpix(im, work_x, ly, &temp); - for(ch=0;chchannels; ch++) - temp.channel[ch] = (unsigned char)((float)val->channel[ch]*ratio + (float)temp.channel[ch]*(1.0-ratio)); - i_ppix(im, work_x, ly, &temp); + assert(pix_coverage <= 256); + *cout++ = pix_coverage * 255 / 256; } else { /* full coverage */ - i_ppix(im, work_x, ly, val); + *cout++ = 255; } } + r(im, min_x, ly, max_x - min_x + 1, coverage, ctx); } } + + myfree(coverage); +} + +static void +scanline_flush_color(i_img *im, i_img_dim x, i_img_dim y, i_img_dim width, const unsigned char *cover, void *ctx) { + flush_color_t *fc = ctx; + + i_render_color(&fc->r, x, y, width, cover, &fc->c); } +static void +scanline_flush_fill(i_img *im, i_img_dim x, i_img_dim y, i_img_dim width, const unsigned char *cover, void *ctx) { + flush_fill_t *ff = ctx; + + i_render_fill(&ff->r, x, y, width, cover, ff->fill); +} + + /* =item i_circle_out(im, x, y, r, col) diff --git a/imager.h b/imager.h index c494044a..0d42826d 100644 --- a/imager.h +++ b/imager.h @@ -128,6 +128,7 @@ void i_arc_aa (i_img *im, double x, double y, double rad, double d1, dou void i_arc_cfill(i_img *im,i_img_dim x,i_img_dim y,double rad,double d1,double d2,i_fill_t *fill); void i_arc_aa_cfill(i_img *im,double x,double y,double rad,double d1,double d2,i_fill_t *fill); void i_circle_aa (i_img *im,double x, double y,double rad,const i_color *val); +void i_circle_aa_fill(i_img *im,double x, double y,double rad,i_fill_t *fill); int i_circle_out (i_img *im,i_img_dim x, i_img_dim y, i_img_dim rad,const i_color *val); int i_circle_out_aa (i_img *im,i_img_dim x, i_img_dim y, i_img_dim rad,const i_color *val); void i_copyto (i_img *im,i_img *src,i_img_dim x1,i_img_dim y1,i_img_dim x2,i_img_dim y2,i_img_dim tx,i_img_dim ty); -- 2.39.5