vector: add a fast path for RGBA dst images.

name                      old time/op  new time/op  delta
GlyphRGBA16Over-8         25.1µs ± 2%   6.0µs ± 0%  -76.09%  (p=0.000 n=10+10)
GlyphRGBA16Src-8          17.3µs ± 2%   5.4µs ± 0%  -68.68%  (p=0.000 n=10+10)
GlyphRGBA32Over-8         93.2µs ± 2%  14.5µs ± 0%  -84.41%  (p=0.000 n=10+10)
GlyphRGBA32Src-8          59.3µs ± 2%  12.4µs ± 0%  -79.04%    (p=0.000 n=9+9)
GlyphRGBA64Over-8          350µs ± 2%    45µs ± 0%  -87.21%    (p=0.000 n=9+9)
GlyphRGBA64Src-8           223µs ± 2%    37µs ± 0%  -83.58%    (p=0.000 n=9+9)
GlyphRGBA128Over-8        1.37ms ± 2%  0.16ms ± 1%  -88.19%   (p=0.000 n=9+10)
GlyphRGBA128Src-8          868µs ± 2%   128µs ± 0%  -85.21%   (p=0.000 n=10+9)
GlyphRGBA256Over-8        5.50ms ± 3%  0.59ms ± 0%  -89.31%  (p=0.000 n=10+10)
GlyphRGBA256Src-8         3.47ms ± 2%  0.45ms ± 0%  -86.91%   (p=0.000 n=9+10)

Change-Id: I3df60e6b7147872367715361c9d1ed52951b22e0
Reviewed-on: https://go-review.googlesource.com/29699
Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
Nigel Tao 2016-09-25 13:27:14 +10:00
parent 0080ac3d2c
commit 14bbbc8017

View File

@ -228,7 +228,7 @@ func (z *Rasterizer) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp
// r.Add(sp.Sub(r.Min)). // r.Add(sp.Sub(r.Min)).
if src, ok := src.(*image.Uniform); ok { if src, ok := src.(*image.Uniform); ok {
_, _, _, srcA := src.RGBA() srcR, srcG, srcB, srcA := src.RGBA()
switch dst := dst.(type) { switch dst := dst.(type) {
case *image.Alpha: case *image.Alpha:
// Fast path for glyph rendering. // Fast path for glyph rendering.
@ -240,6 +240,13 @@ func (z *Rasterizer) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp
} }
return return
} }
case *image.RGBA:
if z.DrawOp == draw.Over {
z.rasterizeDstRGBASrcUniformOpOver(dst, r, srcR, srcG, srcB, srcA)
} else {
z.rasterizeDstRGBASrcUniformOpSrc(dst, r, srcR, srcG, srcB, srcA)
}
return
} }
} }
@ -309,6 +316,43 @@ func (z *Rasterizer) rasterizeDstAlphaSrcOpaqueOpSrc(dst *image.Alpha, r image.R
} }
} }
func (z *Rasterizer) rasterizeDstRGBASrcUniformOpOver(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
z.accumulateMask()
pix := dst.Pix[dst.PixOffset(r.Min.X, r.Min.Y):]
for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
ma := z.bufU32[y*z.size.X+x]
// This formula is like rasterizeOpOver's, simplified for the
// concrete dst type and uniform src assumption.
a := 0xffff - (sa * ma / 0xffff)
i := y*dst.Stride + 4*x
pix[i+0] = uint8(((uint32(pix[i+0])*0x101*a + sr*ma) / 0xffff) >> 8)
pix[i+1] = uint8(((uint32(pix[i+1])*0x101*a + sg*ma) / 0xffff) >> 8)
pix[i+2] = uint8(((uint32(pix[i+2])*0x101*a + sb*ma) / 0xffff) >> 8)
pix[i+3] = uint8(((uint32(pix[i+3])*0x101*a + sa*ma) / 0xffff) >> 8)
}
}
}
func (z *Rasterizer) rasterizeDstRGBASrcUniformOpSrc(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
z.accumulateMask()
pix := dst.Pix[dst.PixOffset(r.Min.X, r.Min.Y):]
for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
ma := z.bufU32[y*z.size.X+x]
// This formula is like rasterizeOpSrc's, simplified for the
// concrete dst type and uniform src assumption.
i := y*dst.Stride + 4*x
pix[i+0] = uint8((sr * ma / 0xffff) >> 8)
pix[i+1] = uint8((sg * ma / 0xffff) >> 8)
pix[i+2] = uint8((sb * ma / 0xffff) >> 8)
pix[i+3] = uint8((sa * ma / 0xffff) >> 8)
}
}
}
func (z *Rasterizer) rasterizeOpOver(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) { func (z *Rasterizer) rasterizeOpOver(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
z.accumulateMask() z.accumulateMask()
out := color.RGBA64{} out := color.RGBA64{}