From 5c403d9969729f717a8930bcef5f129fc56895f1 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Tue, 27 Dec 2016 03:18:56 +0900 Subject: [PATCH] graphics: Avoid copying images twice --- image_test.go | 2 +- imageimpl.go | 6 ++---- internal/graphics/command.go | 31 +++++-------------------------- internal/graphics/image.go | 11 +++++------ internal/restorable/image.go | 15 +++++++-------- 5 files changed, 20 insertions(+), 45 deletions(-) diff --git a/image_test.go b/image_test.go index eb9a7f9bd..50043e73d 100644 --- a/image_test.go +++ b/image_test.go @@ -84,7 +84,7 @@ func TestImagePixels(t *testing.T) { } if got := img0.Bounds().Size(); got != img.Bounds().Size() { - t.Errorf("img size: got %d; want %d", got, img.Bounds().Size()) + t.Fatalf("img size: got %d; want %d", got, img.Bounds().Size()) } for j := 0; j < img0.Bounds().Size().Y; j++ { diff --git a/imageimpl.go b/imageimpl.go index 0d9ad989a..d716e247f 100644 --- a/imageimpl.go +++ b/imageimpl.go @@ -81,7 +81,7 @@ func newImageImplFromImage(source image.Image, filter Filter) (*imageImpl, error for j := 0; j < h; j++ { copy(p[j*w*4:(j+1)*w*4], rgbaImg.Pix[j*rgbaImg.Stride:]) } - img, err := restorable.NewImageFromImage(rgbaImg, glFilter(filter)) + img, err := restorable.NewImageFromImage(rgbaImg, w, h, glFilter(filter)) if err != nil { return nil, err } @@ -180,9 +180,7 @@ func (i *imageImpl) At(x, y int, context *opengl.Context) color.Color { if i.restorable == nil { return color.Transparent } - w, _ := i.restorable.Size() - idx := 4*x + 4*y*w - clr, err := i.restorable.At(idx, context) + clr, err := i.restorable.At(x, y, context) if err != nil { panic(err) } diff --git a/internal/graphics/command.go b/internal/graphics/command.go index 141bd2c83..679eca3af 100644 --- a/internal/graphics/command.go +++ b/internal/graphics/command.go @@ -19,7 +19,6 @@ import ( "fmt" "image" "image/color" - "image/draw" "math" "sync" @@ -287,28 +286,6 @@ type newImageFromImageCommand struct { filter opengl.Filter } -func adjustImageForTexture(img *image.RGBA) *image.RGBA { - width, height := img.Bounds().Size().X, img.Bounds().Size().Y - adjustedImageBounds := image.Rectangle{ - image.ZP, - image.Point{ - NextPowerOf2Int(width), - NextPowerOf2Int(height), - }, - } - if img.Bounds() == adjustedImageBounds { - return img - } - - adjustedImage := image.NewRGBA(adjustedImageBounds) - dstBounds := image.Rectangle{ - image.ZP, - img.Bounds().Size(), - } - draw.Draw(adjustedImage, dstBounds, img, img.Bounds().Min, draw.Src) - return adjustedImage -} - func (c *newImageFromImageCommand) Exec(context *opengl.Context, indexOffsetInBytes int) error { origSize := c.img.Bounds().Size() if origSize.X < 1 { @@ -317,9 +294,11 @@ func (c *newImageFromImageCommand) Exec(context *opengl.Context, indexOffsetInBy if origSize.Y < 1 { return errors.New("graphics: height must be equal or more than 1.") } - adjustedImage := adjustImageForTexture(c.img) - size := adjustedImage.Bounds().Size() - native, err := context.NewTexture(size.X, size.Y, adjustedImage.Pix, c.filter) + w, h := c.img.Bounds().Size().X, c.img.Bounds().Size().Y + if c.img.Bounds() != image.Rect(0, 0, NextPowerOf2Int(w), NextPowerOf2Int(h)) { + panic(fmt.Sprintf("graphics: invalid image bounds: %v", c.img.Bounds())) + } + native, err := context.NewTexture(w, h, c.img.Pix, c.filter) if err != nil { return err } diff --git a/internal/graphics/image.go b/internal/graphics/image.go index f3e09590e..f6c1e819b 100644 --- a/internal/graphics/image.go +++ b/internal/graphics/image.go @@ -27,7 +27,7 @@ import ( func CopyImage(origImg image.Image) *image.RGBA { size := origImg.Bounds().Size() w, h := size.X, size.Y - newImg := image.NewRGBA(image.Rect(0, 0, w, h)) + newImg := image.NewRGBA(image.Rect(0, 0, NextPowerOf2Int(w), NextPowerOf2Int(h))) switch origImg := origImg.(type) { case *image.Paletted: b := origImg.Bounds() @@ -63,7 +63,7 @@ func CopyImage(origImg image.Image) *image.RGBA { index1 += d1 } default: - draw.Draw(newImg, newImg.Bounds(), origImg, origImg.Bounds().Min, draw.Src) + draw.Draw(newImg, image.Rect(0, 0, w, h), origImg, origImg.Bounds().Min, draw.Src) } runtime.Gosched() return newImg @@ -93,11 +93,10 @@ func NewImage(width, height int, filter opengl.Filter) (*Image, error) { return i, nil } -func NewImageFromImage(img *image.RGBA, filter opengl.Filter) (*Image, error) { - s := img.Bounds().Size() +func NewImageFromImage(img *image.RGBA, width, height int, filter opengl.Filter) (*Image, error) { i := &Image{ - width: s.X, - height: s.Y, + width: width, + height: height, } c := &newImageFromImageCommand{ result: i, diff --git a/internal/restorable/image.go b/internal/restorable/image.go index d05ab2fed..226cba726 100644 --- a/internal/restorable/image.go +++ b/internal/restorable/image.go @@ -62,14 +62,12 @@ func NewImage(width, height int, filter opengl.Filter, volatile bool) (*Image, e }, nil } -func NewImageFromImage(source *image.RGBA, filter opengl.Filter) (*Image, error) { - img, err := graphics.NewImageFromImage(source, filter) +func NewImageFromImage(source *image.RGBA, width, height int, filter opengl.Filter) (*Image, error) { + img, err := graphics.NewImageFromImage(source, width, height, filter) if err != nil { // TODO: texture should be removed here? return nil, err } - size := source.Bounds().Size() - width, height := size.X, size.Y return &Image{ image: img, width: width, @@ -172,11 +170,12 @@ func (p *Image) appendDrawImageHistory(image *graphics.Image, vertices []float32 p.drawImageHistory = append(p.drawImageHistory, item) } -// At returns a color value at idx. +// At returns a color value at (x, y). // // Note that this must not be called until context is available. // This means Pixels members must match with acutal state in VRAM. -func (p *Image) At(idx int, context *opengl.Context) (color.RGBA, error) { +func (p *Image) At(x, y int, context *opengl.Context) (color.RGBA, error) { + idx := 4*x + 4*y*p.width if p.basePixels == nil || p.drawImageHistory != nil || p.stale { if err := p.readPixelsFromVRAM(p.image, context); err != nil { return color.RGBA{}, err @@ -260,13 +259,13 @@ func (p *Image) Restore(context *opengl.Context) error { if p.stale { return errors.New("restorable: pixels must not be stale when restoring") } - img := image.NewRGBA(image.Rect(0, 0, p.width, p.height)) + img := image.NewRGBA(image.Rect(0, 0, graphics.NextPowerOf2Int(p.width), graphics.NextPowerOf2Int(p.height))) if p.basePixels != nil { for j := 0; j < p.height; j++ { copy(img.Pix[j*img.Stride:], p.basePixels[j*p.width*4:(j+1)*p.width*4]) } } - gimg, err := graphics.NewImageFromImage(img, p.filter) + gimg, err := graphics.NewImageFromImage(img, p.width, p.height, p.filter) if err != nil { return err }