From 27097612559b61f36a88f87647848bf2014fa85c Mon Sep 17 00:00:00 2001 From: "Sascha L. Teichmann" Date: Sat, 20 Sep 2014 23:53:09 +0200 Subject: [PATCH] mtwebmapper: Added fast path for rendering RGBA sub base level tiles. Up to 5-10x faster. --- cmd/mtwebmapper/subbaseline.go | 79 ++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 12 deletions(-) diff --git a/cmd/mtwebmapper/subbaseline.go b/cmd/mtwebmapper/subbaseline.go index f28e033..4260d65 100644 --- a/cmd/mtwebmapper/subbaseline.go +++ b/cmd/mtwebmapper/subbaseline.go @@ -7,7 +7,6 @@ package main import ( "fmt" "image" - "image/color" "image/png" "log" "net/http" @@ -105,7 +104,56 @@ func (sb *subBaseLine) ServeHTTP(rw http.ResponseWriter, r *http.Request) { func blowUp(src image.Image) *image.RGBA { - // TODO: Fast path for image.RGBA + // Fast path for RGBA -> RGBA + if rgba, ok := src.(*image.RGBA); ok { + return blowUpRGBA(rgba) + } + + // Fallback + dst := image.NewRGBA(image.Rect(0, 0, 256, 256)) + + // fix point numbers x:8 + dx, dy := src.Bounds().Dx(), src.Bounds().Dy() + + bx, by := src.Bounds().Min.X<<8, src.Bounds().Min.Y<<8 + + //start := time.Now() + + pix := dst.Pix + + lineOfs := dst.PixOffset(0, 0) // Should be 0. + + py := by + var r, g, b, a uint8 + for y := 0; y < 256; y++ { + sy := (py >> 8) & 0xff + ox := -1 + px := bx + ofs := lineOfs // Should not really b needed + lineOfs += dst.Stride + for x := 0; x < 256; x++ { + sx := (px >> 8) & 0xff + if sx != ox { // Minimize interface indirection access. + ox = sx + xr, xg, xb, xa := src.At(sx, sy).RGBA() + r, g, b, a = uint8(xr), uint8(xg), uint8(xb), uint8(xa) + } + pix[ofs] = r + pix[ofs+1] = g + pix[ofs+2] = b + pix[ofs+3] = a + ofs += 4 + px += dx + } + py += dy + } + + //log.Printf("Rendering took: %s", time.Since(start)) + + return dst +} + +func blowUpRGBA(src *image.RGBA) *image.RGBA { dst := image.NewRGBA(image.Rect(0, 0, 256, 256)) @@ -114,24 +162,31 @@ func blowUp(src image.Image) *image.RGBA { bx, by := src.Bounds().Min.X<<8, src.Bounds().Min.Y<<8 + //start := time.Now() + + sPix := src.Pix + dPix := dst.Pix + py := by - for y := 0; y < 256; y++ { + // Assuming memory layout is packed 256*256*4 with stride of 4*256. + // for dLineOfs, dEnd := dst.PixOffset(0, 0), dst.PixOffset(0, 256); dLineOfs < dEnd; dLineOfs += dst.Stride { + for ofs := 0; ofs < 256*256*4; { sy := (py >> 8) & 0xff - ox := -1 + sLineOfs := src.PixOffset(0, sy) px := bx - var col color.Color - for x := 0; x < 256; x++ { - sx := (px >> 8) & 0xff - if sx != ox { // Minimize interface indirection access. - ox = sx - col = src.At(sx, sy) - } - dst.Set(x, y, col) + // ofs := dLineOfs + for end := ofs + 4*256; ofs < end; ofs += 4 { + sOfs := sLineOfs + ((px >> 6) & 0x3fc) px += dx + dPix[ofs] = sPix[sOfs] + dPix[ofs+1] = sPix[sOfs+1] + dPix[ofs+2] = sPix[sOfs+2] + dPix[ofs+3] = sPix[sOfs+3] } py += dy } + //log.Printf("Rendering took: %s", time.Since(start)) return dst }