diff options
author | Artyom Pervukhin <artyom.pervukhin@gmail.com> | 2017-10-21 09:36:54 +0300 |
---|---|---|
committer | Nigel Tao <nigeltao@golang.org> | 2017-10-25 23:43:27 +0000 |
commit | 088209bbe870725f82e44e604e787d7273488bd6 (patch) | |
tree | 78c01c9b648a93e6d792a79083f271e1bbc820dc /src/image | |
parent | f2d52519e1fad35566afb46ef521934cf0f5e5fd (diff) | |
download | go-088209bbe870725f82e44e604e787d7273488bd6.tar.gz go-088209bbe870725f82e44e604e787d7273488bd6.zip |
image/draw: reduce drawPaletted allocations for special source cases
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>
Diffstat (limited to 'src/image')
-rw-r--r-- | src/image/draw/draw.go | 14 |
1 files changed, 13 insertions, 1 deletions
diff --git a/src/image/draw/draw.go b/src/image/draw/draw.go index a31dd427ce..f81d791f18 100644 --- a/src/image/draw/draw.go +++ b/src/image/draw/draw.go @@ -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) |