mirror of
https://github.com/golang/go
synced 2024-11-05 18:36:08 +00:00
image/draw: optimize bounds checks in loops
Use subslices with known length and cap to give bounds checking hints to the compiler. Improves over the earlier pointer based optimizations in https://go-review.googlesource.com/c/go/+/14093 for GlyphOver but not for FillOver so the latter is left unchanged. See #27857 for discussion of small caps used in subslices. name old time/op new time/op delta FillOver-8 607µs ± 1% 609µs ± 1% ~ (p=0.447 n=9+10) FillSrc-8 23.0µs ± 1% 22.9µs ± 2% ~ (p=0.412 n=9+10) CopyOver-8 647µs ± 0% 560µs ± 0% -13.43% (p=0.000 n=9+10) CopySrc-8 19.3µs ± 1% 19.1µs ± 2% -0.66% (p=0.029 n=10+10) NRGBAOver-8 697µs ± 1% 651µs ± 1% -6.64% (p=0.000 n=10+10) NRGBASrc-8 405µs ± 1% 347µs ± 0% -14.23% (p=0.000 n=10+10) YCbCr-8 432µs ± 2% 431µs ± 1% ~ (p=0.764 n=10+9) Gray-8 164µs ± 1% 139µs ± 1% -15.44% (p=0.000 n=10+10) CMYK-8 498µs ± 0% 461µs ± 0% -7.49% (p=0.000 n=10+9) GlyphOver-8 220µs ± 0% 199µs ± 0% -9.52% (p=0.000 n=9+10) RGBA-8 3.81ms ± 5% 3.79ms ± 5% ~ (p=0.549 n=9+10) Paletted-8 1.73ms ± 0% 1.73ms ± 1% ~ (p=0.278 n=10+9) GenericOver-8 11.0ms ± 2% 11.0ms ± 1% ~ (p=0.842 n=9+10) GenericMaskOver-8 5.29ms ± 1% 5.30ms ± 0% ~ (p=0.182 n=9+10) GenericSrc-8 4.24ms ± 1% 4.24ms ± 0% ~ (p=0.436 n=9+9) GenericMaskSrc-8 7.89ms ± 1% 7.90ms ± 2% ~ (p=0.631 n=10+10) Change-Id: I6fe1b21bb5e255826cbfdd2e73efd5858cd5557c Reviewed-on: https://go-review.googlesource.com/136935 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
e945623930
commit
5bba505367
1 changed files with 61 additions and 61 deletions
|
@ -309,23 +309,20 @@ func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.
|
|||
dpix := dst.Pix[d0:]
|
||||
spix := src.Pix[s0:]
|
||||
for i := i0; i != i1; i += idelta {
|
||||
sr := uint32(spix[i+0]) * 0x101
|
||||
sg := uint32(spix[i+1]) * 0x101
|
||||
sb := uint32(spix[i+2]) * 0x101
|
||||
sa := uint32(spix[i+3]) * 0x101
|
||||
|
||||
dr := &dpix[i+0]
|
||||
dg := &dpix[i+1]
|
||||
db := &dpix[i+2]
|
||||
da := &dpix[i+3]
|
||||
s := spix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
sr := uint32(s[0]) * 0x101
|
||||
sg := uint32(s[1]) * 0x101
|
||||
sb := uint32(s[2]) * 0x101
|
||||
sa := uint32(s[3]) * 0x101
|
||||
|
||||
// The 0x101 is here for the same reason as in drawRGBA.
|
||||
a := (m - sa) * 0x101
|
||||
|
||||
*dr = uint8((uint32(*dr)*a/m + sr) >> 8)
|
||||
*dg = uint8((uint32(*dg)*a/m + sg) >> 8)
|
||||
*db = uint8((uint32(*db)*a/m + sb) >> 8)
|
||||
*da = uint8((uint32(*da)*a/m + sa) >> 8)
|
||||
d := dpix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
d[0] = uint8((uint32(d[0])*a/m + sr) >> 8)
|
||||
d[1] = uint8((uint32(d[1])*a/m + sg) >> 8)
|
||||
d[2] = uint8((uint32(d[2])*a/m + sb) >> 8)
|
||||
d[3] = uint8((uint32(d[3])*a/m + sa) >> 8)
|
||||
}
|
||||
d0 += ddelta
|
||||
s0 += sdelta
|
||||
|
@ -372,23 +369,25 @@ func drawNRGBAOver(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp imag
|
|||
|
||||
for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
|
||||
// Convert from non-premultiplied color to pre-multiplied color.
|
||||
sa := uint32(spix[si+3]) * 0x101
|
||||
sr := uint32(spix[si+0]) * sa / 0xff
|
||||
sg := uint32(spix[si+1]) * sa / 0xff
|
||||
sb := uint32(spix[si+2]) * sa / 0xff
|
||||
s := spix[si : si+4 : si+4] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
sa := uint32(s[3]) * 0x101
|
||||
sr := uint32(s[0]) * sa / 0xff
|
||||
sg := uint32(s[1]) * sa / 0xff
|
||||
sb := uint32(s[2]) * sa / 0xff
|
||||
|
||||
dr := uint32(dpix[i+0])
|
||||
dg := uint32(dpix[i+1])
|
||||
db := uint32(dpix[i+2])
|
||||
da := uint32(dpix[i+3])
|
||||
d := dpix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
dr := uint32(d[0])
|
||||
dg := uint32(d[1])
|
||||
db := uint32(d[2])
|
||||
da := uint32(d[3])
|
||||
|
||||
// The 0x101 is here for the same reason as in drawRGBA.
|
||||
a := (m - sa) * 0x101
|
||||
|
||||
dpix[i+0] = uint8((dr*a/m + sr) >> 8)
|
||||
dpix[i+1] = uint8((dg*a/m + sg) >> 8)
|
||||
dpix[i+2] = uint8((db*a/m + sb) >> 8)
|
||||
dpix[i+3] = uint8((da*a/m + sa) >> 8)
|
||||
d[0] = uint8((dr*a/m + sr) >> 8)
|
||||
d[1] = uint8((dg*a/m + sg) >> 8)
|
||||
d[2] = uint8((db*a/m + sb) >> 8)
|
||||
d[3] = uint8((da*a/m + sa) >> 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -407,15 +406,17 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image
|
|||
|
||||
for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
|
||||
// Convert from non-premultiplied color to pre-multiplied color.
|
||||
sa := uint32(spix[si+3]) * 0x101
|
||||
sr := uint32(spix[si+0]) * sa / 0xff
|
||||
sg := uint32(spix[si+1]) * sa / 0xff
|
||||
sb := uint32(spix[si+2]) * sa / 0xff
|
||||
s := spix[si : si+4 : si+4] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
sa := uint32(s[3]) * 0x101
|
||||
sr := uint32(s[0]) * sa / 0xff
|
||||
sg := uint32(s[1]) * sa / 0xff
|
||||
sb := uint32(s[2]) * sa / 0xff
|
||||
|
||||
dpix[i+0] = uint8(sr >> 8)
|
||||
dpix[i+1] = uint8(sg >> 8)
|
||||
dpix[i+2] = uint8(sb >> 8)
|
||||
dpix[i+3] = uint8(sa >> 8)
|
||||
d := dpix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
d[0] = uint8(sr >> 8)
|
||||
d[1] = uint8(sg >> 8)
|
||||
d[2] = uint8(sb >> 8)
|
||||
d[3] = uint8(sa >> 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -434,10 +435,11 @@ func drawGray(dst *image.RGBA, r image.Rectangle, src *image.Gray, sp image.Poin
|
|||
|
||||
for i, si := i0, si0; i < i1; i, si = i+4, si+1 {
|
||||
p := spix[si]
|
||||
dpix[i+0] = p
|
||||
dpix[i+1] = p
|
||||
dpix[i+2] = p
|
||||
dpix[i+3] = 255
|
||||
d := dpix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
d[0] = p
|
||||
d[1] = p
|
||||
d[2] = p
|
||||
d[3] = 255
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -455,9 +457,10 @@ func drawCMYK(dst *image.RGBA, r image.Rectangle, src *image.CMYK, sp image.Poin
|
|||
spix := src.Pix[sy*src.Stride:]
|
||||
|
||||
for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
|
||||
dpix[i+0], dpix[i+1], dpix[i+2] =
|
||||
color.CMYKToRGB(spix[si+0], spix[si+1], spix[si+2], spix[si+3])
|
||||
dpix[i+3] = 255
|
||||
s := spix[si : si+4 : si+4] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
d := dpix[i : i+4 : i+4]
|
||||
d[0], d[1], d[2] = color.CMYKToRGB(s[0], s[1], s[2], s[3])
|
||||
d[3] = 255
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -475,18 +478,14 @@ func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask
|
|||
}
|
||||
ma |= ma << 8
|
||||
|
||||
dr := &dst.Pix[i+0]
|
||||
dg := &dst.Pix[i+1]
|
||||
db := &dst.Pix[i+2]
|
||||
da := &dst.Pix[i+3]
|
||||
|
||||
// The 0x101 is here for the same reason as in drawRGBA.
|
||||
a := (m - (sa * ma / m)) * 0x101
|
||||
|
||||
*dr = uint8((uint32(*dr)*a + sr*ma) / m >> 8)
|
||||
*dg = uint8((uint32(*dg)*a + sg*ma) / m >> 8)
|
||||
*db = uint8((uint32(*db)*a + sb*ma) / m >> 8)
|
||||
*da = uint8((uint32(*da)*a + sa*ma) / m >> 8)
|
||||
d := dst.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
d[0] = uint8((uint32(d[0])*a + sr*ma) / m >> 8)
|
||||
d[1] = uint8((uint32(d[1])*a + sg*ma) / m >> 8)
|
||||
d[2] = uint8((uint32(d[2])*a + sb*ma) / m >> 8)
|
||||
d[3] = uint8((uint32(d[3])*a + sa*ma) / m >> 8)
|
||||
}
|
||||
i0 += dst.Stride
|
||||
i1 += dst.Stride
|
||||
|
@ -518,11 +517,12 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin
|
|||
_, _, _, ma = mask.At(mx, my).RGBA()
|
||||
}
|
||||
sr, sg, sb, sa := src.At(sx, sy).RGBA()
|
||||
d := dst.Pix[i : i+4 : i+4] // Small cap improves performance, see https://golang.org/issue/27857
|
||||
if op == Over {
|
||||
dr := uint32(dst.Pix[i+0])
|
||||
dg := uint32(dst.Pix[i+1])
|
||||
db := uint32(dst.Pix[i+2])
|
||||
da := uint32(dst.Pix[i+3])
|
||||
dr := uint32(d[0])
|
||||
dg := uint32(d[1])
|
||||
db := uint32(d[2])
|
||||
da := uint32(d[3])
|
||||
|
||||
// dr, dg, db and da are all 8-bit color at the moment, ranging in [0,255].
|
||||
// We work in 16-bit color, and so would normally do:
|
||||
|
@ -532,16 +532,16 @@ func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Poin
|
|||
// This yields the same result, but is fewer arithmetic operations.
|
||||
a := (m - (sa * ma / m)) * 0x101
|
||||
|
||||
dst.Pix[i+0] = uint8((dr*a + sr*ma) / m >> 8)
|
||||
dst.Pix[i+1] = uint8((dg*a + sg*ma) / m >> 8)
|
||||
dst.Pix[i+2] = uint8((db*a + sb*ma) / m >> 8)
|
||||
dst.Pix[i+3] = uint8((da*a + sa*ma) / m >> 8)
|
||||
d[0] = uint8((dr*a + sr*ma) / m >> 8)
|
||||
d[1] = uint8((dg*a + sg*ma) / m >> 8)
|
||||
d[2] = uint8((db*a + sb*ma) / m >> 8)
|
||||
d[3] = uint8((da*a + sa*ma) / m >> 8)
|
||||
|
||||
} else {
|
||||
dst.Pix[i+0] = uint8(sr * ma / m >> 8)
|
||||
dst.Pix[i+1] = uint8(sg * ma / m >> 8)
|
||||
dst.Pix[i+2] = uint8(sb * ma / m >> 8)
|
||||
dst.Pix[i+3] = uint8(sa * ma / m >> 8)
|
||||
d[0] = uint8(sr * ma / m >> 8)
|
||||
d[1] = uint8(sg * ma / m >> 8)
|
||||
d[2] = uint8(sb * ma / m >> 8)
|
||||
d[3] = uint8(sa * ma / m >> 8)
|
||||
}
|
||||
}
|
||||
i0 += dy * dst.Stride
|
||||
|
|
Loading…
Reference in a new issue