]> Cypherpunks repositories - gostls13.git/commitdiff
image/draw: reduce drawPaletted allocations for special source cases
authorArtyom Pervukhin <artyom.pervukhin@gmail.com>
Sat, 21 Oct 2017 06:36:54 +0000 (09:36 +0300)
committerNigel Tao <nigeltao@golang.org>
Wed, 25 Oct 2017 23:43:27 +0000 (23:43 +0000)
drawPaletted has to discover R,G,B,A color values of each source image
pixel in a given rectangle. Doing that by calling image.Image.At()
method returning color.Color interface is quite taxing allocation-wise
since interface values go through heap. Introduce special cases for some
concrete source types by fetching color values using type-specific
methods.

name        old time/op    new time/op    delta
Paletted-4    7.62ms ± 4%    3.72ms ± 3%   -51.20%  (p=0.008 n=5+5)

name        old alloc/op   new alloc/op   delta
Paletted-4     480kB ± 0%       0kB ± 0%   -99.99%  (p=0.000 n=4+5)

name        old allocs/op  new allocs/op  delta
Paletted-4      120k ± 0%        0k ± 0%  -100.00%  (p=0.008 n=5+5)

Updates #15759.

Change-Id: I0ce1770ff600ac80599541aaad4c2c826855c8fb
Reviewed-on: https://go-review.googlesource.com/72370
Reviewed-by: Nigel Tao <nigeltao@golang.org>
src/image/draw/draw.go

index a31dd427ce1fd947810f1db452832be2192d43ee..f81d791f185c45f505ce580a0f7cf20b0ab253e7 100644 (file)
@@ -603,6 +603,18 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
                quantErrorCurr = make([][4]int32, r.Dx()+2)
                quantErrorNext = make([][4]int32, r.Dx()+2)
        }
+       pxRGBA := func(x, y int) (r, g, b, a uint32) { return src.At(x, y).RGBA() }
+       // Fast paths for special cases to avoid excessive use of the color.Color
+       // interface which escapes to the heap but need to be discovered for
+       // each pixel on r. See also https://golang.org/issues/15759.
+       switch src0 := src.(type) {
+       case *image.RGBA:
+               pxRGBA = func(x, y int) (r, g, b, a uint32) { return src0.RGBAAt(x, y).RGBA() }
+       case *image.NRGBA:
+               pxRGBA = func(x, y int) (r, g, b, a uint32) { return src0.NRGBAAt(x, y).RGBA() }
+       case *image.YCbCr:
+               pxRGBA = func(x, y int) (r, g, b, a uint32) { return src0.YCbCrAt(x, y).RGBA() }
+       }
 
        // Loop over each source pixel.
        out := color.RGBA64{A: 0xffff}
@@ -610,7 +622,7 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
                for x := 0; x != r.Dx(); x++ {
                        // er, eg and eb are the pixel's R,G,B values plus the
                        // optional Floyd-Steinberg error.
-                       sr, sg, sb, sa := src.At(sp.X+x, sp.Y+y).RGBA()
+                       sr, sg, sb, sa := pxRGBA(sp.X+x, sp.Y+y)
                        er, eg, eb, ea := int32(sr), int32(sg), int32(sb), int32(sa)
                        if floydSteinberg {
                                er = clamp(er + quantErrorCurr[x+1][0]/16)