mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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/137495 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
43cd907017
commit
b57ccdf992
1 changed files with 82 additions and 67 deletions
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue