Commit b57ccdf9 authored by Ian Davis's avatar Ian Davis Committed by Ian Lance Taylor

image: optimize bounds checking for At and Set methods

Use a subslice of the pixel data to give the compiler hints
for bounds checking. Only do this for image formats that
require 4 or more slice reads/writes.

See #27857 for discussion of small cap sizes.

name                   old time/op    new time/op    delta
At/rgba-8              18.8ns ± 2%    18.5ns ± 1%   -1.49%  (p=0.026 n=10+10)
At/rgba64-8            22.2ns ± 2%    21.1ns ± 3%   -4.51%  (p=0.000 n=10+10)
At/nrgba-8             18.8ns ± 2%    18.7ns ± 2%     ~     (p=0.467 n=10+10)
At/nrgba64-8           21.9ns ± 2%    21.0ns ± 2%   -4.15%  (p=0.000 n=10+9)
At/alpha-8             14.3ns ± 1%    14.3ns ± 2%     ~     (p=0.543 n=10+10)
At/alpha16-8           6.43ns ± 1%    6.47ns ± 1%     ~     (p=0.053 n=10+10)
At/gray-8              14.4ns ± 2%    14.6ns ± 5%     ~     (p=0.194 n=10+10)
At/gray16-8            6.52ns ± 1%    6.55ns ± 2%     ~     (p=0.610 n=10+10)
At/paletted-8          4.17ns ± 1%    4.21ns ± 2%     ~     (p=0.095 n=9+10)
Set/rgba-8             39.2ns ± 2%    40.1ns ± 4%   +2.45%  (p=0.007 n=10+10)
Set/rgba64-8           46.2ns ± 3%    43.3ns ± 3%   -6.11%  (p=0.000 n=10+10)
Set/nrgba-8            39.2ns ± 1%    39.7ns ± 5%     ~     (p=0.407 n=10+10)
Set/nrgba64-8          45.6ns ± 3%    42.9ns ± 3%   -5.83%  (p=0.000 n=9+10)
Set/alpha-8            35.0ns ± 3%    34.1ns ± 2%   -2.43%  (p=0.017 n=10+10)
Set/alpha16-8          36.3ns ± 4%    35.8ns ± 5%     ~     (p=0.254 n=10+10)
Set/gray-8             19.8ns ± 1%    19.7ns ± 0%   -0.69%  (p=0.002 n=8+6)
Set/gray16-8           36.0ns ± 1%    36.4ns ± 2%   +1.08%  (p=0.037 n=10+10)
Set/paletted-8         39.1ns ± 0%    39.6ns ± 1%   +1.30%  (p=0.000 n=10+10)
RGBAAt-8               3.72ns ± 1%    3.58ns ± 1%   -3.76%  (p=0.000 n=9+10)
RGBASetRGBA-8          4.35ns ± 1%    3.70ns ± 1%  -14.92%  (p=0.000 n=10+10)
RGBA64At-8             5.08ns ± 1%    3.69ns ± 1%  -27.40%  (p=0.000 n=9+9)
RGBA64SetRGBA64-8      6.65ns ± 2%    3.63ns ± 0%  -45.35%  (p=0.000 n=10+9)
NRGBAAt-8              3.72ns ± 1%    3.59ns ± 1%   -3.55%  (p=0.000 n=10+10)
NRGBASetNRGBA-8        4.05ns ± 0%    3.71ns ± 1%   -8.57%  (p=0.000 n=9+10)
NRGBA64At-8            4.99ns ± 1%    3.69ns ± 0%  -26.07%  (p=0.000 n=10+9)
NRGBA64SetNRGBA64-8    6.66ns ± 1%    3.64ns ± 1%  -45.40%  (p=0.000 n=10+10)
AlphaAt-8              1.44ns ± 1%    1.44ns ± 0%     ~     (p=0.176 n=10+7)
AlphaSetAlpha-8        1.60ns ± 2%    1.56ns ± 0%   -2.62%  (p=0.000 n=10+6)
Alpha16At-8            2.87ns ± 1%    2.92ns ± 2%   +1.67%  (p=0.001 n=10+10)
AlphaSetAlpha16-8      3.26ns ± 1%    3.35ns ± 1%   +2.68%  (p=0.012 n=8+3)

Fixes #14884

Change-Id: Ia0383530596a550e1b1c7aafce5220e5e0935a53
Reviewed-on: https://go-review.googlesource.com/137495Reviewed-by: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 43cd9070
......@@ -80,7 +80,8 @@ func (p *RGBA) RGBAAt(x, y int) color.RGBA {
return color.RGBA{}
}
i := p.PixOffset(x, y)
return color.RGBA{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
return color.RGBA{s[0], s[1], s[2], s[3]}
}
// PixOffset returns the index of the first element of Pix that corresponds to
......@@ -95,10 +96,11 @@ func (p *RGBA) Set(x, y int, c color.Color) {
}
i := p.PixOffset(x, y)
c1 := color.RGBAModel.Convert(c).(color.RGBA)
p.Pix[i+0] = c1.R
p.Pix[i+1] = c1.G
p.Pix[i+2] = c1.B
p.Pix[i+3] = c1.A
s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
s[0] = c1.R
s[1] = c1.G
s[2] = c1.B
s[3] = c1.A
}
func (p *RGBA) SetRGBA(x, y int, c color.RGBA) {
......@@ -106,10 +108,11 @@ func (p *RGBA) SetRGBA(x, y int, c color.RGBA) {
return
}
i := p.PixOffset(x, y)
p.Pix[i+0] = c.R
p.Pix[i+1] = c.G
p.Pix[i+2] = c.B
p.Pix[i+3] = c.A
s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
s[0] = c.R
s[1] = c.G
s[2] = c.B
s[3] = c.A
}
// SubImage returns an image representing the portion of the image p visible
......@@ -179,11 +182,12 @@ func (p *RGBA64) RGBA64At(x, y int) color.RGBA64 {
return color.RGBA64{}
}
i := p.PixOffset(x, y)
s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
return color.RGBA64{
uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]),
uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]),
uint16(s[0])<<8 | uint16(s[1]),
uint16(s[2])<<8 | uint16(s[3]),
uint16(s[4])<<8 | uint16(s[5]),
uint16(s[6])<<8 | uint16(s[7]),
}
}
......@@ -199,14 +203,15 @@ func (p *RGBA64) Set(x, y int, c color.Color) {
}
i := p.PixOffset(x, y)
c1 := color.RGBA64Model.Convert(c).(color.RGBA64)
p.Pix[i+0] = uint8(c1.R >> 8)
p.Pix[i+1] = uint8(c1.R)
p.Pix[i+2] = uint8(c1.G >> 8)
p.Pix[i+3] = uint8(c1.G)
p.Pix[i+4] = uint8(c1.B >> 8)
p.Pix[i+5] = uint8(c1.B)
p.Pix[i+6] = uint8(c1.A >> 8)
p.Pix[i+7] = uint8(c1.A)
s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
s[0] = uint8(c1.R >> 8)
s[1] = uint8(c1.R)
s[2] = uint8(c1.G >> 8)
s[3] = uint8(c1.G)
s[4] = uint8(c1.B >> 8)
s[5] = uint8(c1.B)
s[6] = uint8(c1.A >> 8)
s[7] = uint8(c1.A)
}
func (p *RGBA64) SetRGBA64(x, y int, c color.RGBA64) {
......@@ -214,14 +219,15 @@ func (p *RGBA64) SetRGBA64(x, y int, c color.RGBA64) {
return
}
i := p.PixOffset(x, y)
p.Pix[i+0] = uint8(c.R >> 8)
p.Pix[i+1] = uint8(c.R)
p.Pix[i+2] = uint8(c.G >> 8)
p.Pix[i+3] = uint8(c.G)
p.Pix[i+4] = uint8(c.B >> 8)
p.Pix[i+5] = uint8(c.B)
p.Pix[i+6] = uint8(c.A >> 8)
p.Pix[i+7] = uint8(c.A)
s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
s[0] = uint8(c.R >> 8)
s[1] = uint8(c.R)
s[2] = uint8(c.G >> 8)
s[3] = uint8(c.G)
s[4] = uint8(c.B >> 8)
s[5] = uint8(c.B)
s[6] = uint8(c.A >> 8)
s[7] = uint8(c.A)
}
// SubImage returns an image representing the portion of the image p visible
......@@ -291,7 +297,8 @@ func (p *NRGBA) NRGBAAt(x, y int) color.NRGBA {
return color.NRGBA{}
}
i := p.PixOffset(x, y)
return color.NRGBA{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
return color.NRGBA{s[0], s[1], s[2], s[3]}
}
// PixOffset returns the index of the first element of Pix that corresponds to
......@@ -306,10 +313,11 @@ func (p *NRGBA) Set(x, y int, c color.Color) {
}
i := p.PixOffset(x, y)
c1 := color.NRGBAModel.Convert(c).(color.NRGBA)
p.Pix[i+0] = c1.R
p.Pix[i+1] = c1.G
p.Pix[i+2] = c1.B
p.Pix[i+3] = c1.A
s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
s[0] = c1.R
s[1] = c1.G
s[2] = c1.B
s[3] = c1.A
}
func (p *NRGBA) SetNRGBA(x, y int, c color.NRGBA) {
......@@ -317,10 +325,11 @@ func (p *NRGBA) SetNRGBA(x, y int, c color.NRGBA) {
return
}
i := p.PixOffset(x, y)
p.Pix[i+0] = c.R
p.Pix[i+1] = c.G
p.Pix[i+2] = c.B
p.Pix[i+3] = c.A
s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
s[0] = c.R
s[1] = c.G
s[2] = c.B
s[3] = c.A
}
// SubImage returns an image representing the portion of the image p visible
......@@ -390,11 +399,12 @@ func (p *NRGBA64) NRGBA64At(x, y int) color.NRGBA64 {
return color.NRGBA64{}
}
i := p.PixOffset(x, y)
s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
return color.NRGBA64{
uint16(p.Pix[i+0])<<8 | uint16(p.Pix[i+1]),
uint16(p.Pix[i+2])<<8 | uint16(p.Pix[i+3]),
uint16(p.Pix[i+4])<<8 | uint16(p.Pix[i+5]),
uint16(p.Pix[i+6])<<8 | uint16(p.Pix[i+7]),
uint16(s[0])<<8 | uint16(s[1]),
uint16(s[2])<<8 | uint16(s[3]),
uint16(s[4])<<8 | uint16(s[5]),
uint16(s[6])<<8 | uint16(s[7]),
}
}
......@@ -410,14 +420,15 @@ func (p *NRGBA64) Set(x, y int, c color.Color) {
}
i := p.PixOffset(x, y)
c1 := color.NRGBA64Model.Convert(c).(color.NRGBA64)
p.Pix[i+0] = uint8(c1.R >> 8)
p.Pix[i+1] = uint8(c1.R)
p.Pix[i+2] = uint8(c1.G >> 8)
p.Pix[i+3] = uint8(c1.G)
p.Pix[i+4] = uint8(c1.B >> 8)
p.Pix[i+5] = uint8(c1.B)
p.Pix[i+6] = uint8(c1.A >> 8)
p.Pix[i+7] = uint8(c1.A)
s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
s[0] = uint8(c1.R >> 8)
s[1] = uint8(c1.R)
s[2] = uint8(c1.G >> 8)
s[3] = uint8(c1.G)
s[4] = uint8(c1.B >> 8)
s[5] = uint8(c1.B)
s[6] = uint8(c1.A >> 8)
s[7] = uint8(c1.A)
}
func (p *NRGBA64) SetNRGBA64(x, y int, c color.NRGBA64) {
......@@ -425,14 +436,15 @@ func (p *NRGBA64) SetNRGBA64(x, y int, c color.NRGBA64) {
return
}
i := p.PixOffset(x, y)
p.Pix[i+0] = uint8(c.R >> 8)
p.Pix[i+1] = uint8(c.R)
p.Pix[i+2] = uint8(c.G >> 8)
p.Pix[i+3] = uint8(c.G)
p.Pix[i+4] = uint8(c.B >> 8)
p.Pix[i+5] = uint8(c.B)
p.Pix[i+6] = uint8(c.A >> 8)
p.Pix[i+7] = uint8(c.A)
s := p.Pix[i : i+8 : i+8] // Small cap improves performance, see https://golang.org/issue/27857
s[0] = uint8(c.R >> 8)
s[1] = uint8(c.R)
s[2] = uint8(c.G >> 8)
s[3] = uint8(c.G)
s[4] = uint8(c.B >> 8)
s[5] = uint8(c.B)
s[6] = uint8(c.A >> 8)
s[7] = uint8(c.A)
}
// SubImage returns an image representing the portion of the image p visible
......@@ -850,7 +862,8 @@ func (p *CMYK) CMYKAt(x, y int) color.CMYK {
return color.CMYK{}
}
i := p.PixOffset(x, y)
return color.CMYK{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
return color.CMYK{s[0], s[1], s[2], s[3]}
}
// PixOffset returns the index of the first element of Pix that corresponds to
......@@ -865,10 +878,11 @@ func (p *CMYK) Set(x, y int, c color.Color) {
}
i := p.PixOffset(x, y)
c1 := color.CMYKModel.Convert(c).(color.CMYK)
p.Pix[i+0] = c1.C
p.Pix[i+1] = c1.M
p.Pix[i+2] = c1.Y
p.Pix[i+3] = c1.K
s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
s[0] = c1.C
s[1] = c1.M
s[2] = c1.Y
s[3] = c1.K
}
func (p *CMYK) SetCMYK(x, y int, c color.CMYK) {
......@@ -876,10 +890,11 @@ func (p *CMYK) SetCMYK(x, y int, c color.CMYK) {
return
}
i := p.PixOffset(x, y)
p.Pix[i+0] = c.C
p.Pix[i+1] = c.M
p.Pix[i+2] = c.Y
p.Pix[i+3] = c.K
s := p.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
s[0] = c.C
s[1] = c.M
s[2] = c.Y
s[3] = c.K
}
// SubImage returns an image representing the portion of the image p visible
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment