From 840c4d24df03f39066f16957793f07217a45c961 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sun, 17 Jun 2018 20:38:07 +0900 Subject: [PATCH] graphicsutil: Accept matrix parameters directly for performance --- image.go | 20 ++++-------- internal/graphicsutil/vertices.go | 11 ++----- internal/restorable/image.go | 20 ++---------- internal/restorable/images_test.go | 47 ++++++++++------------------ internal/shareable/shareable.go | 14 +++------ internal/shareable/shareable_test.go | 14 ++------- 6 files changed, 34 insertions(+), 92 deletions(-) diff --git a/image.go b/image.go index 8da0e5245..0369e7169 100644 --- a/image.go +++ b/image.go @@ -126,14 +126,6 @@ func (i *Image) fill(r, g, b, a uint8) { _ = i.DrawImage(emptyImage, op) } -type geoM32 struct { - inner *GeoM -} - -func (g geoM32) Elements() (a, b, c, d, tx, ty float32) { - return g.inner.elements() -} - // DrawImage draws the given image on the image i. // // DrawImage accepts the options. For details, see the document of DrawImageOptions. @@ -219,7 +211,7 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error { sy1 = r.Max.Y } } - geom := geoM32{&options.GeoM} + geom := &options.GeoM if sx0 < 0 || sy0 < 0 { dx := 0.0 dy := 0.0 @@ -231,10 +223,9 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error { dy = -float64(sy0) sy0 = 0 } - g := &GeoM{} - g.Translate(dx, dy) - g.Concat(options.GeoM) - geom = geoM32{g} + geom = &GeoM{} + geom.Translate(dx, dy) + geom.Concat(options.GeoM) } mode := opengl.CompositeMode(options.CompositeMode) @@ -246,7 +237,8 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error { filter = graphics.Filter(img.filter) } - i.shareableImage.DrawImage(img.shareableImage, sx0, sy0, sx1, sy1, geom, options.ColorM.impl, mode, filter) + a, b, c, d, tx, ty := geom.elements() + i.shareableImage.DrawImage(img.shareableImage, sx0, sy0, sx1, sy1, a, b, c, d, tx, ty, options.ColorM.impl, mode, filter) return nil } diff --git a/internal/graphicsutil/vertices.go b/internal/graphicsutil/vertices.go index e17f9faad..e17fbc81e 100644 --- a/internal/graphicsutil/vertices.go +++ b/internal/graphicsutil/vertices.go @@ -43,15 +43,11 @@ func (v *verticesBackend) sliceForOneQuad() []float32 { return s } -type GeoM interface { - Elements() (a, b, c, d, tx, ty float32) -} - func isPowerOf2(x int) bool { return (x & (x - 1)) == 0 } -func QuadVertices(width, height int, sx0, sy0, sx1, sy1 int, geom GeoM) []float32 { +func QuadVertices(width, height int, sx0, sy0, sx1, sy1 int, a, b, c, d, tx, ty float32) []float32 { if !isPowerOf2(width) { panic("not reached") } @@ -69,13 +65,12 @@ func QuadVertices(width, height int, sx0, sy0, sx1, sy1 int, geom GeoM) []float3 wf := float32(width) hf := float32(height) u0, v0, u1, v1 := float32(sx0)/wf, float32(sy0)/hf, float32(sx1)/wf, float32(sy1)/hf - return quadVerticesImpl(float32(sx1-sx0), float32(sy1-sy0), u0, v0, u1, v1, geom) + return quadVerticesImpl(float32(sx1-sx0), float32(sy1-sy0), u0, v0, u1, v1, a, b, c, d, tx, ty) } -func quadVerticesImpl(x, y, u0, v0, u1, v1 float32, geom GeoM) []float32 { +func quadVerticesImpl(x, y, u0, v0, u1, v1, a, b, c, d, tx, ty float32) []float32 { vs := theVerticesBackend.sliceForOneQuad() - a, b, c, d, tx, ty := geom.Elements() ax, by, cx, dy := a*x, b*y, c*x, d*y // Vertex coordinates diff --git a/internal/restorable/image.go b/internal/restorable/image.go index f4944eae9..ac630705c 100644 --- a/internal/restorable/image.go +++ b/internal/restorable/image.go @@ -136,17 +136,6 @@ var ( quadIndices = []uint16{0, 1, 2, 1, 2, 3} ) -type geoM struct { - scaleX float32 - scaleY float32 - tx float32 - ty float32 -} - -func (g *geoM) Elements() (a, b, c, d, tx, ty float32) { - return g.scaleX, 0, 0, g.scaleY, g.tx, g.ty -} - // ReplacePixels replaces the image pixels with the given pixels slice. // // If pixels is nil, ReplacePixels clears the specified reagion. @@ -172,12 +161,9 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) { // and this image can be restored without dummyImage. w, h := dummyImage.Size() colorm := (*affine.ColorM)(nil).Scale(0, 0, 0, 0) - vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, &geoM{ - scaleX: float32(width) / float32(w), - scaleY: float32(height) / float32(h), - tx: float32(x), - ty: float32(y), - }) + vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, + float32(width)/float32(w), 0, 0, float32(height)/float32(h), + float32(x), float32(y)) i.image.DrawImage(dummyImage.image, vs, quadIndices, colorm, opengl.CompositeModeCopy, graphics.FilterNearest) } diff --git a/internal/restorable/images_test.go b/internal/restorable/images_test.go index da0a774c7..dc7a46e71 100644 --- a/internal/restorable/images_test.go +++ b/internal/restorable/images_test.go @@ -105,12 +105,6 @@ var ( quadIndices = []uint16{0, 1, 2, 1, 2, 3} ) -type idGeoM struct{} - -func (idGeoM) Elements() (a, b, c, d, tx, ty float32) { - return 1, 0, 0, 1, 0, 0 -} - func TestRestoreChain(t *testing.T) { const num = 10 imgs := []*Image{} @@ -128,7 +122,7 @@ func TestRestoreChain(t *testing.T) { fill(imgs[0], clr.R, clr.G, clr.B, clr.A) for i := 0; i < num-1; i++ { w, h := imgs[i].Size() - vs := graphicsutil.QuadVertices(w, h, 0, 0, 1, 1, idGeoM{}) + vs := graphicsutil.QuadVertices(w, h, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0) imgs[i+1].DrawImage(imgs[i], vs, quadIndices, nil, opengl.CompositeModeCopy, graphics.FilterNearest) } if err := ResolveStaleImages(); err != nil { @@ -171,7 +165,7 @@ func TestRestoreChain2(t *testing.T) { clr8 := color.RGBA{0x00, 0x00, 0xff, 0xff} fill(imgs[8], clr8.R, clr8.G, clr8.B, clr8.A) - vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, idGeoM{}) + vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0) imgs[8].DrawImage(imgs[7], vs, quadIndices, nil, opengl.CompositeModeCopy, graphics.FilterNearest) imgs[9].DrawImage(imgs[8], vs, quadIndices, nil, opengl.CompositeModeCopy, graphics.FilterNearest) for i := 0; i < 7; i++ { @@ -218,7 +212,7 @@ func TestRestoreOverrideSource(t *testing.T) { clr0 := color.RGBA{0x00, 0x00, 0x00, 0xff} clr1 := color.RGBA{0x00, 0x00, 0x01, 0xff} fill(img1, clr0.R, clr0.G, clr0.B, clr0.A) - vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, idGeoM{}) + vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0) img2.DrawImage(img1, vs, quadIndices, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) img3.DrawImage(img2, vs, quadIndices, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) fill(img0, clr1.R, clr1.G, clr1.B, clr1.A) @@ -262,15 +256,6 @@ func TestRestoreOverrideSource(t *testing.T) { } } -type geoM struct { - tx float32 - ty float32 -} - -func (g *geoM) Elements() (a, b, c, d, tx, ty float32) { - return 1, 0, 0, 1, g.tx, g.ty -} - func TestRestoreComplexGraph(t *testing.T) { const ( w = 4 @@ -313,23 +298,23 @@ func TestRestoreComplexGraph(t *testing.T) { img1.Dispose() img0.Dispose() }() - vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, &geoM{0, 0}) + vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0) img3.DrawImage(img0, vs, quadIndices, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) - vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, &geoM{1, 0}) + vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0) img3.DrawImage(img1, vs, quadIndices, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) - vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, &geoM{1, 0}) + vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0) img4.DrawImage(img1, vs, quadIndices, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) - vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, &geoM{2, 0}) + vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 2, 0) img4.DrawImage(img2, vs, quadIndices, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) - vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, &geoM{0, 0}) + vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0) img5.DrawImage(img3, vs, quadIndices, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) - vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, &geoM{0, 0}) + vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0) img6.DrawImage(img3, vs, quadIndices, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) - vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, &geoM{1, 0}) + vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0) img6.DrawImage(img4, vs, quadIndices, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) - vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, &geoM{0, 0}) + vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0) img7.DrawImage(img2, vs, quadIndices, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) - vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, &geoM{2, 0}) + vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 2, 0) img7.DrawImage(img3, vs, quadIndices, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) if err := ResolveStaleImages(); err != nil { t.Fatal(err) @@ -422,7 +407,7 @@ func TestRestoreRecursive(t *testing.T) { img1.Dispose() img0.Dispose() }() - vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, &geoM{1, 0}) + vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0) img1.DrawImage(img0, vs, quadIndices, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) img0.DrawImage(img1, vs, quadIndices, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) if err := ResolveStaleImages(); err != nil { @@ -519,7 +504,7 @@ func TestDrawImageAndReplacePixels(t *testing.T) { img1 := NewImage(2, 1, false) defer img1.Dispose() - vs := graphicsutil.QuadVertices(1, 1, 0, 0, 1, 1, idGeoM{}) + vs := graphicsutil.QuadVertices(1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0) img1.DrawImage(img0, vs, quadIndices, nil, opengl.CompositeModeCopy, graphics.FilterNearest) img1.ReplacePixels([]byte{0xff, 0xff, 0xff, 0xff}, 1, 0, 1, 1) @@ -555,7 +540,7 @@ func TestDispose(t *testing.T) { img2 := newImageFromImage(base2) defer img2.Dispose() - vs := graphicsutil.QuadVertices(1, 1, 0, 0, 1, 1, idGeoM{}) + vs := graphicsutil.QuadVertices(1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0) img1.DrawImage(img2, vs, quadIndices, nil, opengl.CompositeModeCopy, graphics.FilterNearest) img0.DrawImage(img1, vs, quadIndices, nil, opengl.CompositeModeCopy, graphics.FilterNearest) img1.Dispose() @@ -587,7 +572,7 @@ func TestDoubleResolve(t *testing.T) { base.Pix[3] = 0xff img1 := newImageFromImage(base) - vs := graphicsutil.QuadVertices(1, 1, 0, 0, 1, 1, idGeoM{}) + vs := graphicsutil.QuadVertices(1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0) img0.DrawImage(img1, vs, quadIndices, nil, opengl.CompositeModeCopy, graphics.FilterNearest) img0.ReplacePixels([]uint8{0x00, 0xff, 0x00, 0xff}, 1, 1, 1, 1) // Now img0 is stale. diff --git a/internal/shareable/shareable.go b/internal/shareable/shareable.go index b35ac3d40..42a1ecb7b 100644 --- a/internal/shareable/shareable.go +++ b/internal/shareable/shareable.go @@ -67,7 +67,7 @@ func (b *backend) TryAlloc(width, height int) (*packing.Node, bool) { newImg := restorable.NewImage(s, s, false) oldImg := b.restorable w, h := oldImg.Size() - vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, idGeoM{}) + vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0) newImg.DrawImage(oldImg, vs, quadIndices, nil, opengl.CompositeModeCopy, graphics.FilterNearest) oldImg.Dispose() b.restorable = newImg @@ -98,12 +98,6 @@ type Image struct { node *packing.Node } -type idGeoM struct{} - -func (idGeoM) Elements() (a, b, c, d, tx, ty float32) { - return 1, 0, 0, 1, 0, 0 -} - func (i *Image) ensureNotShared() { if i.backend == nil { i.allocate(false) @@ -117,7 +111,7 @@ func (i *Image) ensureNotShared() { x, y, w, h := i.region() newImg := restorable.NewImage(w, h, false) vw, vh := i.backend.restorable.Size() - vs := graphicsutil.QuadVertices(vw, vh, x, y, x+w, y+h, idGeoM{}) + vs := graphicsutil.QuadVertices(vw, vh, x, y, x+w, y+h, 1, 0, 0, 1, 0, 0) newImg.DrawImage(i.backend.restorable, vs, quadIndices, nil, opengl.CompositeModeCopy, graphics.FilterNearest) i.dispose(false) @@ -141,7 +135,7 @@ func (i *Image) Size() (width, height int) { return i.width, i.height } -func (i *Image) DrawImage(img *Image, sx0, sy0, sx1, sy1 int, geom graphicsutil.GeoM, colorm *affine.ColorM, mode opengl.CompositeMode, filter graphics.Filter) { +func (i *Image) DrawImage(img *Image, sx0, sy0, sx1, sy1 int, a, b, c, d, tx, ty float32, colorm *affine.ColorM, mode opengl.CompositeMode, filter graphics.Filter) { backendsM.Lock() defer backendsM.Unlock() @@ -165,7 +159,7 @@ func (i *Image) DrawImage(img *Image, sx0, sy0, sx1, sy1 int, geom graphicsutil. dx, dy, _, _ := img.region() w, h := img.backend.restorable.SizePowerOf2() - vs := graphicsutil.QuadVertices(w, h, sx0+dx, sy0+dy, sx1+dx, sy1+dy, geom) + vs := graphicsutil.QuadVertices(w, h, sx0+dx, sy0+dy, sx1+dx, sy1+dy, a, b, c, d, tx, ty) i.backend.restorable.DrawImage(img.backend.restorable, vs, quadIndices, colorm, mode, filter) } diff --git a/internal/shareable/shareable_test.go b/internal/shareable/shareable_test.go index fff536142..00a605a65 100644 --- a/internal/shareable/shareable_test.go +++ b/internal/shareable/shareable_test.go @@ -45,15 +45,6 @@ func TestMain(m *testing.M) { const bigSize = 2049 -type geoM struct { - tx float32 - ty float32 -} - -func (g *geoM) Elements() (a, b, c, d, tx, ty float32) { - return 1, 0, 0, 1, g.tx, g.ty -} - func TestEnsureNotShared(t *testing.T) { // Create img1 and img2 with this size so that the next images are allocated // with non-upper-left location. @@ -93,8 +84,7 @@ func TestEnsureNotShared(t *testing.T) { dy1 = size * 3 / 4 ) // img4.ensureNotShared() should be called. - geom := &geoM{size / 4, size / 4} - img4.DrawImage(img3, 0, 0, size/2, size/2, geom, nil, opengl.CompositeModeCopy, graphics.FilterNearest) + img4.DrawImage(img3, 0, 0, size/2, size/2, 1, 0, 0, 1, size/4, size/4, nil, opengl.CompositeModeCopy, graphics.FilterNearest) for j := 0; j < size; j++ { for i := 0; i < size; i++ { @@ -115,5 +105,5 @@ func TestEnsureNotShared(t *testing.T) { // Check further drawing doesn't cause panic. // This bug was fixed by 03dcd948. - img4.DrawImage(img3, 0, 0, size/2, size/2, geom, nil, opengl.CompositeModeCopy, graphics.FilterNearest) + img4.DrawImage(img3, 0, 0, size/2, size/2, 1, 0, 0, 1, size/4, size/4, nil, opengl.CompositeModeCopy, graphics.FilterNearest) }