diff --git a/gpu/compute.go b/gpu/compute.go index ce06add5..ee6e127c 100644 --- a/gpu/compute.go +++ b/gpu/compute.go @@ -10,6 +10,7 @@ import ( "hash/maphash" "image" "image/color" + "image/draw" "image/png" "io/ioutil" "math" @@ -648,17 +649,13 @@ func (g *compute) frame(target RenderTarget) error { func (g *compute) dumpAtlases() { for i, a := range g.atlases { - dump, err := driver.DownloadImage(g.ctx, a.image, image.Rectangle{Max: a.size}) + dump := image.NewRGBA(image.Rectangle{Max: a.size}) + err := driver.DownloadImage(g.ctx, a.image, dump) if err != nil { panic(err) } nrgba := image.NewNRGBA(dump.Bounds()) - bnd := dump.Bounds() - for x := bnd.Min.X; x < bnd.Max.X; x++ { - for y := bnd.Min.Y; y < bnd.Max.Y; y++ { - nrgba.SetNRGBA(x, y, f32color.RGBAToNRGBA(dump.RGBAAt(x, y))) - } - } + draw.Draw(nrgba, image.Rectangle{}, dump, image.Point{}, draw.Src) var buf bytes.Buffer if err := png.Encode(&buf, nrgba); err != nil { panic(err) diff --git a/gpu/headless/driver_test.go b/gpu/headless/driver_test.go index 34e4d530..dbfb253a 100644 --- a/gpu/headless/driver_test.go +++ b/gpu/headless/driver_test.go @@ -185,7 +185,8 @@ func newDriver(t *testing.T) driver.Device { } func screenshot(t *testing.T, d driver.Device, fbo driver.Texture, size image.Point) *image.RGBA { - img, err := driver.DownloadImage(d, fbo, image.Rectangle{Max: size}) + img := image.NewRGBA(image.Rectangle{Max: size}) + err := driver.DownloadImage(d, fbo, img) if err != nil { t.Fatal(err) } diff --git a/gpu/headless/headless.go b/gpu/headless/headless.go index 78353cec..22d86b1e 100644 --- a/gpu/headless/headless.go +++ b/gpu/headless/headless.go @@ -122,7 +122,12 @@ func (w *Window) Release() { } } -// Frame replace the window content and state with the +// Size returns the window size. +func (w *Window) Size() image.Point { + return w.size +} + +// Frame replaces the window content and state with the // operation list. func (w *Window) Frame(frame *op.Ops) error { return contextDo(w.ctx, func() error { @@ -131,18 +136,11 @@ func (w *Window) Frame(frame *op.Ops) error { }) } -// Screenshot returns an image with the content of the window. -func (w *Window) Screenshot() (*image.RGBA, error) { - var img *image.RGBA - err := contextDo(w.ctx, func() error { - var err error - img, err = driver.DownloadImage(w.dev, w.fboTex, image.Rectangle{Max: w.size}) - return err +// Screenshot transfers the Window content at origin img.Rect.Min to img. +func (w *Window) Screenshot(img *image.RGBA) error { + return contextDo(w.ctx, func() error { + return driver.DownloadImage(w.dev, w.fboTex, img) }) - if err != nil { - return nil, err - } - return img, nil } func contextDo(ctx context, f func() error) error { diff --git a/gpu/headless/headless_test.go b/gpu/headless/headless_test.go index 2e016394..6c6cb10c 100644 --- a/gpu/headless/headless_test.go +++ b/gpu/headless/headless_test.go @@ -28,7 +28,8 @@ func TestHeadless(t *testing.T) { t.Fatal(err) } - img, err := w.Screenshot() + img := image.NewRGBA(image.Rectangle{Max: w.Size()}) + err := w.Screenshot(img) if err != nil { t.Fatal(err) } @@ -69,7 +70,8 @@ func TestClipping(t *testing.T) { t.Fatal(err) } - img, err := w.Screenshot() + img := image.NewRGBA(image.Rectangle{Max: w.Size()}) + err := w.Screenshot(img) if err != nil { t.Fatal(err) } @@ -108,7 +110,8 @@ func TestDepth(t *testing.T) { t.Fatal(err) } - img, err := w.Screenshot() + img := image.NewRGBA(image.Rectangle{Max: w.Size()}) + err := w.Screenshot(img) if err != nil { t.Fatal(err) } diff --git a/gpu/internal/driver/driver.go b/gpu/internal/driver/driver.go index 69791443..58cb89bd 100644 --- a/gpu/internal/driver/driver.go +++ b/gpu/internal/driver/driver.go @@ -199,17 +199,17 @@ func (f Features) Has(feats Features) bool { return f&feats == feats } -func DownloadImage(d Device, t Texture, r image.Rectangle) (*image.RGBA, error) { - img := image.NewRGBA(r) +func DownloadImage(d Device, t Texture, img *image.RGBA) error { + r := img.Bounds() if err := t.ReadPixels(r, img.Pix, img.Stride); err != nil { - return nil, err + return err } if d.Caps().BottomLeftOrigin { // OpenGL origin is in the lower-left corner. Flip the image to // match. flipImageY(r.Dx()*4, r.Dy(), img.Pix) } - return img, nil + return nil } func flipImageY(stride, height int, pixels []byte) { diff --git a/gpu/internal/rendertest/bench_test.go b/gpu/internal/rendertest/bench_test.go index dd333aeb..73366d38 100644 --- a/gpu/internal/rendertest/bench_test.go +++ b/gpu/internal/rendertest/bench_test.go @@ -47,7 +47,8 @@ func resetOps(gtx layout.Context) { func finishBenchmark(b *testing.B, w *headless.Window) { b.StopTimer() if *dumpImages { - img, err := w.Screenshot() + img := image.NewRGBA(image.Rectangle{Max: w.Size()}) + err := w.Screenshot(img) w.Release() if err != nil { b.Error(err) diff --git a/gpu/internal/rendertest/util_test.go b/gpu/internal/rendertest/util_test.go index b56188de..6f3f688c 100644 --- a/gpu/internal/rendertest/util_test.go +++ b/gpu/internal/rendertest/util_test.go @@ -59,7 +59,7 @@ func buildSquares(size int) paint.ImageOp { return paint.NewImageOp(im) } -func drawImage(t *testing.T, size int, ops *op.Ops, draw func(o *op.Ops)) (im *image.RGBA, err error) { +func drawImage(t *testing.T, size int, ops *op.Ops, draw func(o *op.Ops)) (*image.RGBA, error) { sz := image.Point{X: size, Y: size} w := newWindow(t, sz.X, sz.Y) defer w.Release() @@ -67,7 +67,9 @@ func drawImage(t *testing.T, size int, ops *op.Ops, draw func(o *op.Ops)) (im *i if err := w.Frame(ops); err != nil { return nil, err } - return w.Screenshot() + img := image.NewRGBA(image.Rectangle{Max: sz}) + err := w.Screenshot(img) + return img, err } func run(t *testing.T, f func(o *op.Ops), c func(r result)) { @@ -106,7 +108,6 @@ type frameT struct { func multiRun(t *testing.T, frames ...frameT) { // draw a few times and check that it is correct each time, to // ensure any caching effects still generate the correct images. - var img *image.RGBA var err error sz := image.Point{X: 128, Y: 128} w := newWindow(t, sz.X, sz.Y) @@ -119,7 +120,8 @@ func multiRun(t *testing.T, frames ...frameT) { t.Errorf("rendering failed: %v", err) continue } - img, err = w.Screenshot() + img := image.NewRGBA(image.Rectangle{Max: sz}) + err = w.Screenshot(img) if err != nil { t.Errorf("screenshot failed: %v", err) continue