-
Notifications
You must be signed in to change notification settings - Fork 17.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
image/color: NRGBA(64).RGBA() optimization #11793
Comments
CC @nigeltao |
It might be faster, or it might not: branches may or may not be faster than branch-free-but-redundant arithmetic. Actual data would be useful. |
My benchmark: package main
import (
"image/color"
"testing"
)
func BenchmarkNRGBAToRGBAOpaque(b *testing.B) {
c := color.NRGBA{0xff, 0x80, 0x00, 0xff}
for i := 0; i < b.N; i++ {
c.RGBA()
}
}
func BenchmarkNRGBAToRGBATransparent(b *testing.B) {
c := color.NRGBA{0xff, 0x80, 0x00, 0x00}
for i := 0; i < b.N; i++ {
c.RGBA()
}
}
func BenchmarkNRGBAToRGBATranslucent(b *testing.B) {
c := color.NRGBA{0xff, 0x80, 0x00, 0x80}
for i := 0; i < b.N; i++ {
c.RGBA()
}
}
func BenchmarkNRGBA64ToRGBAOpaque(b *testing.B) {
c := color.NRGBA64{0xffff, 0x8000, 0x0000, 0xffff}
for i := 0; i < b.N; i++ {
c.RGBA()
}
}
func BenchmarkNRGBA64ToRGBATransparent(b *testing.B) {
c := color.NRGBA64{0xffff, 0x8000, 0x0000, 0x0000}
for i := 0; i < b.N; i++ {
c.RGBA()
}
}
func BenchmarkNRGBA64ToRGBATranslucent(b *testing.B) {
c := color.NRGBA64{0xffff, 0x8000, 0x0000, 0x8000}
for i := 0; i < b.N; i++ {
c.RGBA()
}
} Result:
Go version: Go 1.5 beta2 |
Just updated my benchmark with NRGBA & NRGBA64 result. |
Most pixels are probably fully opaque or fully transparent. Still, I might be wrong here, but I would have thought most of the calls to color.NRGBA's RGBA method would be indirect, through the color.Color interface, and once you pull in the overhead of a per-pixel interface method call, the percentage delta will be a lot less dramatic. For example, using the standard library's image/draw package will go through this interface. CC'ing @robpike if he has thoughts on whether this micro-optimization is worth it. |
I believe these two cases are dynamically dominant, so why not? |
OK, I'll make a patch (or take a patch, if you want to cook one up), but please wait until the tree opens after Go 1.5 is released. |
In my benchmark, if I initialize the color with c := color.Color(color.NRGBA64{0xffff, 0x8000, 0x0000, 0xffff}) I get this:
(I'm running this benchmark on a different computer: Virtualbox, Linux, Go 1.5 beta2, Intel(R) Core(TM) i7 CPU 930 @ 2.80GHz) I agree, it's a micro-optimization. |
I agree, it's not high priority.
This could be my first (micro) contribution to Go :) |
Sounds like a great place to start. :) |
New benchmark: added image NRGBA to JPEG (https://raw.githubusercontent.com/pierrre/imageserver/master/testdata/medium.jpg)
benchcmp
old
new
code package main
import (
"image"
"image/color"
"image/draw"
"image/jpeg"
_ "image/jpeg"
_ "image/png"
"io/ioutil"
"os"
"testing"
)
func BenchmarkNRGBAToRGBAOpaque(b *testing.B) {
c := color.NRGBA{0xff, 0x80, 0x00, 0xff}
for i := 0; i < b.N; i++ {
c.RGBA()
}
}
func BenchmarkNRGBAToRGBATransparent(b *testing.B) {
c := color.NRGBA{0xff, 0x80, 0x00, 0x00}
for i := 0; i < b.N; i++ {
c.RGBA()
}
}
func BenchmarkNRGBAToRGBATranslucent(b *testing.B) {
c := color.NRGBA{0xff, 0x80, 0x00, 0x80}
for i := 0; i < b.N; i++ {
c.RGBA()
}
}
func BenchmarkNRGBA64ToRGBAOpaque(b *testing.B) {
c := color.NRGBA64{0xffff, 0x8000, 0x0000, 0xffff}
for i := 0; i < b.N; i++ {
c.RGBA()
}
}
func BenchmarkNRGBA64ToRGBATransparent(b *testing.B) {
c := color.NRGBA64{0xffff, 0x8000, 0x0000, 0x0000}
for i := 0; i < b.N; i++ {
c.RGBA()
}
}
func BenchmarkNRGBA64ToRGBATranslucent(b *testing.B) {
c := color.NRGBA64{0xffff, 0x8000, 0x0000, 0x8000}
for i := 0; i < b.N; i++ {
c.RGBA()
}
}
var (
imNRGBA *image.NRGBA
imNRGBA64 *image.NRGBA64
)
func init() {
f, err := os.Open("/home/pierre/Go/src/github.com/pierrre/imageserver/testdata/medium.jpg")
if err != nil {
panic(err)
}
im, _, err := image.Decode(f)
if err != nil {
panic(err)
}
imNRGBA = image.NewNRGBA(image.Rect(0, 0, im.Bounds().Dx(), im.Bounds().Dy()))
draw.Draw(imNRGBA, imNRGBA.Bounds(), im, im.Bounds().Min, draw.Src)
imNRGBA64 = image.NewNRGBA64(image.Rect(0, 0, im.Bounds().Dx(), im.Bounds().Dy()))
draw.Draw(imNRGBA64, imNRGBA64.Bounds(), im, im.Bounds().Min, draw.Src)
}
func BenchmarkImageNRGBAToJPEG(b *testing.B) {
for i := 0; i < b.N; i++ {
err := jpeg.Encode(ioutil.Discard, imNRGBA, nil)
if err != nil {
b.Fatal(err)
}
}
}
func BenchmarkImageNRGBA64ToJPEG(b *testing.B) {
for i := 0; i < b.N; i++ {
err := jpeg.Encode(ioutil.Discard, imNRGBA64, nil)
if err != nil {
b.Fatal(err)
}
}
} |
If alpha is equal to 0xffff, return r,b,g,a.
If alpha is equal to 0, return 0,0,0,0.
Else, multiply by alpha, divide by 0xffff, return r,g,b,a.
New code:
The text was updated successfully, but these errors were encountered: