From af9bd6a28212ab6cf139a565bb95e589401909dc Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sun, 8 Sep 2024 21:41:20 +0900 Subject: [PATCH] all: specify src-regions correctly This parameter was not important and actually not used with usual shaders. However, now this information will be important for the restorable package optimization later. There was a performance issue that was caused by srcRegions, but now this should not happen thanks to FilterUniformVariables. Updates #1293 --- internal/atlas/image.go | 7 ++- internal/atlas/image_test.go | 59 +++++++++++-------- internal/atlas/shader_test.go | 5 +- internal/buffered/image.go | 3 +- internal/graphicscommand/image_test.go | 12 ++-- internal/mipmap/mipmap.go | 5 +- internal/restorable/images_test.go | 78 ++++++++++++++++---------- internal/restorable/shader_test.go | 13 ++++- internal/ui/image.go | 9 ++- 9 files changed, 121 insertions(+), 70 deletions(-) diff --git a/internal/atlas/image.go b/internal/atlas/image.go index 0a395ef1a..71165ea6e 100644 --- a/internal/atlas/image.go +++ b/internal/atlas/image.go @@ -284,8 +284,9 @@ func (i *Image) ensureIsolatedFromSource(backends []*backend) { graphics.QuadVerticesFromDstAndSrc(vs, 0, 0, w, h, 0, 0, w, h, 1, 1, 1, 1) is := graphics.QuadIndices() dr := image.Rect(0, 0, i.width, i.height) + sr := image.Rect(0, 0, i.width, i.height) - newI.drawTriangles([graphics.ShaderSrcImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintOverwriteDstRegion) + newI.drawTriangles([graphics.ShaderSrcImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintOverwriteDstRegion) newI.moveTo(i) } @@ -315,7 +316,8 @@ func (i *Image) putOnSourceBackend() { graphics.QuadVerticesFromDstAndSrc(vs, 0, 0, w, h, 0, 0, w, h, 1, 1, 1, 1) is := graphics.QuadIndices() dr := image.Rect(0, 0, i.width, i.height) - newI.drawTriangles([graphics.ShaderSrcImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintOverwriteDstRegion) + sr := image.Rect(0, 0, i.width, i.height) + newI.drawTriangles([graphics.ShaderSrcImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintOverwriteDstRegion) newI.moveTo(i) i.usedAsSourceCount = 0 @@ -433,6 +435,7 @@ func (i *Image) drawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertice // A source region can be deliberately empty when this is not needed in order to avoid unexpected // performance issue (#1293). + // TODO: This should no longer be needed but is kept just in case. Remove this later. if srcRegions[i].Empty() { continue } diff --git a/internal/atlas/image_test.go b/internal/atlas/image_test.go index 0a021b95e..7d9f783f3 100644 --- a/internal/atlas/image_test.go +++ b/internal/atlas/image_test.go @@ -103,7 +103,8 @@ func TestEnsureIsolatedFromSourceBackend(t *testing.T) { vs := quadVertices(size/2, size/2, size/4, size/4, 1) is := graphics.QuadIndices() dr := image.Rect(0, 0, size, size) - img4.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, size/2, size/2) + img4.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) if got, want := img4.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -111,7 +112,8 @@ func TestEnsureIsolatedFromSourceBackend(t *testing.T) { // img5 is not allocated now, but is allocated at DrawTriangles. vs = quadVertices(0, 0, size/2, size/2, 1) dr = image.Rect(0, 0, size/2, size/2) - img3.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img5}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr = image.Rect(0, 0, size/2, size/2) + img3.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img5}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) if got, want := img3.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -145,7 +147,9 @@ 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.ShaderSrcImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + dr = image.Rect(0, 0, size, size) + sr = image.Rect(0, 0, size/2, size/2) + img4.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) } func TestReputOnSourceBackend(t *testing.T) { @@ -186,10 +190,11 @@ func TestReputOnSourceBackend(t *testing.T) { // Use img1 as a render target. is := graphics.QuadIndices() dr := image.Rect(0, 0, size, size) + sr := image.Rect(0, 0, size, size) // Render onto img1. The count should not matter. for i := 0; i < 5; i++ { vs := quadVertices(size, size, 0, 0, 1) - img1.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img1.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -201,7 +206,7 @@ func TestReputOnSourceBackend(t *testing.T) { for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ { atlas.PutImagesOnSourceBackendForTesting() vs := quadVertices(size, size, 0, 0, 1) - img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -209,7 +214,7 @@ func TestReputOnSourceBackend(t *testing.T) { // Finally, img1 is on a source backend. atlas.PutImagesOnSourceBackendForTesting() vs := quadVertices(size, size, 0, 0, 1) - img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) if got, want := img1.IsOnSourceBackendForTesting(), true; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -238,7 +243,7 @@ func TestReputOnSourceBackend(t *testing.T) { } vs = quadVertices(size, size, 0, 0, 1) - img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) if got, want := img1.IsOnSourceBackendForTesting(), true; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -268,7 +273,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.ShaderSrcImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img1.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -280,7 +285,7 @@ func TestReputOnSourceBackend(t *testing.T) { atlas.PutImagesOnSourceBackendForTesting() img1.WritePixels(make([]byte, 4*size*size), image.Rect(0, 0, size, size)) vs := quadVertices(size, size, 0, 0, 1) - img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -289,7 +294,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.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) if got, want := img1.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -298,7 +303,7 @@ func TestReputOnSourceBackend(t *testing.T) { for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ { atlas.PutImagesOnSourceBackendForTesting() vs := quadVertices(size, size, 0, 0, 1) - img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) if got, want := img3.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -401,7 +406,8 @@ func TestWritePixelsAfterDrawTriangles(t *testing.T) { vs := quadVertices(w, h, 0, 0, 1) is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) - dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) dst.WritePixels(pix, image.Rect(0, 0, w, h)) pix = make([]byte, 4*w*h) @@ -448,7 +454,8 @@ func TestSmallImages(t *testing.T) { vs := quadVertices(w, h, 0, 0, 1) is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) - dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) pix = make([]byte, 4*w*h) ok, err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)) @@ -495,7 +502,8 @@ func TestLongImages(t *testing.T) { vs := quadVertices(w, h, 0, 0, scale) is := graphics.QuadIndices() dr := image.Rect(0, 0, dstW, dstH) - dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) pix = make([]byte, 4*dstW*dstH) ok, err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, dstW, dstH)) @@ -611,7 +619,8 @@ func TestDeallocatedAndReputOnSourceBackend(t *testing.T) { vs := quadVertices(size, size, 0, 0, 1) is := graphics.QuadIndices() dr := image.Rect(0, 0, size, size) - src.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, size, size) + src.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) if got, want := src.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -620,7 +629,7 @@ func TestDeallocatedAndReputOnSourceBackend(t *testing.T) { for i := 0; i < atlas.BaseCountToPutOnSourceBackend/2; i++ { atlas.PutImagesOnSourceBackendForTesting() vs := quadVertices(size, size, 0, 0, 1) - dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) if got, want := src.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -648,13 +657,14 @@ func TestImageIsNotReputOnSourceBackendWithoutUsingAsSource(t *testing.T) { vs := quadVertices(size, size, 0, 0, 1) is := graphics.QuadIndices() dr := image.Rect(0, 0, size, size) + sr := image.Rect(0, 0, size, size) // Use src2 as a rendering target, and make src2 on a destination backend. // // 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.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + src2.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) } if got, want := src2.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) @@ -673,7 +683,7 @@ func TestImageIsNotReputOnSourceBackendWithoutUsingAsSource(t *testing.T) { for i := 0; i < atlas.BaseCountToPutOnSourceBackend; i++ { atlas.PutImagesOnSourceBackendForTesting() vs := quadVertices(size, size, 0, 0, 1) - dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) if got, want := src2.IsOnSourceBackendForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -796,17 +806,18 @@ func TestDestinationCountOverflow(t *testing.T) { vs := quadVertices(w, h, 0, 0, 1) is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) + sr := image.Rect(0, 0, w, h) // Use dst0 as a destination for a while. for i := 0; i < 31; i++ { - dst0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + dst0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) atlas.PutImagesOnSourceBackendForTesting() } // 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.ShaderSrcImageCount]*atlas.Image{dst0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + dst1.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{dst0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) atlas.PutImagesOnSourceBackendForTesting() if dst0.IsOnSourceBackendForTesting() { t.Errorf("dst0 cannot be on a source backend: %d", i) @@ -831,8 +842,9 @@ func TestIteratingImagesToPutOnSourceBackend(t *testing.T) { vs := quadVertices(w, h, 0, 0, 1) is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) + sr := image.Rect(0, 0, w, h) for _, img := range srcs { - img.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) } atlas.PutImagesOnSourceBackendForTesting() @@ -840,7 +852,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.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) } atlas.PutImagesOnSourceBackendForTesting() } @@ -888,7 +900,8 @@ func TestDallocateUnmanagedImageBackends(t *testing.T) { vs := quadVertices(w, h, 0, 0, 1) is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) - img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, w, h) + img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) // Get the difference of the number of backends before and after the images are deallocated. c := atlas.BackendCountForTesting() diff --git a/internal/atlas/shader_test.go b/internal/atlas/shader_test.go index a594585fa..569d0f93b 100644 --- a/internal/atlas/shader_test.go +++ b/internal/atlas/shader_test.go @@ -70,11 +70,12 @@ func TestImageDrawTwice(t *testing.T) { vs := quadVertices(w, h, 0, 0, 1) is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) - dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) // Vertices must be recreated (#1755) vs = quadVertices(w, h, 0, 0, 1) - dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) pix := make([]byte, 4*w*h) ok, err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)) diff --git a/internal/buffered/image.go b/internal/buffered/image.go index 62c3e8fab..5c74a41ae 100644 --- a/internal/buffered/image.go +++ b/internal/buffered/image.go @@ -310,8 +310,9 @@ func (i *Image) syncPixelsIfNeeded() { srcs := [graphics.ShaderSrcImageCount]*atlas.Image{whiteImage.img} dr := image.Rect(0, 0, i.width, i.height) + sr := image.Rect(0, 0, whiteImage.width, whiteImage.height) blend := graphicsdriver.BlendCopy - i.img.DrawTriangles(srcs, vs, is, blend, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + i.img.DrawTriangles(srcs, vs, is, blend, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, atlas.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) // TODO: Use clear if Go 1.21 is available. for pos := range i.dotsBuffer { diff --git a/internal/graphicscommand/image_test.go b/internal/graphicscommand/image_test.go index f13f04958..8f8462522 100644 --- a/internal/graphicscommand/image_test.go +++ b/internal/graphicscommand/image_test.go @@ -56,7 +56,8 @@ func TestClear(t *testing.T) { vs := quadVertices(w/2, h/2) is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) - dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillRuleFillAll) + sr := image.Rect(0, 0, w/2, h/2) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, nearestFilterShader, nil, graphicsdriver.FillRuleFillAll) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), []graphicsdriver.PixelsArgs{ @@ -87,8 +88,10 @@ func TestWritePixelsPartAfterDrawTriangles(t *testing.T) { vs := quadVertices(w/2, h/2) is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) - dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillRuleFillAll) - dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillRuleFillAll) + sr0 := image.Rect(0, 0, w, h) + sr1 := image.Rect(0, 0, w/2, h/2) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr0}, nearestFilterShader, nil, graphicsdriver.FillRuleFillAll) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr1}, nearestFilterShader, nil, graphicsdriver.FillRuleFillAll) bs := graphics.NewManagedBytes(4, func(bs []byte) { for i := range bs { bs[i] = 0 @@ -106,7 +109,8 @@ func TestShader(t *testing.T) { vs := quadVertices(w, h) is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) - dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillRuleFillAll) + sr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, nearestFilterShader, nil, graphicsdriver.FillRuleFillAll) g := ui.Get().GraphicsDriverForTesting() s := graphicscommand.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff), "") diff --git a/internal/mipmap/mipmap.go b/internal/mipmap/mipmap.go index e5f68d62f..389b47f79 100644 --- a/internal/mipmap/mipmap.go +++ b/internal/mipmap/mipmap.go @@ -185,7 +185,10 @@ func (m *Mipmap) level(level int) *buffered.Image { s := buffered.NewImage(w2, h2, m.imageType) dstRegion := image.Rect(0, 0, w2, h2) - s.DrawTriangles([graphics.ShaderSrcImageCount]*buffered.Image{src}, vs, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.LinearFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintOverwriteDstRegion) + w := sizeForLevel(m.width, level-1) + h := sizeForLevel(m.height, level-1) + srcRegion := image.Rect(0, 0, w, h) + s.DrawTriangles([graphics.ShaderSrcImageCount]*buffered.Image{src}, vs, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderSrcImageCount]image.Rectangle{srcRegion}, atlas.LinearFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintOverwriteDstRegion) m.setImg(level, s) return m.imgs[level] diff --git a/internal/restorable/images_test.go b/internal/restorable/images_test.go index 8c434b119..402918c6e 100644 --- a/internal/restorable/images_test.go +++ b/internal/restorable/images_test.go @@ -140,7 +140,8 @@ func TestRestoreChain(t *testing.T) { vs := quadVertices(1, 1, 0, 0) is := graphics.QuadIndices() dr := image.Rect(0, 0, 1, 1) - imgs[i+1].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[i]}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, 1, 1) + imgs[i+1].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[i]}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) } if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil { t.Fatal(err) @@ -183,10 +184,11 @@ func TestRestoreChain2(t *testing.T) { is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) - imgs[8].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[7]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) - imgs[9].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[8]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, w, h) + imgs[8].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[7]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + imgs[9].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[8]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) for i := 0; i < 7; i++ { - imgs[i+1].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[i]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + imgs[i+1].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[i]}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) } if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil { @@ -227,10 +229,11 @@ func TestRestoreOverrideSource(t *testing.T) { img1.WritePixels(bytesToManagedBytes([]byte{clr0.R, clr0.G, clr0.B, clr0.A}), image.Rect(0, 0, w, h)) is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) - img2.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) - img3.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img2}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, w, h) + img2.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img3.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img2}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) img0.WritePixels(bytesToManagedBytes([]byte{clr1.R, clr1.G, clr1.B, clr1.A}), image.Rect(0, 0, w, h)) - img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, quadVertices(w, h, 0, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil { t.Fatal(err) } @@ -309,24 +312,25 @@ func TestRestoreComplexGraph(t *testing.T) { }() is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) + sr := image.Rect(0, 0, w, h) vs := quadVertices(w, h, 0, 0) - img3.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img3.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) vs = quadVertices(w, h, 1, 0) - img3.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img3.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) vs = quadVertices(w, h, 1, 0) - img4.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img4.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) vs = quadVertices(w, h, 2, 0) - img4.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img2}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img4.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img2}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) vs = quadVertices(w, h, 0, 0) - img5.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img5.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) vs = quadVertices(w, h, 0, 0) - img6.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img6.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) vs = quadVertices(w, h, 1, 0) - img6.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img4}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img6.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img4}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) vs = quadVertices(w, h, 0, 0) - img7.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img2}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img7.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img2}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) vs = quadVertices(w, h, 2, 0) - img7.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img7.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img3}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil { t.Fatal(err) } @@ -419,8 +423,9 @@ func TestRestoreRecursive(t *testing.T) { }() is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) - img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) - img0.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, w, h) + img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img0.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, quadVertices(w, h, 1, 0), is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil { t.Fatal(err) } @@ -519,7 +524,8 @@ func TestDrawTrianglesAndWritePixels(t *testing.T) { vs := quadVertices(1, 1, 0, 0) is := graphics.QuadIndices() dr := image.Rect(0, 0, 2, 1) - img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, 1, 1) + img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) img1.WritePixels(bytesToManagedBytes([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}), image.Rect(0, 0, 2, 1)) if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil { @@ -557,8 +563,9 @@ func TestDispose(t *testing.T) { is := graphics.QuadIndices() dr := image.Rect(0, 0, 1, 1) - img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img2}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) - img0.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, 1, 1) + img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img2}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + img0.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img1}, quadVertices(1, 1, 0, 0), is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) img1.Dispose() if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil { @@ -667,7 +674,8 @@ func TestWritePixelsOnly(t *testing.T) { vs := quadVertices(1, 1, 0, 0) is := graphics.QuadIndices() dr := image.Rect(0, 0, 1, 1) - img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, w, h) + img1.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{img0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) img0.WritePixels(bytesToManagedBytes([]byte{5, 6, 7, 8}), image.Rect(0, 0, 1, 1)) // BasePixelsForTesting is available without GPU accessing. @@ -721,7 +729,8 @@ func TestReadPixelsFromVolatileImage(t *testing.T) { vs := quadVertices(1, 1, 0, 0) is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) - dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) // Read the pixels. If the implementation is correct, dst tries to read its pixels from GPU due to being // stale. @@ -745,7 +754,8 @@ func TestAllowWritePixelsAfterDrawTriangles(t *testing.T) { vs := quadVertices(w, h, 0, 0) is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) - dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) dst.WritePixels(bytesToManagedBytes(make([]byte, 4*w*h)), image.Rect(0, 0, w, h)) // WritePixels for a whole image doesn't panic. } @@ -764,7 +774,8 @@ func TestAllowWritePixelsForPartAfterDrawTriangles(t *testing.T) { vs := quadVertices(w, h, 0, 0) is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) - dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) dst.WritePixels(bytesToManagedBytes(make([]byte, 4*2*2)), image.Rect(0, 0, 2, 2)) // WritePixels for a part of image doesn't panic. @@ -858,7 +869,8 @@ func TestDrawTrianglesAndExtend(t *testing.T) { vs := quadVertices(w, h, 0, 0) is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) - orig.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, w, h) + orig.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) extended := orig.Extend(w*2, h*2) // After this, orig is already disposed. result := make([]byte, 4*(w*2)*(h*2)) @@ -908,7 +920,8 @@ func TestMutateSlices(t *testing.T) { is := make([]uint32, len(graphics.QuadIndices())) copy(is, graphics.QuadIndices()) dr := image.Rect(0, 0, w, h) - dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) for i := range vs { vs[i] = 0 } @@ -1100,7 +1113,8 @@ func TestDrawTrianglesAndReadPixels(t *testing.T) { vs := quadVertices(w, h, 0, 0) is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) - dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h)); err != nil { @@ -1124,7 +1138,8 @@ func TestWritePixelsAndDrawTriangles(t *testing.T) { vs := quadVertices(1, 1, 1, 0) is := graphics.QuadIndices() dr := image.Rect(1, 0, 2, 1) - dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, 1, 1) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) // Get the pixels. pix := make([]byte, 4*2*1) @@ -1151,10 +1166,11 @@ func TestOverwriteDstRegion(t *testing.T) { vs := quadVertices(w, h, 0, 0) is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) - dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src0}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, w, h) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src0}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) // This tests that HintOverwriteDstRegion removes the previous DrawTriangles. // In practice, BlendCopy should be used instead of BlendSourceOver in this case. - dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintOverwriteDstRegion) + dst.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{src1}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintOverwriteDstRegion) if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil { t.Fatal(err) diff --git a/internal/restorable/shader_test.go b/internal/restorable/shader_test.go index 2e9901502..41d2c74e9 100644 --- a/internal/restorable/shader_test.go +++ b/internal/restorable/shader_test.go @@ -46,7 +46,8 @@ func clearImage(img *restorable.Image, w, h int) { } is := graphics.QuadIndices() dr := image.Rect(0, 0, w, h) - img.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{emptyImage}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, 3, 3) + img.DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{emptyImage}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, restorable.NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) } func TestShader(t *testing.T) { @@ -85,7 +86,8 @@ func TestShaderChain(t *testing.T) { s := restorable.NewShader(etesting.ShaderProgramImages(1), "") for i := 0; i < num-1; i++ { dr := image.Rect(0, 0, 1, 1) - imgs[i+1].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[i]}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, s, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + sr := image.Rect(0, 0, 1, 1) + imgs[i+1].DrawTriangles([graphics.ShaderSrcImageCount]*restorable.Image{imgs[i]}, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, s, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) } if err := restorable.ResolveStaleImages(ui.Get().GraphicsDriverForTesting()); err != nil { @@ -117,7 +119,12 @@ func TestShaderMultipleSources(t *testing.T) { s := restorable.NewShader(etesting.ShaderProgramImages(3), "") dr := image.Rect(0, 0, 1, 1) - dst.DrawTriangles(srcs, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, s, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) + srs := [graphics.ShaderSrcImageCount]image.Rectangle{ + image.Rect(0, 0, 1, 1), + image.Rect(0, 0, 1, 1), + image.Rect(0, 0, 1, 1), + } + dst.DrawTriangles(srcs, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), graphicsdriver.BlendCopy, dr, srs, s, nil, graphicsdriver.FillRuleFillAll, restorable.HintNone) // Clear one of the sources after DrawTriangles. dst should not be affected. clearImage(srcs[0], 1, 1) diff --git a/internal/ui/image.go b/internal/ui/image.go index 94a03555f..3ffc47571 100644 --- a/internal/ui/image.go +++ b/internal/ui/image.go @@ -183,8 +183,9 @@ func (i *Image) Fill(r, g, b, a float32, region image.Rectangle) { if a == 1 && i.lastBlend == graphicsdriver.BlendSourceOver { blend = graphicsdriver.BlendSourceOver } + sr := image.Rect(0, 0, i.ui.whiteImage.width, i.ui.whiteImage.height) // i.lastBlend is updated in DrawTriangles. - i.DrawTriangles(srcs, i.tmpVerticesForFill, is, blend, region, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, true, false, restorable.HintOverwriteDstRegion) + i.DrawTriangles(srcs, i.tmpVerticesForFill, is, blend, region, [graphics.ShaderSrcImageCount]image.Rectangle{sr}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, true, false, restorable.HintOverwriteDstRegion) } type bigOffscreenImage struct { @@ -253,7 +254,8 @@ func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderSrcImageCount]*Im 1, 1, 1, 1) is := graphics.QuadIndices() dstRegion := image.Rect(0, 0, i.region.Dx()*bigOffscreenScale, i.region.Dy()*bigOffscreenScale) - i.image.DrawTriangles(srcs, i.tmpVerticesForCopying, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, true, false, restorable.HintOverwriteDstRegion) + srcRegion := i.region + i.image.DrawTriangles(srcs, i.tmpVerticesForCopying, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderSrcImageCount]image.Rectangle{srcRegion}, NearestFilterShader, nil, graphicsdriver.FillRuleFillAll, true, false, restorable.HintOverwriteDstRegion) } for idx := 0; idx < len(vertices); idx += graphics.VertexFloatCount { @@ -297,13 +299,14 @@ func (i *bigOffscreenImage) flush() { 1, 1, 1, 1) is := graphics.QuadIndices() dstRegion := i.region + srcRegion := image.Rect(0, 0, i.region.Dx()*bigOffscreenScale, i.region.Dy()*bigOffscreenScale) blend := graphicsdriver.BlendSourceOver hint := restorable.HintNone if i.blend != graphicsdriver.BlendSourceOver { blend = graphicsdriver.BlendCopy hint = restorable.HintOverwriteDstRegion } - i.orig.DrawTriangles(srcs, i.tmpVerticesForFlushing, is, blend, dstRegion, [graphics.ShaderSrcImageCount]image.Rectangle{}, LinearFilterShader, nil, graphicsdriver.FillRuleFillAll, true, false, hint) + i.orig.DrawTriangles(srcs, i.tmpVerticesForFlushing, is, blend, dstRegion, [graphics.ShaderSrcImageCount]image.Rectangle{srcRegion}, LinearFilterShader, nil, graphicsdriver.FillRuleFillAll, true, false, hint) i.image.clear() i.dirty = false