]> Cypherpunks repositories - gostls13.git/commitdiff
jpeg: speed up RGBA encoding ~%50
authorBrad Fitzpatrick <bradfitz@golang.org>
Mon, 2 May 2011 14:26:40 +0000 (07:26 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Mon, 2 May 2011 14:26:40 +0000 (07:26 -0700)
Avoids image.At(), color.RGBA(), opposing 8 bit shifts,
and min function calls in a loop.  Not as pretty as before,
but the pure version is still there to revert back to
later if/when the compiler gets better.

before (best of 5)
jpeg.BenchmarkEncodeRGBOpaque   50   64781360 ns/op   18.97 MB/s

after (best of 5)
jpeg.BenchmarkEncodeRGBOpaque   50   42044300 ns/op   29.23 MB/s

(benchmarked on an HP z600; 16 core Xeon E5520 @ 2.27Ghz)

R=r, r2, nigeltao
CC=golang-dev
https://golang.org/cl/4433088

src/pkg/image/jpeg/writer.go

index 505cce04fb015735ac1eaab1d74615b50d91883c..52b3dc4e2c1a3c474654d4aff6f1f90f48ab5dee 100644 (file)
@@ -391,6 +391,31 @@ func toYCbCr(m image.Image, p image.Point, yBlock, cbBlock, crBlock *block) {
        }
 }
 
+// rgbaToYCbCr is a specialized version of toYCbCr for image.RGBA images.
+func rgbaToYCbCr(m *image.RGBA, p image.Point, yBlock, cbBlock, crBlock *block) {
+       b := m.Bounds()
+       xmax := b.Max.X - 1
+       ymax := b.Max.Y - 1
+       for j := 0; j < 8; j++ {
+               sj := p.Y + j
+               if sj > ymax {
+                       sj = ymax
+               }
+               yoff := sj * m.Stride
+               for i := 0; i < 8; i++ {
+                       sx := p.X + i
+                       if sx > xmax {
+                               sx = xmax
+                       }
+                       col := &m.Pix[yoff+sx]
+                       yy, cb, cr := ycbcr.RGBToYCbCr(col.R, col.G, col.B)
+                       yBlock[8*j+i] = int(yy)
+                       cbBlock[8*j+i] = int(cb)
+                       crBlock[8*j+i] = int(cr)
+               }
+       }
+}
+
 // scale scales the 16x16 region represented by the 4 src blocks to the 8x8
 // dst block.
 func scale(dst *block, src *[4]block) {
@@ -431,13 +456,18 @@ func (e *encoder) writeSOS(m image.Image) {
                prevDCY, prevDCCb, prevDCCr int
        )
        bounds := m.Bounds()
+       rgba, _ := m.(*image.RGBA)
        for y := bounds.Min.Y; y < bounds.Max.Y; y += 16 {
                for x := bounds.Min.X; x < bounds.Max.X; x += 16 {
                        for i := 0; i < 4; i++ {
                                xOff := (i & 1) * 8
                                yOff := (i & 2) * 4
                                p := image.Point{x + xOff, y + yOff}
-                               toYCbCr(m, p, &yBlock, &cbBlock[i], &crBlock[i])
+                               if rgba != nil {
+                                       rgbaToYCbCr(rgba, p, &yBlock, &cbBlock[i], &crBlock[i])
+                               } else {
+                                       toYCbCr(m, p, &yBlock, &cbBlock[i], &crBlock[i])
+                               }
                                prevDCY = e.writeBlock(&yBlock, 0, prevDCY)
                        }
                        scale(&cBlock, &cbBlock)