Commit f782a7e0 authored by Nigel Tao's avatar Nigel Tao

image/draw: optimize drawFillOver as drawFillSrc for opaque fills.

Benchmarks are much better for opaque fills and slightly worse on non
opaque fills. I think that on balance, this is still a win.

When the source is uniform(color.RGBA{0x11, 0x22, 0x33, 0xff}):
name        old time/op  new time/op  delta
FillOver-8   966µs ± 1%    32µs ± 1%  -96.67%  (p=0.000 n=10+10)
FillSrc-8   32.4µs ± 1%  32.2µs ± 1%     ~      (p=0.053 n=9+10)

When the source is uniform(color.RGBA{0x11, 0x22, 0x33, 0x44}):
name        old time/op  new time/op  delta
FillOver-8   962µs ± 0%  1018µs ± 0%  +5.85%   (p=0.000 n=9+10)
FillSrc-8   32.2µs ± 1%  32.1µs ± 0%    ~     (p=0.148 n=10+10)

Change-Id: I52ec6d5fcd0fbc6710cef0e973a21ee7827c0dd9
Reviewed-on: https://go-review.googlesource.com/28790Reviewed-by: default avatarDavid Crawshaw <crawshaw@golang.org>
parent 06eeea21
...@@ -74,7 +74,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) { ...@@ -74,7 +74,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
var src image.Image var src image.Image
switch scm { switch scm {
case nil: case nil:
src = &image.Uniform{C: color.RGBA{0x11, 0x22, 0x33, 0xff}} src = &image.Uniform{C: color.RGBA{0x11, 0x22, 0x33, 0x44}}
case color.CMYKModel: case color.CMYKModel:
src1 := image.NewCMYK(image.Rect(0, 0, srcw, srch)) src1 := image.NewCMYK(image.Rect(0, 0, srcw, srch))
for y := 0; y < srch; y++ { for y := 0; y < srch; y++ {
......
...@@ -116,7 +116,12 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas ...@@ -116,7 +116,12 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
if mask == nil { if mask == nil {
switch src0 := src.(type) { switch src0 := src.(type) {
case *image.Uniform: case *image.Uniform:
drawFillOver(dst0, r, src0) sr, sg, sb, sa := src0.RGBA()
if sa == 0xffff {
drawFillSrc(dst0, r, sr, sg, sb, sa)
} else {
drawFillOver(dst0, r, sr, sg, sb, sa)
}
return return
case *image.RGBA: case *image.RGBA:
drawCopyOver(dst0, r, src0, sp) drawCopyOver(dst0, r, src0, sp)
...@@ -150,7 +155,8 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas ...@@ -150,7 +155,8 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
if mask == nil { if mask == nil {
switch src0 := src.(type) { switch src0 := src.(type) {
case *image.Uniform: case *image.Uniform:
drawFillSrc(dst0, r, src0) sr, sg, sb, sa := src0.RGBA()
drawFillSrc(dst0, r, sr, sg, sb, sa)
return return
case *image.RGBA: case *image.RGBA:
drawCopySrc(dst0, r, src0, sp) drawCopySrc(dst0, r, src0, sp)
...@@ -232,8 +238,7 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas ...@@ -232,8 +238,7 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
} }
} }
func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform) { func drawFillOver(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
sr, sg, sb, sa := src.RGBA()
// The 0x101 is here for the same reason as in drawRGBA. // The 0x101 is here for the same reason as in drawRGBA.
a := (m - sa) * 0x101 a := (m - sa) * 0x101
i0 := dst.PixOffset(r.Min.X, r.Min.Y) i0 := dst.PixOffset(r.Min.X, r.Min.Y)
...@@ -255,8 +260,7 @@ func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform) { ...@@ -255,8 +260,7 @@ func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
} }
} }
func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.Uniform) { func drawFillSrc(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
sr, sg, sb, sa := src.RGBA()
sr8 := uint8(sr >> 8) sr8 := uint8(sr >> 8)
sg8 := uint8(sg >> 8) sg8 := uint8(sg >> 8)
sb8 := uint8(sb >> 8) sb8 := uint8(sb >> 8)
......
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