yy1 := int32(c.Y) * 0x10100 // Convert 0x12 to 0x121200.
cb1 := int32(c.Cb) - 128
cr1 := int32(c.Cr) - 128
- r := (yy1 + 91881*cr1) >> 8
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 8
- b := (yy1 + 116130*cb1) >> 8
- if r < 0 {
- r = 0
- } else if r > 0xffff {
- r = 0xffff
+
+ // The bit twiddling below is equivalent to
+ //
+ // r := (yy1 + 91881*cr1) >> 8
+ // if r < 0 {
+ // r = 0
+ // } else if r > 0xff {
+ // r = 0xffff
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // The code below to compute g and b uses a similar pattern.
+ r := yy1 + 91881*cr1
+ if uint32(r)&0xff000000 == 0 {
+ r >>= 8
+ } else {
+ r = ^(r >> 31) & 0xffff
}
- if g < 0 {
- g = 0
- } else if g > 0xffff {
- g = 0xffff
+
+ g := yy1 - 22554*cb1 - 46802*cr1
+ if uint32(g)&0xff000000 == 0 {
+ g >>= 8
+ } else {
+ g = ^(g >> 31) & 0xffff
}
- if b < 0 {
- b = 0
- } else if b > 0xffff {
- b = 0xffff
+
+ b := yy1 + 116130*cb1
+ if uint32(b)&0xff000000 == 0 {
+ b >>= 8
+ } else {
+ b = ^(b >> 31) & 0xffff
}
+
return uint32(r), uint32(g), uint32(b), 0xffff
}
yy1 := int32(c.Y) * 0x10100 // Convert 0x12 to 0x121200.
cb1 := int32(c.Cb) - 128
cr1 := int32(c.Cr) - 128
- r := (yy1 + 91881*cr1) >> 8
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 8
- b := (yy1 + 116130*cb1) >> 8
- if r < 0 {
- r = 0
- } else if r > 0xffff {
- r = 0xffff
+
+ // The bit twiddling below is equivalent to
+ //
+ // r := (yy1 + 91881*cr1) >> 8
+ // if r < 0 {
+ // r = 0
+ // } else if r > 0xff {
+ // r = 0xffff
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // The code below to compute g and b uses a similar pattern.
+ r := yy1 + 91881*cr1
+ if uint32(r)&0xff000000 == 0 {
+ r >>= 8
+ } else {
+ r = ^(r >> 31) & 0xffff
}
- if g < 0 {
- g = 0
- } else if g > 0xffff {
- g = 0xffff
+
+ g := yy1 - 22554*cb1 - 46802*cr1
+ if uint32(g)&0xff000000 == 0 {
+ g >>= 8
+ } else {
+ g = ^(g >> 31) & 0xffff
}
- if b < 0 {
- b = 0
- } else if b > 0xffff {
- b = 0xffff
+
+ b := yy1 + 116130*cb1
+ if uint32(b)&0xff000000 == 0 {
+ b >>= 8
+ } else {
+ b = ^(b >> 31) & 0xffff
}
// The second part of this method applies the alpha.
}
}
-var sink uint8
+var sink8 uint8
+var sink32 uint32
func BenchmarkYCbCrToRGB(b *testing.B) {
// YCbCrToRGB does saturating arithmetic.
// different paths through the generated code.
b.Run("0", func(b *testing.B) {
for i := 0; i < b.N; i++ {
- sink, sink, sink = YCbCrToRGB(0, 0, 0)
+ sink8, sink8, sink8 = YCbCrToRGB(0, 0, 0)
}
})
b.Run("128", func(b *testing.B) {
for i := 0; i < b.N; i++ {
- sink, sink, sink = YCbCrToRGB(128, 128, 128)
+ sink8, sink8, sink8 = YCbCrToRGB(128, 128, 128)
}
})
b.Run("255", func(b *testing.B) {
for i := 0; i < b.N; i++ {
- sink, sink, sink = YCbCrToRGB(255, 255, 255)
+ sink8, sink8, sink8 = YCbCrToRGB(255, 255, 255)
}
})
}
// 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)
+ sink8, sink8, sink8 = 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)
+ sink8, sink8, sink8 = 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)
+ sink8, sink8, sink8 = RGBToYCbCr(255, 0, 0)
+ }
+ })
+}
+
+func BenchmarkYCbCrToRGBA(b *testing.B) {
+ // RGB does saturating arithmetic.
+ // Low, middle, and high values can take
+ // different paths through the generated code.
+ b.Run("0", func(b *testing.B) {
+ c := YCbCr{0, 0, 0}
+ for i := 0; i < b.N; i++ {
+ sink32, sink32, sink32, sink32 = c.RGBA()
+ }
+ })
+ b.Run("128", func(b *testing.B) {
+ c := YCbCr{128, 128, 128}
+ for i := 0; i < b.N; i++ {
+ sink32, sink32, sink32, sink32 = c.RGBA()
+ }
+ })
+ b.Run("255", func(b *testing.B) {
+ c := YCbCr{255, 255, 255}
+ for i := 0; i < b.N; i++ {
+ sink32, sink32, sink32, sink32 = c.RGBA()
+ }
+ })
+}
+
+func BenchmarkNYCbCrAToRGBA(b *testing.B) {
+ // RGBA does saturating arithmetic.
+ // Low, middle, and high values can take
+ // different paths through the generated code.
+ b.Run("0", func(b *testing.B) {
+ c := NYCbCrA{YCbCr{0, 0, 0}, 0xff}
+ for i := 0; i < b.N; i++ {
+ sink32, sink32, sink32, sink32 = c.RGBA()
+ }
+ })
+ b.Run("128", func(b *testing.B) {
+ c := NYCbCrA{YCbCr{128, 128, 128}, 0xff}
+ for i := 0; i < b.N; i++ {
+ sink32, sink32, sink32, sink32 = c.RGBA()
+ }
+ })
+ b.Run("255", func(b *testing.B) {
+ c := NYCbCrA{YCbCr{255, 255, 255}, 0xff}
+ for i := 0; i < b.N; i++ {
+ sink32, sink32, sink32, sink32 = c.RGBA()
}
})
}