diff --git a/image.go b/image.go index e08a8c81f..f795b1323 100644 --- a/image.go +++ b/image.go @@ -270,7 +270,7 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) { }) } - i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedRegion(), img.adjustedRegion(), [graphics.ShaderImageCount - 1][2]float32{}, shader.shader, i.tmpUniforms, false, canSkipMipmap(geoM, filter), false) + i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedRegion(), [graphics.ShaderImageCount]graphicsdriver.Region{img.adjustedRegion()}, shader.shader, i.tmpUniforms, false, canSkipMipmap(geoM, filter), false) } // Vertex represents a vertex passed to DrawTriangles. @@ -515,7 +515,7 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o }) } - i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedRegion(), img.adjustedRegion(), [graphics.ShaderImageCount - 1][2]float32{}, shader.shader, i.tmpUniforms, options.FillRule == EvenOdd, filter != builtinshader.FilterLinear, options.AntiAlias) + i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedRegion(), [graphics.ShaderImageCount]graphicsdriver.Region{img.adjustedRegion()}, shader.shader, i.tmpUniforms, options.FillRule == EvenOdd, filter != builtinshader.FilterLinear, options.AntiAlias) } // DrawTrianglesShaderOptions represents options for DrawTrianglesShader. @@ -659,28 +659,18 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader imgs[i] = img.image } - var sr graphicsdriver.Region - if img := options.Images[0]; img != nil { - sr = img.adjustedRegion() - } - - var offsets [graphics.ShaderImageCount - 1][2]float32 - for i, img := range options.Images[1:] { + var srcRegions [graphics.ShaderImageCount]graphicsdriver.Region + for i, img := range options.Images { if img == nil { continue } - b := img.Bounds() - x, y := img.adjustPosition(b.Min.X, b.Min.Y) - // (sr.X, sr.Y) is the upper-left position of the first image. - // Calculate the distance between the current image's upper-left position and the first one's. - offsets[i][0] = float32(x) - sr.X - offsets[i][1] = float32(y) - sr.Y + srcRegions[i] = img.adjustedRegion() } i.tmpUniforms = i.tmpUniforms[:0] i.tmpUniforms = shader.appendUniforms(i.tmpUniforms, options.Uniforms) - i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedRegion(), sr, offsets, shader.shader, i.tmpUniforms, options.FillRule == EvenOdd, true, options.AntiAlias) + i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedRegion(), srcRegions, shader.shader, i.tmpUniforms, options.FillRule == EvenOdd, true, options.AntiAlias) } // DrawRectShaderOptions represents options for DrawRectShader. @@ -775,16 +765,20 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR imgs[i] = img.image } - var sr graphicsdriver.Region - if img := options.Images[0]; img != nil { - sr = img.adjustedRegion() - } else if shader.unit == shaderir.Pixels { - // Give the source size as pixels only when the unit is pixels so that users can get the source size via imageSrcRegionOnTexture (#2166). - // With the texel mode, the imageSrcRegionOnTexture values should be in texels so the source position in pixels would not match. - sr = graphicsdriver.Region{ - Width: float32(width), - Height: float32(height), + var srcRegions [graphics.ShaderImageCount]graphicsdriver.Region + for i, img := range options.Images { + if img == nil { + if shader.unit == shaderir.Pixels && i == 0 { + // Give the source size as pixels only when the unit is pixels so that users can get the source size via imageSrcRegionOnTexture (#2166). + // With the texel mode, the imageSrcRegionOnTexture values should be in texels so the source position in pixels would not match. + srcRegions[i] = graphicsdriver.Region{ + Width: float32(width), + Height: float32(height), + } + } + continue } + srcRegions[i] = img.adjustedRegion() } geoM := options.GeoM @@ -794,27 +788,15 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR a, b, c, d, tx, ty := geoM.elements32() cr, cg, cb, ca := options.ColorScale.elements() vs := i.ensureTmpVertices(4 * graphics.VertexFloatCount) - // Do not use sr.Width and sr.Height as these might be empty. - graphics.QuadVertices(vs, sr.X, sr.Y, sr.X+float32(width), sr.Y+float32(height), a, b, c, d, tx, ty, cr, cg, cb, ca) - is := graphics.QuadIndices() - var offsets [graphics.ShaderImageCount - 1][2]float32 - for i, img := range options.Images[1:] { - if img == nil { - continue - } - b := img.Bounds() - x, y := img.adjustPosition(b.Min.X, b.Min.Y) - // (sr.X, sr.Y) is the upper-left position of the first image. - // Calculate the distance between the current image's upper-left position and the first one's. - offsets[i][0] = float32(x) - sr.X - offsets[i][1] = float32(y) - sr.Y - } + // Do not use srcRegions[0].Width and srcRegions[-].Height as these might be empty. + graphics.QuadVertices(vs, srcRegions[0].X, srcRegions[0].Y, srcRegions[0].X+float32(width), srcRegions[0].Y+float32(height), a, b, c, d, tx, ty, cr, cg, cb, ca) + is := graphics.QuadIndices() i.tmpUniforms = i.tmpUniforms[:0] i.tmpUniforms = shader.appendUniforms(i.tmpUniforms, options.Uniforms) - i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedRegion(), sr, offsets, shader.shader, i.tmpUniforms, false, true, false) + i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedRegion(), srcRegions, shader.shader, i.tmpUniforms, false, true, false) } // SubImage returns an image representing the portion of the image p visible through r. diff --git a/internal/atlas/image.go b/internal/atlas/image.go index 82a9d8028..9077f6a65 100644 --- a/internal/atlas/image.go +++ b/internal/atlas/image.go @@ -282,7 +282,7 @@ func (i *Image) ensureIsolatedFromSource(backends []*backend) { Height: h, } - newI.drawTriangles([graphics.ShaderImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader, nil, false, true) + newI.drawTriangles([graphics.ShaderImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, NearestFilterShader, nil, false, true) newI.moveTo(i) } @@ -317,7 +317,7 @@ func (i *Image) putOnSourceBackend(graphicsDriver graphicsdriver.Graphics) { Width: w, Height: h, } - newI.drawTriangles([graphics.ShaderImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader, nil, false, true) + newI.drawTriangles([graphics.ShaderImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, NearestFilterShader, nil, false, true) newI.moveTo(i) i.usedAsSourceCount = 0 @@ -349,13 +349,13 @@ func (i *Image) regionWithPadding() image.Rectangle { // 5: Color G // 6: Color B // 7: Color Y -func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, subimageOffsets [graphics.ShaderImageCount - 1][2]float32, shader *Shader, uniforms []uint32, evenOdd bool) { +func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool) { backendsM.Lock() defer backendsM.Unlock() - i.drawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegion, subimageOffsets, shader, uniforms, evenOdd, false) + i.drawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd, false) } -func (i *Image) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, subimageOffsets [graphics.ShaderImageCount - 1][2]float32, shader *Shader, uniforms []uint32, evenOdd bool, keepOnAtlas bool) { +func (i *Image) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool, keepOnAtlas bool) { if i.disposed { panic("atlas: the drawing target image must not be disposed (DrawTriangles)") } @@ -413,12 +413,6 @@ func (i *Image) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [ vertices[i+3] /= shf } } - // srcRegion can be deliberately empty when this is not needed in order to avoid unexpected - // performance issue (#1293). - if srcRegion.Width != 0 && srcRegion.Height != 0 { - srcRegion.X += oxf - srcRegion.Y += oyf - } } else { n := len(vertices) for i := 0; i < n; i += graphics.VertexFloatCount { @@ -427,17 +421,23 @@ func (i *Image) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [ } } - var offsets [graphics.ShaderImageCount - 1][2]float32 - var imgs [graphics.ShaderImageCount]*restorable.Image - for i, subimageOffset := range subimageOffsets { - src := srcs[i+1] + for i, src := range srcs { if src == nil { continue } + + // A source region can be deliberately empty when this is not needed in order to avoid unexpected + // performance issue (#1293). + if srcRegions[i].Width == 0 || srcRegions[i].Height == 0 { + continue + } + r := src.regionWithPadding() - offsets[i][0] = float32(r.Min.X) - oxf + subimageOffset[0] - offsets[i][1] = float32(r.Min.Y) - oyf + subimageOffset[1] + srcRegions[i].X += float32(r.Min.X) + srcRegions[i].Y += float32(r.Min.Y) } + + var imgs [graphics.ShaderImageCount]*restorable.Image for i, src := range srcs { if src == nil { continue @@ -445,7 +445,7 @@ func (i *Image) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [ imgs[i] = src.backend.restorable } - i.backend.restorable.DrawTriangles(imgs, offsets, vertices, indices, blend, dstRegion, srcRegion, shader.shader, uniforms, evenOdd) + i.backend.restorable.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader.shader, uniforms, evenOdd) for _, src := range srcs { if src == nil { diff --git a/internal/atlas/image_test.go b/internal/atlas/image_test.go index b8b697bf1..4af74dffc 100644 --- a/internal/atlas/image_test.go +++ b/internal/atlas/image_test.go @@ -108,7 +108,7 @@ func TestEnsureIsolatedFromSourceBackend(t *testing.T) { Width: size, Height: size, } - img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) if got, want := img4.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -121,7 +121,7 @@ func TestEnsureIsolatedFromSourceBackend(t *testing.T) { Width: size / 2, Height: size / 2, } - img3.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img5}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img3.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img5}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) if got, want := img3.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -151,7 +151,7 @@ func TestEnsureIsolatedFromSourceBackend(t *testing.T) { // Check further drawing doesn't cause panic. // This bug was fixed by 03dcd948. vs = quadVertices(0, 0, size/2, size/2, 1) - img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) } func TestReputOnSourceBackend(t *testing.T) { @@ -200,7 +200,7 @@ func TestReputOnSourceBackend(t *testing.T) { // Render onto img1. The count should not matter. for i := 0; i < 5; i++ { vs := quadVertices(size, size, 0, 0, 1) - img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -212,7 +212,7 @@ func TestReputOnSourceBackend(t *testing.T) { for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ { atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) vs := quadVertices(size, size, 0, 0, 1) - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -220,7 +220,7 @@ func TestReputOnSourceBackend(t *testing.T) { // Finally, img1 is on a source backend. atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) vs := quadVertices(size, size, 0, 0, 1) - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnSourceBackendForTesting(), true; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -245,7 +245,7 @@ func TestReputOnSourceBackend(t *testing.T) { } vs = quadVertices(size, size, 0, 0, 1) - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnSourceBackendForTesting(), true; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -271,7 +271,7 @@ func TestReputOnSourceBackend(t *testing.T) { // Use img1 as a render target again. The count should not matter. for i := 0; i < 5; i++ { vs := quadVertices(size, size, 0, 0, 1) - img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -283,7 +283,7 @@ func TestReputOnSourceBackend(t *testing.T) { atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) img1.WritePixels(make([]byte, 4*size*size), image.Rect(0, 0, size, size)) vs := quadVertices(size, size, 0, 0, 1) - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -292,7 +292,7 @@ func TestReputOnSourceBackend(t *testing.T) { // img1 is not on an atlas due to WritePixels. vs = quadVertices(size, size, 0, 0, 1) - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -301,7 +301,7 @@ func TestReputOnSourceBackend(t *testing.T) { for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ { atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) vs := quadVertices(size, size, 0, 0, 1) - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) if got, want := img3.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -401,7 +401,7 @@ func TestWritePixelsAfterDrawTriangles(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) dst.WritePixels(pix, image.Rect(0, 0, w, h)) pix = make([]byte, 4*w*h) @@ -449,7 +449,7 @@ func TestSmallImages(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) pix = make([]byte, 4*w*h) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil { @@ -497,7 +497,7 @@ func TestLongImages(t *testing.T) { Width: dstW, Height: dstH, } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) pix = make([]byte, 4*dstW*dstH) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(0, 0, dstW, dstH)); err != nil { @@ -614,7 +614,7 @@ func TestDisposedAndReputOnSourceBackend(t *testing.T) { Width: size, Height: size, } - src.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + src.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) if got, want := src.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -623,7 +623,7 @@ func TestDisposedAndReputOnSourceBackend(t *testing.T) { for i := 0; i < atlas.BaseCountToPutOnSourceBackend/2; i++ { atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) vs := quadVertices(size, size, 0, 0, 1) - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) if got, want := src.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -665,7 +665,7 @@ func TestImageIsNotReputOnSourceBackendWithoutUsingAsSource(t *testing.T) { // Call DrawTriangles multiple times. // The number of DrawTriangles doesn't matter as long as these are called in one frame. for i := 0; i < 2; i++ { - src2.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + src2.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) } if got, want := src2.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) @@ -684,7 +684,7 @@ func TestImageIsNotReputOnSourceBackendWithoutUsingAsSource(t *testing.T) { for i := 0; i < atlas.BaseCountToPutOnSourceBackend; i++ { atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) vs := quadVertices(size, size, 0, 0, 1) - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) if got, want := src2.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -811,14 +811,14 @@ func TestDestinationCountOverflow(t *testing.T) { // Use dst0 as a destination for a while. for i := 0; i < 31; i++ { - dst0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + dst0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) } // Use dst0 as a source for a while. // As dst0 is used as a destination too many times (31 is a maximum), dst0's backend should never be a source backend. for i := 0; i < 100; i++ { - dst1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{dst0}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + dst1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{dst0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) if dst0.IsOnSourceBackendForTesting() { t.Errorf("dst0 cannot be on a source backend: %d", i) @@ -849,7 +849,7 @@ func TestIteratingImagesToPutOnSourceBackend(t *testing.T) { Height: h, } for _, img := range srcs { - img.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + img.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) } atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) @@ -857,7 +857,7 @@ func TestIteratingImagesToPutOnSourceBackend(t *testing.T) { // Check iterating the registered image works correctly. for i := 0; i < 100; i++ { for _, src := range srcs { - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) } atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting()) } diff --git a/internal/atlas/shader_test.go b/internal/atlas/shader_test.go index 218d1c838..c0d5bb867 100644 --- a/internal/atlas/shader_test.go +++ b/internal/atlas/shader_test.go @@ -41,12 +41,12 @@ func TestShaderFillTwice(t *testing.T) { } g := ui.GraphicsDriverForTesting() s0 := atlas.NewShader(etesting.ShaderProgramFill(0xff, 0xff, 0xff, 0xff)) - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, s0, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, s0, nil, false) // Vertices must be recreated (#1755) vs = quadVertices(w, h, 0, 0, 1) s1 := atlas.NewShader(etesting.ShaderProgramFill(0x80, 0x80, 0x80, 0xff)) - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, s1, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, s1, nil, false) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(g, pix, image.Rect(0, 0, w, h)); err != nil { @@ -74,11 +74,11 @@ func TestImageDrawTwice(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src0}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) // Vertices must be recreated (#1755) vs = quadVertices(w, h, 0, 0, 1) - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src1}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, atlas.NearestFilterShader, nil, false) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil { diff --git a/internal/buffered/image.go b/internal/buffered/image.go index 321d53ec5..e33f7b7f7 100644 --- a/internal/buffered/image.go +++ b/internal/buffered/image.go @@ -149,7 +149,7 @@ func (i *Image) writePixelsImpl(pix []byte, region image.Rectangle) { // DrawTriangles draws the src image with the given vertices. // // Copying vertices and indices is the caller's responsibility. -func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, subimageOffsets [graphics.ShaderImageCount - 1][2]float32, shader *Shader, uniforms []uint32, evenOdd bool) { +func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool) { for _, src := range srcs { if i == src { panic("buffered: Image.DrawTriangles: source images must be different from the receiver") @@ -164,15 +164,15 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [ us := make([]uint32, len(uniforms)) copy(us, uniforms) if tryAddDelayedCommand(func() { - i.drawTrianglesImpl(srcs, vs, is, blend, dstRegion, srcRegion, subimageOffsets, shader, us, evenOdd) + i.drawTrianglesImpl(srcs, vs, is, blend, dstRegion, srcRegions, shader, us, evenOdd) }) { return } } - i.drawTrianglesImpl(srcs, vertices, indices, blend, dstRegion, srcRegion, subimageOffsets, shader, uniforms, evenOdd) + i.drawTrianglesImpl(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd) } -func (i *Image) drawTrianglesImpl(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, subimageOffsets [graphics.ShaderImageCount - 1][2]float32, shader *Shader, uniforms []uint32, evenOdd bool) { +func (i *Image) drawTrianglesImpl(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool) { var imgs [graphics.ShaderImageCount]*atlas.Image for i, img := range srcs { if img == nil { @@ -182,7 +182,7 @@ func (i *Image) drawTrianglesImpl(srcs [graphics.ShaderImageCount]*Image, vertic } i.invalidatePixels() - i.img.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegion, subimageOffsets, shader.shader, uniforms, evenOdd) + i.img.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader.shader, uniforms, evenOdd) } type Shader struct { diff --git a/internal/graphics/shader.go b/internal/graphics/shader.go index 62bddede1..99fe7125e 100644 --- a/internal/graphics/shader.go +++ b/internal/graphics/shader.go @@ -33,13 +33,13 @@ func imageDstTextureSize() vec2 { ` shaderSuffix += fmt.Sprintf(` -var __srcTextureSizes [%[1]d]vec2 +var __imageSrcTextureSizes [%[1]d]vec2 // imageSrcTextureSize returns the source image's texture size in pixels. // As an image is a part of internal texture, the texture is usually bigger than the image. // The texture's size is useful when you want to calculate pixels from texels in the texel mode. func imageSrcTextureSize() vec2 { - return __srcTextureSizes[0] + return __imageSrcTextureSizes[0] } // The unit is the source texture's pixel or texel. @@ -56,11 +56,8 @@ func imageDstRegionOnTexture() (vec2, vec2) { return __imageDstRegionOrigin, __imageDstRegionSize } -// The unit is the source texture's pixel. -var __imageSrcOffsets [%[2]d]vec2 - // The unit is the source texture's pixel or texel. -var __imageSrcRegionOrigin vec2 +var __imageSrcRegionOrigins [%[1]d]vec2 // The unit is the source texture's pixel or texel. var __imageSrcRegionSizes [%[1]d]vec2 @@ -70,9 +67,9 @@ var __imageSrcRegionSizes [%[1]d]vec2 // // As an image is a part of internal texture, the image can be located at an arbitrary position on the texture. func imageSrcRegionOnTexture() (vec2, vec2) { - return __imageSrcRegionOrigin, __imageSrcRegionSizes[0] + return __imageSrcRegionOrigins[0], __imageSrcRegionSizes[0] } -`, ShaderImageCount, ShaderImageCount-1) +`, ShaderImageCount) for i := 0; i < ShaderImageCount; i++ { pos := "pos" @@ -80,9 +77,9 @@ func imageSrcRegionOnTexture() (vec2, vec2) { // Convert the position in texture0's positions to the target texture positions. switch unit { case shaderir.Pixels: - pos = fmt.Sprintf("pos + __imageSrcOffsets[%d]", i-1) + pos = fmt.Sprintf("pos - __imageSrcRegionOrigins[0] + __imageSrcRegionOrigins[%d]", i) case shaderir.Texels: - pos = fmt.Sprintf("(pos * __srcTextureSizes[0] + __imageSrcOffsets[%d]) / __srcTextureSizes[%d]", i-1, i) + pos = fmt.Sprintf("((pos - __imageSrcRegionOrigins[0]) * __imageSrcTextureSizes[0]) / __imageSrcTextureSizes[%[1]d] + __imageSrcRegionOrigins[%[1]d]", i) default: return "", fmt.Errorf("graphics: unexpected unit: %d", unit) } @@ -93,14 +90,29 @@ func imageSrc%[1]dUnsafeAt(pos vec2) vec4 { // pos is the position in positions of the source texture (= 0th image's texture). return __texelAt(__t%[1]d, %[2]s) } - +`, i, pos) + switch unit { + case shaderir.Pixels: + shaderSuffix += fmt.Sprintf(` func imageSrc%[1]dAt(pos vec2) vec4 { // pos is the position of the source texture (= 0th image's texture). // If pos is in the region, the result is (1, 1). Otherwise, either element is 0. - in := step(__imageSrcRegionOrigin, pos) - step(__imageSrcRegionOrigin + __imageSrcRegionSizes[%[1]d], pos) + in := step(__imageSrcRegionOrigins[0], pos) - step(__imageSrcRegionOrigins[0] + __imageSrcRegionSizes[%[1]d], pos) return __texelAt(__t%[1]d, %[2]s) * in.x * in.y } `, i, pos) + case shaderir.Texels: + shaderSuffix += fmt.Sprintf(` +func imageSrc%[1]dAt(pos vec2) vec4 { + // pos is the position of the source texture (= 0th image's texture). + // If pos is in the region, the result is (1, 1). Otherwise, either element is 0. + // With the texel mode, all the source region sizes are the same (#1870). + // As pos is in texels of the 0th texture, always use the 0th image region size. + in := step(__imageSrcRegionOrigins[0], pos) - step(__imageSrcRegionOrigins[0] + __imageSrcRegionSizes[0], pos) + return __texelAt(__t%[1]d, %[2]s) * in.x * in.y +} +`, i, pos) + } } shaderSuffix += ` diff --git a/internal/graphics/vertex.go b/internal/graphics/vertex.go index 621eb0b04..3d98b77d3 100644 --- a/internal/graphics/vertex.go +++ b/internal/graphics/vertex.go @@ -27,19 +27,17 @@ const ( 1 + // the source texture sizes array 1 + // the destination image region origin 1 + // the destination image region size - 1 + // the offsets array of the second and the following source images - 1 + // the source image region origin + 1 + // the source image region origins 1 + // the source image region sizes array 1 // the projection matrix - ProjectionMatrixUniformVariableIndex = 7 + ProjectionMatrixUniformVariableIndex = 6 PreservedUniformUint32Count = 2 + // the destination texture size 2*ShaderImageCount + // the source texture sizes array 2 + // the destination image region origin 2 + // the destination image region size - 2*(ShaderImageCount-1) + // the offsets array of the second and the following source images - 2 + // the source image region origin + 2*ShaderImageCount + // the source image region origins array 2*ShaderImageCount + // the source image region sizes array 16 // the projection matrix ) diff --git a/internal/graphicscommand/command.go b/internal/graphicscommand/command.go index 262b46ce7..1b889dbaf 100644 --- a/internal/graphicscommand/command.go +++ b/internal/graphicscommand/command.go @@ -111,7 +111,7 @@ func mustUseDifferentVertexBuffer(nextNumVertexFloats int) bool { } // EnqueueDrawTrianglesCommand enqueues a drawing-image command. -func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageCount]*Image, offsets [graphics.ShaderImageCount - 1][2]float32, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool) { +func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool) { if len(vertices) > graphics.MaxVertexFloatsCount { panic(fmt.Sprintf("graphicscommand: len(vertices) must equal to or less than %d but was %d", graphics.MaxVertexFloatsCount, len(vertices))) } @@ -131,7 +131,7 @@ func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.Sh // prependPreservedUniforms not only prepends values to the given slice but also creates a new slice. // Allocating a new slice is necessary to make EnqueueDrawTrianglesCommand safe so far. // TODO: This might cause a performance issue (#2601). - uniforms = q.prependPreservedUniforms(uniforms, shader, dst, srcs, offsets, dstRegion, srcRegion) + uniforms = q.prependPreservedUniforms(uniforms, shader, dst, srcs, dstRegion, srcRegions) // Remove unused uniform variables so that more commands can be merged. shader.ir.FilterUniformVariables(uniforms) @@ -662,7 +662,7 @@ func roundUpPower2(x int) int { return p2 } -func (q *commandQueue) prependPreservedUniforms(uniforms []uint32, shader *Shader, dst *Image, srcs [graphics.ShaderImageCount]*Image, offsets [graphics.ShaderImageCount - 1][2]float32, dstRegion, srcRegion graphicsdriver.Region) []uint32 { +func (q *commandQueue) prependPreservedUniforms(uniforms []uint32, shader *Shader, dst *Image, srcs [graphics.ShaderImageCount]*Image, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region) []uint32 { origUniforms := uniforms uniforms = q.uint32sBuffer.alloc(len(origUniforms) + graphics.PreservedUniformUint32Count) copy(uniforms[graphics.PreservedUniformUint32Count:], origUniforms) @@ -721,36 +721,38 @@ func (q *commandQueue) prependPreservedUniforms(uniforms []uint32, shader *Shade uniforms[12] = math.Float32bits(dstRegion.Width) uniforms[13] = math.Float32bits(dstRegion.Height) - if shader.unit() == shaderir.Texels && srcs[0] != nil { - w, h := srcs[0].InternalSize() - srcRegion.X /= float32(w) - srcRegion.Y /= float32(h) - srcRegion.Width /= float32(w) - srcRegion.Height /= float32(h) + if shader.unit() == shaderir.Texels { + for i, src := range srcs { + if src == nil { + continue + } + w, h := src.InternalSize() + srcRegions[i].X /= float32(w) + srcRegions[i].Y /= float32(h) + srcRegions[i].Width /= float32(w) + srcRegions[i].Height /= float32(h) + } } - // Set the source region offsets. - uniforms[14] = math.Float32bits(offsets[0][0]) - uniforms[15] = math.Float32bits(offsets[0][1]) - uniforms[16] = math.Float32bits(offsets[1][0]) - uniforms[17] = math.Float32bits(offsets[1][1]) - uniforms[18] = math.Float32bits(offsets[2][0]) - uniforms[19] = math.Float32bits(offsets[2][1]) - - // Set the source region origin. - uniforms[20] = math.Float32bits(srcRegion.X) - uniforms[21] = math.Float32bits(srcRegion.Y) + // Set the source region origins. + uniforms[14] = math.Float32bits(srcRegions[0].X) + uniforms[15] = math.Float32bits(srcRegions[0].Y) + uniforms[16] = math.Float32bits(srcRegions[1].X) + uniforms[17] = math.Float32bits(srcRegions[1].Y) + uniforms[18] = math.Float32bits(srcRegions[2].X) + uniforms[19] = math.Float32bits(srcRegions[2].Y) + uniforms[20] = math.Float32bits(srcRegions[3].X) + uniforms[21] = math.Float32bits(srcRegions[3].Y) // Set the source region sizes. - // TODO: Set a different sizes for a different source (#1870). - uniforms[22] = math.Float32bits(srcRegion.Width) - uniforms[23] = math.Float32bits(srcRegion.Height) - uniforms[24] = math.Float32bits(srcRegion.Width) - uniforms[25] = math.Float32bits(srcRegion.Height) - uniforms[26] = math.Float32bits(srcRegion.Width) - uniforms[27] = math.Float32bits(srcRegion.Height) - uniforms[28] = math.Float32bits(srcRegion.Width) - uniforms[29] = math.Float32bits(srcRegion.Height) + uniforms[22] = math.Float32bits(srcRegions[0].Width) + uniforms[23] = math.Float32bits(srcRegions[0].Height) + uniforms[24] = math.Float32bits(srcRegions[1].Width) + uniforms[25] = math.Float32bits(srcRegions[1].Height) + uniforms[26] = math.Float32bits(srcRegions[2].Width) + uniforms[27] = math.Float32bits(srcRegions[2].Height) + uniforms[28] = math.Float32bits(srcRegions[3].Width) + uniforms[29] = math.Float32bits(srcRegions[3].Height) // Set the projection matrix. uniforms[30] = math.Float32bits(2 / float32(dw)) diff --git a/internal/graphicscommand/image.go b/internal/graphicscommand/image.go index 4e16925d6..3780779d5 100644 --- a/internal/graphicscommand/image.go +++ b/internal/graphicscommand/image.go @@ -147,7 +147,7 @@ func (i *Image) InternalSize() (int, int) { // // If the source image is not specified, i.e., src is nil and there is no image in the uniform variables, the // elements for the source image are not used. -func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, offsets [graphics.ShaderImageCount - 1][2]float32, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool) { +func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool) { for _, src := range srcs { if src == nil { continue @@ -159,7 +159,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, offsets [g } i.flushBufferedWritePixels() - currentCommandQueue().EnqueueDrawTrianglesCommand(i, srcs, offsets, vertices, indices, blend, dstRegion, srcRegion, shader, uniforms, evenOdd) + currentCommandQueue().EnqueueDrawTrianglesCommand(i, srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd) } // ReadPixels reads the image's pixels. diff --git a/internal/graphicscommand/image_test.go b/internal/graphicscommand/image_test.go index 3f427ebe4..4d76db75f 100644 --- a/internal/graphicscommand/image_test.go +++ b/internal/graphicscommand/image_test.go @@ -64,7 +64,7 @@ func TestClear(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendClear, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, nearestFilterShader, nil, false) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), []graphicsdriver.PixelsArgs{ @@ -100,8 +100,8 @@ func TestWritePixelsPartAfterDrawTriangles(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendClear, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false) - dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, nearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, nearestFilterShader, nil, false) dst.WritePixels(make([]byte, 4), image.Rect(0, 0, 1, 1)) // TODO: Check the result. @@ -119,11 +119,11 @@ func TestShader(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendClear, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, nearestFilterShader, nil, false) g := ui.GraphicsDriverForTesting() s := graphicscommand.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff)) - dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, s, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, s, nil, false) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(g, []graphicsdriver.PixelsArgs{ diff --git a/internal/mipmap/mipmap.go b/internal/mipmap/mipmap.go index ffcfd05a8..7e8feadda 100644 --- a/internal/mipmap/mipmap.go +++ b/internal/mipmap/mipmap.go @@ -66,7 +66,7 @@ func (m *Mipmap) ReadPixels(graphicsDriver graphicsdriver.Graphics, pixels []byt return m.orig.ReadPixels(graphicsDriver, pixels, region) } -func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageCount]*Mipmap, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, subimageOffsets [graphics.ShaderImageCount - 1][2]float32, shader *Shader, uniforms []uint32, evenOdd bool, canSkipMipmap bool) { +func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageCount]*Mipmap, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool, canSkipMipmap bool) { if len(indices) == 0 { return } @@ -124,7 +124,7 @@ func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageCount]*Mipmap, vertices imgs[i] = src.orig } - m.orig.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegion, subimageOffsets, shader.shader, uniforms, evenOdd) + m.orig.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader.shader, uniforms, evenOdd) m.disposeMipmaps() } @@ -193,7 +193,7 @@ func (m *Mipmap) level(level int) *buffered.Image { Width: float32(w2), Height: float32(h2), } - s.DrawTriangles([graphics.ShaderImageCount]*buffered.Image{src}, vs, is, graphicsdriver.BlendCopy, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, shader.shader, nil, false) + s.DrawTriangles([graphics.ShaderImageCount]*buffered.Image{src}, vs, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderImageCount]graphicsdriver.Region{}, shader.shader, nil, false) m.setImg(level, s) return m.imgs[level] diff --git a/internal/restorable/image.go b/internal/restorable/image.go index 2e236a026..ec008eddc 100644 --- a/internal/restorable/image.go +++ b/internal/restorable/image.go @@ -73,16 +73,15 @@ func (p *Pixels) AppendRegion(regions []image.Rectangle) []image.Rectangle { // drawTrianglesHistoryItem is an item for history of draw-image commands. type drawTrianglesHistoryItem struct { - images [graphics.ShaderImageCount]*Image - offsets [graphics.ShaderImageCount - 1][2]float32 - vertices []float32 - indices []uint16 - blend graphicsdriver.Blend - dstRegion graphicsdriver.Region - srcRegion graphicsdriver.Region - shader *Shader - uniforms []uint32 - evenOdd bool + images [graphics.ShaderImageCount]*Image + vertices []float32 + indices []uint16 + blend graphicsdriver.Blend + dstRegion graphicsdriver.Region + srcRegions [graphics.ShaderImageCount]graphicsdriver.Region + shader *Shader + uniforms []uint32 + evenOdd bool } type ImageType int @@ -174,7 +173,6 @@ func (i *Image) Extend(width, height int) *Image { // Use DrawTriangles instead of WritePixels because the image i might be stale and not have its pixels // information. srcs := [graphics.ShaderImageCount]*Image{i} - var offsets [graphics.ShaderImageCount - 1][2]float32 sw, sh := i.image.InternalSize() vs := quadVertices(0, 0, float32(sw), float32(sh), 0, 0, float32(sw), float32(sh), 1, 1, 1, 1) is := graphics.QuadIndices() @@ -184,7 +182,7 @@ func (i *Image) Extend(width, height int) *Image { Width: float32(sw), Height: float32(sh), } - newImg.DrawTriangles(srcs, offsets, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, NearestFilterShader, nil, false) + newImg.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, NearestFilterShader, nil, false) i.Dispose() return newImg @@ -206,14 +204,13 @@ func clearImage(i *graphicscommand.Image) { dw, dh := i.InternalSize() vs := quadVertices(0, 0, float32(dw), float32(dh), 0, 0, 0, 0, 0, 0, 0, 0) is := graphics.QuadIndices() - var offsets [graphics.ShaderImageCount - 1][2]float32 dstRegion := graphicsdriver.Region{ X: 0, Y: 0, Width: float32(dw), Height: float32(dh), } - i.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{}, offsets, vs, is, graphicsdriver.BlendClear, dstRegion, graphicsdriver.Region{}, clearShader.shader, nil, false) + i.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendClear, dstRegion, [graphics.ShaderImageCount]graphicsdriver.Region{}, clearShader.shader, nil, false) } // BasePixelsForTesting returns the image's basePixels for testing. @@ -338,7 +335,7 @@ func (i *Image) WritePixels(pixels []byte, region image.Rectangle) { // 5: Color G // 6: Color B // 7: Color Y -func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, offsets [graphics.ShaderImageCount - 1][2]float32, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool) { +func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool) { if len(vertices) == 0 { return } @@ -360,7 +357,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, offsets [g if srcstale || !needsRestoring() || !i.needsRestoring() || i.stale { i.makeStale(regionToRectangle(dstRegion)) } else { - i.appendDrawTrianglesHistory(srcs, offsets, vertices, indices, blend, dstRegion, srcRegion, shader, uniforms, evenOdd) + i.appendDrawTrianglesHistory(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd) } var imgs [graphics.ShaderImageCount]*graphicscommand.Image @@ -370,11 +367,11 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, offsets [g } imgs[i] = src.image } - i.image.DrawTriangles(imgs, offsets, vertices, indices, blend, dstRegion, srcRegion, shader.shader, uniforms, evenOdd) + i.image.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader.shader, uniforms, evenOdd) } // appendDrawTrianglesHistory appends a draw-image history item to the image. -func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderImageCount]*Image, offsets [graphics.ShaderImageCount - 1][2]float32, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool) { +func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool) { if i.stale || !i.needsRestoring() { panic("restorable: an image must not be stale or need restoring at appendDrawTrianglesHistory") } @@ -401,16 +398,15 @@ func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderImageCount]*Imag copy(us, uniforms) item := &drawTrianglesHistoryItem{ - images: srcs, - offsets: offsets, - vertices: vs, - indices: is, - blend: blend, - dstRegion: dstRegion, - srcRegion: srcRegion, - shader: shader, - uniforms: us, - evenOdd: evenOdd, + images: srcs, + vertices: vs, + indices: is, + blend: blend, + dstRegion: dstRegion, + srcRegions: srcRegions, + shader: shader, + uniforms: us, + evenOdd: evenOdd, } i.drawTrianglesHistory = append(i.drawTrianglesHistory, item) } @@ -621,7 +617,7 @@ func (i *Image) restore(graphicsDriver graphicsdriver.Graphics) error { } imgs[i] = img.image } - gimg.DrawTriangles(imgs, c.offsets, c.vertices, c.indices, c.blend, c.dstRegion, c.srcRegion, c.shader.shader, c.uniforms, c.evenOdd) + gimg.DrawTriangles(imgs, c.vertices, c.indices, c.blend, c.dstRegion, c.srcRegions, c.shader.shader, c.uniforms, c.evenOdd) } // In order to clear the draw-triangles history, read pixels from GPU. diff --git a/internal/restorable/images_test.go b/internal/restorable/images_test.go index 785d2fb7f..b668dafa2 100644 --- a/internal/restorable/images_test.go +++ b/internal/restorable/images_test.go @@ -139,7 +139,7 @@ func TestRestoreChain(t *testing.T) { Width: 1, Height: 1, } - imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) } if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) @@ -187,10 +187,10 @@ func TestRestoreChain2(t *testing.T) { Width: w, Height: h, } - imgs[8].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[7]}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) - imgs[9].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[8]}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + imgs[8].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[7]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + imgs[9].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[8]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) for i := 0; i < 7; i++ { - imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) } if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { @@ -236,10 +236,10 @@ func TestRestoreOverrideSource(t *testing.T) { Width: w, Height: h, } - img2.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) - img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img2.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) img0.WritePixels([]byte{clr1.R, clr1.G, clr1.B, clr1.A}, image.Rect(0, 0, w, h)) - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) } @@ -323,25 +323,24 @@ func TestRestoreComplexGraph(t *testing.T) { Width: w, Height: h, } - var offsets [graphics.ShaderImageCount - 1][2]float32 vs := quadVertices(w, h, 0, 0) - img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, offsets, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(w, h, 1, 0) - img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, offsets, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(w, h, 1, 0) - img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, offsets, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(w, h, 2, 0) - img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, offsets, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(w, h, 0, 0) - img5.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, offsets, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img5.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(w, h, 0, 0) - img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, offsets, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(w, h, 1, 0) - img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img4}, offsets, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img4}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(w, h, 0, 0) - img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, offsets, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(w, h, 2, 0) - img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, offsets, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) } @@ -439,8 +438,8 @@ func TestRestoreRecursive(t *testing.T) { Width: w, Height: h, } - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) - img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) } @@ -543,7 +542,7 @@ func TestDrawTrianglesAndWritePixels(t *testing.T) { Width: 2, Height: 1, } - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) img1.WritePixels([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, image.Rect(0, 0, 2, 1)) if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { @@ -586,8 +585,8 @@ func TestDispose(t *testing.T) { Width: 1, Height: 1, } - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) - img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) img1.Dispose() if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { @@ -701,7 +700,7 @@ func TestWritePixelsOnly(t *testing.T) { Width: 1, Height: 1, } - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) img0.WritePixels([]byte{5, 6, 7, 8}, image.Rect(0, 0, 1, 1)) // BasePixelsForTesting is available without GPU accessing. @@ -760,7 +759,7 @@ func TestReadPixelsFromVolatileImage(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) // Read the pixels. If the implementation is correct, dst tries to read its pixels from GPU due to being // stale. @@ -789,7 +788,7 @@ func TestAllowWritePixelsAfterDrawTriangles(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) dst.WritePixels(make([]byte, 4*w*h), image.Rect(0, 0, w, h)) // WritePixels for a whole image doesn't panic. } @@ -813,7 +812,7 @@ func TestAllowWritePixelsForPartAfterDrawTriangles(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) dst.WritePixels(make([]byte, 4*2*2), image.Rect(0, 0, 2, 2)) // WritePixels for a part of image doesn't panic. @@ -912,7 +911,7 @@ func TestDrawTrianglesAndExtend(t *testing.T) { Width: w, Height: h, } - orig.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + orig.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) extended := orig.Extend(w*2, h*2) // After this, orig is already disposed. result := make([]byte, 4*(w*2)*(h*2)) @@ -967,7 +966,7 @@ func TestMutateSlices(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) for i := range vs { vs[i] = 0 } @@ -1164,7 +1163,7 @@ func TestDrawTrianglesAndReadPixels(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil { @@ -1193,7 +1192,7 @@ func TestWritePixelsAndDrawTriangles(t *testing.T) { Width: 1, Height: 1, } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendSourceOver, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) // Get the pixels. pix := make([]byte, 4*2*1) diff --git a/internal/restorable/shader_test.go b/internal/restorable/shader_test.go index dd88f7f71..cb6259a0b 100644 --- a/internal/restorable/shader_test.go +++ b/internal/restorable/shader_test.go @@ -51,7 +51,7 @@ func clearImage(img *restorable.Image, w, h int) { Width: float32(w), Height: float32(h), } - img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{emptyImage}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, graphicsdriver.BlendClear, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{emptyImage}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) } func TestShader(t *testing.T) { @@ -65,7 +65,7 @@ func TestShader(t *testing.T) { Width: 1, Height: 1, } - img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, s, nil, false) + img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, s, nil, false) if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) @@ -100,7 +100,7 @@ func TestShaderChain(t *testing.T) { Width: 1, Height: 1, } - imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, s, nil, false) + imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, s, nil, false) } if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { @@ -131,14 +131,13 @@ func TestShaderMultipleSources(t *testing.T) { dst := restorable.NewImage(1, 1, restorable.ImageTypeRegular) s := restorable.NewShader(etesting.ShaderProgramImages(3)) - var offsets [graphics.ShaderImageCount - 1][2]float32 dr := graphicsdriver.Region{ X: 0, Y: 0, Width: 1, Height: 1, } - dst.DrawTriangles(srcs, offsets, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, s, nil, false) + dst.DrawTriangles(srcs, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, s, nil, false) // Clear one of the sources after DrawTriangles. dst should not be affected. clearImage(srcs[0], 1, 1) @@ -169,17 +168,33 @@ func TestShaderMultipleSourcesOnOneTexture(t *testing.T) { dst := restorable.NewImage(1, 1, restorable.ImageTypeRegular) s := restorable.NewShader(etesting.ShaderProgramImages(3)) - offsets := [graphics.ShaderImageCount - 1][2]float32{ - {1, 0}, - {2, 0}, - } dr := graphicsdriver.Region{ X: 0, Y: 0, Width: 1, Height: 1, } - dst.DrawTriangles(srcs, offsets, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, s, nil, false) + srcRegions := [graphics.ShaderImageCount]graphicsdriver.Region{ + { + X: 0, + Y: 0, + Width: 1, + Height: 1, + }, + { + X: 1, + Y: 0, + Width: 1, + Height: 1, + }, + { + X: 2, + Y: 0, + Width: 1, + Height: 1, + }, + } + dst.DrawTriangles(srcs, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, srcRegions, s, nil, false) // Clear one of the sources after DrawTriangles. dst should not be affected. clearImage(srcs[0], 3, 1) @@ -209,7 +224,7 @@ func TestShaderDispose(t *testing.T) { Width: 1, Height: 1, } - img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, s, nil, false) + img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, s, nil, false) // Dispose the shader. This should invalidate all the images using this shader i.e., all the images become // stale. diff --git a/internal/ui/image.go b/internal/ui/image.go index 116e17854..d4d12ab4a 100644 --- a/internal/ui/image.go +++ b/internal/ui/image.go @@ -76,7 +76,7 @@ func (i *Image) MarkDisposed() { i.modifyCallback = nil } -func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, subimageOffsets [graphics.ShaderImageCount - 1][2]float32, shader *Shader, uniforms []uint32, evenOdd bool, canSkipMipmap bool, antialias bool) { +func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool, canSkipMipmap bool, antialias bool) { if i.modifyCallback != nil { i.modifyCallback() } @@ -98,7 +98,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [ i.bigOffscreenBuffer = newBigOffscreenImage(i, imageType) } - i.bigOffscreenBuffer.drawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegion, subimageOffsets, shader, uniforms, evenOdd, canSkipMipmap, false) + i.bigOffscreenBuffer.drawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd, canSkipMipmap, false) return } @@ -113,7 +113,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [ srcMipmaps[i] = src.mipmap } - i.mipmap.DrawTriangles(srcMipmaps, vertices, indices, blend, dstRegion, srcRegion, subimageOffsets, shader.shader, uniforms, evenOdd, canSkipMipmap) + i.mipmap.DrawTriangles(srcMipmaps, vertices, indices, blend, dstRegion, srcRegions, shader.shader, uniforms, evenOdd, canSkipMipmap) } func (i *Image) WritePixels(pix []byte, region image.Rectangle) { @@ -251,7 +251,7 @@ func (i *Image) flushDotsBufferIfNeeded() { Width: float32(i.width), Height: float32(i.height), } - i.mipmap.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader.shader, nil, false, true) + i.mipmap.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]graphicsdriver.Region{}, NearestFilterShader.shader, nil, false, true) } func (i *Image) flushBigOffscreenBufferIfNeeded() { @@ -302,7 +302,7 @@ func (i *Image) Fill(r, g, b, a float32, region image.Rectangle) { srcs := [graphics.ShaderImageCount]*Image{whiteImage} - i.DrawTriangles(srcs, i.tmpVerticesForFill, is, graphicsdriver.BlendCopy, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader, nil, false, true, false) + i.DrawTriangles(srcs, i.tmpVerticesForFill, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderImageCount]graphicsdriver.Region{}, NearestFilterShader, nil, false, true, false) } type bigOffscreenImage struct { @@ -334,7 +334,7 @@ func (i *bigOffscreenImage) markDisposed() { i.dirty = false } -func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion, srcRegion graphicsdriver.Region, subimageOffsets [graphics.ShaderImageCount - 1][2]float32, shader *Shader, uniforms []uint32, evenOdd bool, canSkipMipmap bool, antialias bool) { +func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint16, blend graphicsdriver.Blend, dstRegion graphicsdriver.Region, srcRegions [graphics.ShaderImageCount]graphicsdriver.Region, shader *Shader, uniforms []uint32, evenOdd bool, canSkipMipmap bool, antialias bool) { if i.blend != blend { i.flush() } @@ -374,7 +374,7 @@ func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderImageCount]*Image Width: i.region.Width * bigOffscreenScale, Height: i.region.Height * bigOffscreenScale, } - i.image.DrawTriangles(srcs, i.tmpVerticesForCopying, is, graphicsdriver.BlendCopy, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader, nil, false, true, false) + i.image.DrawTriangles(srcs, i.tmpVerticesForCopying, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderImageCount]graphicsdriver.Region{}, NearestFilterShader, nil, false, true, false) } for idx := 0; idx < len(vertices); idx += graphics.VertexFloatCount { @@ -399,7 +399,7 @@ func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderImageCount]*Image Height: (y1 - y0) * bigOffscreenScale, } - i.image.DrawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegion, subimageOffsets, shader, uniforms, evenOdd, canSkipMipmap, false) + i.image.DrawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, evenOdd, canSkipMipmap, false) i.dirty = true } @@ -431,7 +431,7 @@ func (i *bigOffscreenImage) flush() { if i.blend != graphicsdriver.BlendSourceOver { blend = graphicsdriver.BlendCopy } - i.orig.DrawTriangles(srcs, i.tmpVerticesForFlushing, is, blend, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, LinearFilterShader, nil, false, true, false) + i.orig.DrawTriangles(srcs, i.tmpVerticesForFlushing, is, blend, dstRegion, [graphics.ShaderImageCount]graphicsdriver.Region{}, LinearFilterShader, nil, false, true, false) i.image.clear() i.dirty = false