From 14bbbc8017cfd5c0ef634ab2d6e90b93bc255600 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Sun, 25 Sep 2016 13:27:14 +1000 Subject: [PATCH] vector: add a fast path for RGBA dst images. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- vector/vector.go | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/vector/vector.go b/vector/vector.go index e11c721..2374995 100644 --- a/vector/vector.go +++ b/vector/vector.go @@ -228,7 +228,7 @@ func (z *Rasterizer) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp // r.Add(sp.Sub(r.Min)). if src, ok := src.(*image.Uniform); ok { - _, _, _, srcA := src.RGBA() + srcR, srcG, srcB, srcA := src.RGBA() switch dst := dst.(type) { case *image.Alpha: // Fast path for glyph rendering. @@ -240,6 +240,13 @@ func (z *Rasterizer) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp } 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) { z.accumulateMask() out := color.RGBA64{}