mirror of
https://github.com/golang/go
synced 2024-11-24 12:20:17 -07:00
png: speed up opaque RGBA encoding
With Linux/8g on a 2006 Mac Mini (1.66 GHz Intel Core Duo, 2KB L1, 2MB L2, 2G main memory), GOMAXPROCS unset: start: png.BenchmarkEncodePaletted 50 44772820 ns/op png.BenchmarkEncodeRGBOpaque 10 208395900 ns/op png.BenchmarkEncodeRGBA 5 331088000 ns/op remove interface method calls: png.BenchmarkEncodePaletted 50 44722880 ns/op png.BenchmarkEncodeRGBOpaque 10 139042600 ns/op png.BenchmarkEncodeRGBA 5 334033600 ns/op flate inline min/max(): png.BenchmarkEncodePaletted 50 40631180 ns/op png.BenchmarkEncodeRGBOpaque 10 124894900 ns/op png.BenchmarkEncodeRGBA 5 312099000 ns/op after adler change: png.BenchmarkEncodePaletted 50 40181760 ns/op png.BenchmarkEncodeRGBOpaque 20 121781950 ns/op png.BenchmarkEncodeRGBA 5 313890800 ns/op In comparison to 121 ms on this 2006 machine, on my Core2 Duo 2.66 GHz laptop, the final BenchmarkEncodeRGBOpaque runs in 27 ms. (these are all for 640x480 images) R=nigeltao, rsc, r CC=golang-dev https://golang.org/cl/4432077
This commit is contained in:
parent
db16bca18f
commit
437015bbed
@ -143,10 +143,18 @@ func (d *compressor) fillWindow(index int) (int, os.Error) {
|
|||||||
d.blockStart = math.MaxInt32
|
d.blockStart = math.MaxInt32
|
||||||
}
|
}
|
||||||
for i, h := range d.hashHead {
|
for i, h := range d.hashHead {
|
||||||
d.hashHead[i] = max(h-wSize, -1)
|
v := h - wSize
|
||||||
|
if v < -1 {
|
||||||
|
v = -1
|
||||||
|
}
|
||||||
|
d.hashHead[i] = v
|
||||||
}
|
}
|
||||||
for i, h := range d.hashPrev {
|
for i, h := range d.hashPrev {
|
||||||
d.hashPrev[i] = max(h-wSize, -1)
|
v := -h - wSize
|
||||||
|
if v < -1 {
|
||||||
|
v = -1
|
||||||
|
}
|
||||||
|
d.hashPrev[i] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
count, err := d.r.Read(d.window[d.windowEnd:])
|
count, err := d.r.Read(d.window[d.windowEnd:])
|
||||||
@ -177,10 +185,18 @@ func (d *compressor) writeBlock(tokens []token, index int, eof bool) os.Error {
|
|||||||
// Try to find a match starting at index whose length is greater than prevSize.
|
// Try to find a match starting at index whose length is greater than prevSize.
|
||||||
// We only look at chainCount possibilities before giving up.
|
// We only look at chainCount possibilities before giving up.
|
||||||
func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead int) (length, offset int, ok bool) {
|
func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead int) (length, offset int, ok bool) {
|
||||||
win := d.window[0 : pos+min(maxMatchLength, lookahead)]
|
minMatchLook := maxMatchLength
|
||||||
|
if lookahead < minMatchLook {
|
||||||
|
minMatchLook = lookahead
|
||||||
|
}
|
||||||
|
|
||||||
|
win := d.window[0 : pos+minMatchLook]
|
||||||
|
|
||||||
// We quit when we get a match that's at least nice long
|
// We quit when we get a match that's at least nice long
|
||||||
nice := min(d.niceMatch, len(win)-pos)
|
nice := len(win) - pos
|
||||||
|
if d.niceMatch < nice {
|
||||||
|
nice = d.niceMatch
|
||||||
|
}
|
||||||
|
|
||||||
// If we've got a match that's good enough, only look in 1/4 the chain.
|
// If we've got a match that's good enough, only look in 1/4 the chain.
|
||||||
tries := d.maxChainLength
|
tries := d.maxChainLength
|
||||||
@ -344,9 +360,12 @@ Loop:
|
|||||||
}
|
}
|
||||||
prevLength := length
|
prevLength := length
|
||||||
prevOffset := offset
|
prevOffset := offset
|
||||||
minIndex := max(index-maxOffset, 0)
|
|
||||||
length = minMatchLength - 1
|
length = minMatchLength - 1
|
||||||
offset = 0
|
offset = 0
|
||||||
|
minIndex := index - maxOffset
|
||||||
|
if minIndex < 0 {
|
||||||
|
minIndex = 0
|
||||||
|
}
|
||||||
|
|
||||||
if chainHead >= minIndex &&
|
if chainHead >= minIndex &&
|
||||||
(isFastDeflate && lookahead > minMatchLength-1 ||
|
(isFastDeflate && lookahead > minMatchLength-1 ||
|
||||||
|
@ -263,7 +263,12 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
|
|||||||
defer zw.Close()
|
defer zw.Close()
|
||||||
|
|
||||||
bpp := 0 // Bytes per pixel.
|
bpp := 0 // Bytes per pixel.
|
||||||
|
|
||||||
|
// Used by fast paths for common image types
|
||||||
var paletted *image.Paletted
|
var paletted *image.Paletted
|
||||||
|
var rgba *image.RGBA
|
||||||
|
rgba, _ = m.(*image.RGBA)
|
||||||
|
|
||||||
switch cb {
|
switch cb {
|
||||||
case cbG8:
|
case cbG8:
|
||||||
bpp = 1
|
bpp = 1
|
||||||
@ -303,12 +308,24 @@ func writeImage(w io.Writer, m image.Image, cb int) os.Error {
|
|||||||
cr[0][x+1] = c.Y
|
cr[0][x+1] = c.Y
|
||||||
}
|
}
|
||||||
case cbTC8:
|
case cbTC8:
|
||||||
for x := b.Min.X; x < b.Max.X; x++ {
|
// We have previously verified that the alpha value is fully opaque.
|
||||||
// We have previously verified that the alpha value is fully opaque.
|
cr0 := cr[0]
|
||||||
r, g, b, _ := m.At(x, y).RGBA()
|
if rgba != nil {
|
||||||
cr[0][3*x+1] = uint8(r >> 8)
|
yoff := y * rgba.Stride
|
||||||
cr[0][3*x+2] = uint8(g >> 8)
|
xoff := 3*b.Min.X + 1
|
||||||
cr[0][3*x+3] = uint8(b >> 8)
|
for _, color := range rgba.Pix[yoff+b.Min.X : yoff+b.Max.X] {
|
||||||
|
cr0[xoff] = color.R
|
||||||
|
cr0[xoff+1] = color.G
|
||||||
|
cr0[xoff+2] = color.B
|
||||||
|
xoff += 3
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for x := b.Min.X; x < b.Max.X; x++ {
|
||||||
|
r, g, b, _ := m.At(x, y).RGBA()
|
||||||
|
cr0[3*x+1] = uint8(r >> 8)
|
||||||
|
cr0[3*x+2] = uint8(g >> 8)
|
||||||
|
cr0[3*x+3] = uint8(b >> 8)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case cbP8:
|
case cbP8:
|
||||||
rowOffset := y * paletted.Stride
|
rowOffset := y * paletted.Stride
|
||||||
|
Loading…
Reference in New Issue
Block a user