aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Möhrmann <martisch@uos.de>2016-04-15 09:38:36 +0200
committerMartin Möhrmann <martisch@uos.de>2016-04-27 06:19:37 +0000
commit102cf2ae0321775eef2d36d7c4258b740fe92458 (patch)
tree929c0445b185dcbe74c625c36b42d4a316d03f89 /src
parent8f2e780e8ac29e47466103998484c0a73df34d51 (diff)
downloadgo-102cf2ae0321775eef2d36d7c4258b740fe92458.tar.xz
image/color: optimize RGBToYCbCr
Apply optimizations used to speed up YCbCrToRGB from https://go-review.googlesource.com/#/c/21910/ to RGBToYCbCr. name old time/op new time/op delta RGBToYCbCr/0-2 6.81ns ± 0% 5.96ns ± 0% -12.48% (p=0.000 n=38+50) RGBToYCbCr/Cb-2 7.68ns ± 0% 6.13ns ± 0% -20.21% (p=0.000 n=50+33) RGBToYCbCr/Cr-2 6.84ns ± 0% 6.04ns ± 0% -11.70% (p=0.000 n=39+42) Updates #15260 Change-Id: If3ea5393ae371a955ddf18ab226aae20b48f9692 Reviewed-on: https://go-review.googlesource.com/22411 Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com> Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ralph Corderoy <ralph@inputplus.co.uk>
Diffstat (limited to 'src')
-rw-r--r--src/image/color/ycbcr.go43
-rw-r--r--src/image/color/ycbcr_test.go29
2 files changed, 53 insertions, 19 deletions
diff --git a/src/image/color/ycbcr.go b/src/image/color/ycbcr.go
index 55549c3fce..3df5d3675d 100644
--- a/src/image/color/ycbcr.go
+++ b/src/image/color/ycbcr.go
@@ -15,24 +15,37 @@ func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
r1 := int32(r)
g1 := int32(g)
b1 := int32(b)
+
+ // yy is in range [0,0xff].
yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16
- cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16
- cr := (32768*r1 - 27440*g1 - 5328*b1 + 257<<15) >> 16
- if yy < 0 {
- yy = 0
- } else if yy > 0xff {
- yy = 0xff
- }
- if cb < 0 {
- cb = 0
- } else if cb > 0xff {
- cb = 0xff
+
+ // The bit twiddling below is equivalent to
+ //
+ // cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16
+ // if cb < 0 {
+ // cb = 0
+ // } else if cb > 0xff {
+ // cb = ^int32(0)
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // Note that the uint8 type conversion in the return
+ // statement will convert ^int32(0) to 0xff.
+ // The code below to compute cr uses a similar pattern.
+ cb := -11056*r1 - 21712*g1 + 32768*b1 + 257<<15
+ if uint32(cb)&0xff000000 == 0 {
+ cb >>= 16
+ } else {
+ cb = ^(cb >> 31)
}
- if cr < 0 {
- cr = 0
- } else if cr > 0xff {
- cr = 0xff
+
+ cr := 32768*r1 - 27440*g1 - 5328*b1 + 257<<15
+ if uint32(cr)&0xff000000 == 0 {
+ cr >>= 16
+ } else {
+ cr = ^(cr >> 31)
}
+
return uint8(yy), uint8(cb), uint8(cr)
}
diff --git a/src/image/color/ycbcr_test.go b/src/image/color/ycbcr_test.go
index 1b110691a2..561699f4e0 100644
--- a/src/image/color/ycbcr_test.go
+++ b/src/image/color/ycbcr_test.go
@@ -172,7 +172,7 @@ func TestPalette(t *testing.T) {
}
}
-var sinkr, sinkg, sinkb uint8
+var sink uint8
func BenchmarkYCbCrToRGB(b *testing.B) {
// YCbCrToRGB does saturating arithmetic.
@@ -180,17 +180,38 @@ func BenchmarkYCbCrToRGB(b *testing.B) {
// different paths through the generated code.
b.Run("0", func(b *testing.B) {
for i := 0; i < b.N; i++ {
- sinkr, sinkg, sinkb = YCbCrToRGB(0, 0, 0)
+ sink, sink, sink = YCbCrToRGB(0, 0, 0)
}
})
b.Run("128", func(b *testing.B) {
for i := 0; i < b.N; i++ {
- sinkr, sinkg, sinkb = YCbCrToRGB(128, 128, 128)
+ sink, sink, sink = YCbCrToRGB(128, 128, 128)
}
})
b.Run("255", func(b *testing.B) {
for i := 0; i < b.N; i++ {
- sinkr, sinkg, sinkb = YCbCrToRGB(255, 255, 255)
+ sink, sink, sink = YCbCrToRGB(255, 255, 255)
+ }
+ })
+}
+
+func BenchmarkRGBToYCbCr(b *testing.B) {
+ // RGBToYCbCr does saturating arithmetic.
+ // Different values can take different paths
+ // through the generated code.
+ b.Run("0", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ sink, sink, sink = RGBToYCbCr(0, 0, 0)
+ }
+ })
+ b.Run("Cb", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ sink, sink, sink = RGBToYCbCr(0, 0, 255)
+ }
+ })
+ b.Run("Cr", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ sink, sink, sink = RGBToYCbCr(255, 0, 0)
}
})
}