diff --git a/internal/atlas/image.go b/internal/atlas/image.go index db460e50a..7e249a189 100644 --- a/internal/atlas/image.go +++ b/internal/atlas/image.go @@ -310,7 +310,7 @@ func (i *Image) ensureIsolated() { Width: float32(w - 2*i.paddingSize()), Height: float32(h - 2*i.paddingSize()), } - newImg.DrawTriangles(srcs, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dstRegion, graphicsdriver.Region{}, nil, nil, false) + newImg.DrawTriangles(srcs, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dstRegion, graphicsdriver.Region{}, NearestFilterShader.shader, nil, false) i.dispose(false) i.backend = &backend{ @@ -349,7 +349,7 @@ func (i *Image) putOnAtlas(graphicsDriver graphicsdriver.Graphics) error { Width: w, Height: h, } - newI.drawTriangles([graphics.ShaderImageCount]*Image{i}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false, true) + newI.drawTriangles([graphics.ShaderImageCount]*Image{i}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, NearestFilterShader, nil, false, true) newI.moveTo(i) i.usedAsSourceCount = 0 diff --git a/internal/atlas/image_test.go b/internal/atlas/image_test.go index 7d6041797..faf0881d4 100644 --- a/internal/atlas/image_test.go +++ b/internal/atlas/image_test.go @@ -107,7 +107,7 @@ func TestEnsureIsolated(t *testing.T) { Width: size, Height: size, } - img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := img4.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -120,7 +120,7 @@ func TestEnsureIsolated(t *testing.T) { Width: size / 2, Height: size / 2, } - img3.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img5}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + img3.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img5}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := img3.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -149,7 +149,7 @@ func TestEnsureIsolated(t *testing.T) { // Check further drawing doesn't cause panic. // This bug was fixed by 03dcd948. - img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) } func TestReputOnAtlas(t *testing.T) { @@ -196,7 +196,7 @@ func TestReputOnAtlas(t *testing.T) { Width: size, Height: size, } - img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -208,7 +208,7 @@ func TestReputOnAtlas(t *testing.T) { if err := atlas.PutImagesOnAtlasForTesting(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) } - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -236,7 +236,7 @@ func TestReputOnAtlas(t *testing.T) { } // img1 is on an atlas again. - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnAtlasForTesting(), true; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -260,7 +260,7 @@ func TestReputOnAtlas(t *testing.T) { } // Use img1 as a render target again. - img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -272,7 +272,7 @@ func TestReputOnAtlas(t *testing.T) { t.Fatal(err) } img1.WritePixels(make([]byte, 4*size*size), 0, 0, size, size) - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -282,7 +282,7 @@ func TestReputOnAtlas(t *testing.T) { } // img1 is not on an atlas due to WritePixels. - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := img1.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -292,7 +292,7 @@ func TestReputOnAtlas(t *testing.T) { if err := atlas.PutImagesOnAtlasForTesting(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) } - img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := img3.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -392,7 +392,7 @@ func TestWritePixelsAfterDrawTriangles(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) dst.WritePixels(pix, 0, 0, w, h) pix = make([]byte, 4*w*h) @@ -440,7 +440,7 @@ func TestSmallImages(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) pix = make([]byte, 4*w*h) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix); err != nil { @@ -488,7 +488,7 @@ func TestLongImages(t *testing.T) { Width: dstW, Height: dstH, } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) pix = make([]byte, 4*dstW*dstH) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix); err != nil { @@ -605,7 +605,7 @@ func TestDisposedAndReputOnAtlas(t *testing.T) { Width: size, Height: size, } - src.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + src.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := src.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -615,7 +615,7 @@ func TestDisposedAndReputOnAtlas(t *testing.T) { if err := atlas.PutImagesOnAtlasForTesting(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := src.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -655,7 +655,7 @@ func TestImageIsNotReputOnAtlasWithoutUsingAsSource(t *testing.T) { } // Use src2 as a rendering target, and make src2 an independent image. - src2.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + src2.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := src2.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } @@ -676,7 +676,7 @@ func TestImageIsNotReputOnAtlasWithoutUsingAsSource(t *testing.T) { if err := atlas.PutImagesOnAtlasForTesting(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) if got, want := src2.IsOnAtlasForTesting(), false; got != want { t.Errorf("got: %v, want: %v", got, want) } diff --git a/internal/atlas/shader.go b/internal/atlas/shader.go index 06960ede8..0fc9fa7f7 100644 --- a/internal/atlas/shader.go +++ b/internal/atlas/shader.go @@ -58,3 +58,8 @@ func (s *Shader) dispose() { s.shader.Dispose() s.shader = nil } + +var ( + NearestFilterShader = &Shader{shader: restorable.NearestFilterShader} + LinearFilterShader = &Shader{shader: restorable.LinearFilterShader} +) diff --git a/internal/atlas/shader_test.go b/internal/atlas/shader_test.go index 6734f6221..bbccef7e6 100644 --- a/internal/atlas/shader_test.go +++ b/internal/atlas/shader_test.go @@ -74,11 +74,11 @@ func TestImageDrawTwice(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src0}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src0}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, 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, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src1}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix); err != nil { diff --git a/internal/buffered/image.go b/internal/buffered/image.go index b7b8dcf7c..e2eda325a 100644 --- a/internal/buffered/image.go +++ b/internal/buffered/image.go @@ -209,3 +209,8 @@ func (s *Shader) MarkDisposed() { s.shader.MarkDisposed() s.shader = nil } + +var ( + NearestFilterShader = &Shader{shader: atlas.NearestFilterShader} + LinearFilterShader = &Shader{shader: atlas.LinearFilterShader} +) diff --git a/internal/graphicscommand/image_test.go b/internal/graphicscommand/image_test.go index b3a956f59..106509f58 100644 --- a/internal/graphicscommand/image_test.go +++ b/internal/graphicscommand/image_test.go @@ -15,10 +15,12 @@ package graphicscommand_test import ( + "fmt" "image/color" "testing" "github.com/hajimehoshi/ebiten/v2/internal/affine" + "github.com/hajimehoshi/ebiten/v2/internal/builtinshader" "github.com/hajimehoshi/ebiten/v2/internal/graphics" "github.com/hajimehoshi/ebiten/v2/internal/graphicscommand" "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver" @@ -26,6 +28,16 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/ui" ) +var nearestFilterShader *graphicscommand.Shader + +func init() { + ir, err := graphics.CompileShader([]byte(builtinshader.Shader(graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, false))) + if err != nil { + panic(fmt.Sprintf("graphicscommand: compiling the nearest shader failed: %v", err)) + } + nearestFilterShader = graphicscommand.NewShader(ir) +} + func TestMain(m *testing.M) { etesting.MainWithRunLoop(m) } @@ -54,7 +66,7 @@ func TestClear(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeClear, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeClear, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, 0, 0, w, h); err != nil { @@ -85,8 +97,8 @@ func TestWritePixelsPartAfterDrawTriangles(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeClear, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) - dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeClear, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false) dst.WritePixels(make([]byte, 4), 0, 0, 1, 1) // TODO: Check the result. @@ -104,7 +116,7 @@ func TestShader(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeClear, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeClear, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nearestFilterShader, nil, false) g := ui.GraphicsDriverForTesting() s := graphicscommand.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff)) diff --git a/internal/mipmap/mipmap.go b/internal/mipmap/mipmap.go index b2409d6b3..6d1bcd742 100644 --- a/internal/mipmap/mipmap.go +++ b/internal/mipmap/mipmap.go @@ -155,12 +155,12 @@ func (m *Mipmap) level(level int) *buffered.Image { var src *buffered.Image var vs []float32 - var filter graphicsdriver.Filter + shader := NearestFilterShader switch { case level == 1: src = m.orig vs = graphics.QuadVertices(0, 0, float32(m.width), float32(m.height), 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1) - filter = graphicsdriver.FilterLinear + shader = LinearFilterShader case level > 1: src = m.level(level - 1) if src == nil { @@ -170,7 +170,7 @@ func (m *Mipmap) level(level int) *buffered.Image { w := sizeForLevel(m.width, level-1) h := sizeForLevel(m.height, level-1) vs = graphics.QuadVertices(0, 0, float32(w), float32(h), 0.5, 0, 0, 0.5, 0, 0, 1, 1, 1, 1) - filter = graphicsdriver.FilterLinear + shader = LinearFilterShader default: panic(fmt.Sprintf("mipmap: invalid level: %d", level)) } @@ -198,7 +198,7 @@ func (m *Mipmap) level(level int) *buffered.Image { Width: float32(w2), Height: float32(h2), } - s.DrawTriangles([graphics.ShaderImageCount]*buffered.Image{src}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, filter, graphicsdriver.AddressUnsafe, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false) + s.DrawTriangles([graphics.ShaderImageCount]*buffered.Image{src}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, shader.shader, nil, false) m.setImg(level, s) return m.imgs[level] @@ -302,3 +302,8 @@ func (s *Shader) MarkDisposed() { s.shader.MarkDisposed() s.shader = nil } + +var ( + NearestFilterShader = &Shader{shader: buffered.NearestFilterShader} + LinearFilterShader = &Shader{shader: buffered.LinearFilterShader} +) diff --git a/internal/restorable/image.go b/internal/restorable/image.go index 6c91b8800..9207ce380 100644 --- a/internal/restorable/image.go +++ b/internal/restorable/image.go @@ -211,7 +211,7 @@ func (i *Image) Extend(width, height int) *Image { Width: float32(sw), Height: float32(sh), } - newImg.DrawTriangles(srcs, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + newImg.DrawTriangles(srcs, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, NearestFilterShader, nil, false) // Overwrite the history as if the image newImg is created only by WritePixels. newImg.clearDrawTrianglesHistory() @@ -257,7 +257,7 @@ func clearImage(i *graphicscommand.Image) { Width: float32(dw), Height: float32(dh), } - i.DrawTriangles(srcs, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeClear, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dstRegion, graphicsdriver.Region{}, nil, nil, false) + i.DrawTriangles(srcs, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeClear, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dstRegion, graphicsdriver.Region{}, NearestFilterShader.shader, nil, false) } // BasePixelsForTesting returns the image's basePixels for testing. diff --git a/internal/restorable/images_test.go b/internal/restorable/images_test.go index ab4dc8b02..32096d6fd 100644 --- a/internal/restorable/images_test.go +++ b/internal/restorable/images_test.go @@ -146,7 +146,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, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) } if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) @@ -194,10 +194,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(imgs[7], w, h, 0, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) - imgs[9].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[8]}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(imgs[8], w, h, 0, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + imgs[8].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[7]}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(imgs[7], w, h, 0, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + imgs[9].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[8]}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(imgs[8], w, h, 0, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, 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(imgs[i], w, h, 0, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + imgs[i+1].DrawTriangles([graphics.ShaderImageCount]*restorable.Image{imgs[i]}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(imgs[i], w, h, 0, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) } if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { @@ -243,10 +243,10 @@ func TestRestoreOverrideSource(t *testing.T) { Width: w, Height: h, } - img2.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img1, w, h, 0, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) - img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img2, w, h, 0, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + img2.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img1, w, h, 0, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img2, w, h, 0, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) img0.WritePixels([]byte{clr1.R, clr1.G, clr1.B, clr1.A}, 0, 0, w, h) - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img0, w, h, 0, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img0, w, h, 0, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) } @@ -332,23 +332,23 @@ func TestRestoreComplexGraph(t *testing.T) { } var offsets [graphics.ShaderImageCount - 1][2]float32 vs := quadVertices(img0, w, h, 0, 0) - img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(img1, w, h, 1, 0) - img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + img3.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(img1, w, h, 1, 0) - img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(img2, w, h, 2, 0) - img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + img4.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(img3, w, h, 0, 0) - img5.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + img5.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(img3, w, h, 0, 0) - img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(img4, w, h, 1, 0) - img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img4}, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + img6.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img4}, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(img2, w, h, 0, 0) - img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) vs = quadVertices(img3, w, h, 2, 0) - img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + img7.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img3}, offsets, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) } @@ -446,8 +446,8 @@ func TestRestoreRecursive(t *testing.T) { Width: w, Height: h, } - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img0, w, h, 1, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) - img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img1, w, h, 1, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img0, w, h, 1, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img1, w, h, 1, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { t.Fatal(err) } @@ -550,7 +550,7 @@ func TestDrawTrianglesAndWritePixels(t *testing.T) { Width: 2, Height: 1, } - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) img1.WritePixels([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 0, 0, 2, 1) if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { @@ -593,8 +593,8 @@ func TestDispose(t *testing.T) { Width: 1, Height: 1, } - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img2, 1, 1, 0, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) - img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img1, 1, 1, 0, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img2}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img2, 1, 1, 0, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) + img0.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img1}, [graphics.ShaderImageCount - 1][2]float32{}, quadVertices(img1, 1, 1, 0, 0), is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) img1.Dispose() if err := restorable.ResolveStaleImages(ui.GraphicsDriverForTesting()); err != nil { @@ -708,7 +708,7 @@ func TestWritePixelsOnly(t *testing.T) { Width: 1, Height: 1, } - img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + img1.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{img0}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) img0.WritePixels([]byte{5, 6, 7, 8}, 0, 0, 1, 1) // BasePixelsForTesting is available without GPU accessing. @@ -767,7 +767,7 @@ func TestReadPixelsFromVolatileImage(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, 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. @@ -796,7 +796,7 @@ func TestAllowWritePixelsAfterDrawTriangles(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) dst.WritePixels(make([]byte, 4*w*h), 0, 0, w, h) // WritePixels for a whole image doesn't panic. } @@ -820,7 +820,7 @@ func TestAllowWritePixelsForPartAfterDrawTriangles(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) dst.WritePixels(make([]byte, 4*2*2), 0, 0, 2, 2) // WritePixels for a part of image doesn't panic. @@ -923,7 +923,7 @@ func TestMutateSlices(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) for i := range vs { vs[i] = 0 } @@ -1120,7 +1120,7 @@ func TestDrawTrianglesAndReadPixels(t *testing.T) { Width: w, Height: h, } - dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + dst.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{src}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeSourceOver, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) pix := make([]byte, 4*w*h) if err := dst.ReadPixels(ui.GraphicsDriverForTesting(), pix, 0, 0, w, h); err != nil { diff --git a/internal/restorable/shader.go b/internal/restorable/shader.go index bd4b6f216..85e404bb0 100644 --- a/internal/restorable/shader.go +++ b/internal/restorable/shader.go @@ -15,7 +15,12 @@ package restorable import ( + "fmt" + + "github.com/hajimehoshi/ebiten/v2/internal/builtinshader" + "github.com/hajimehoshi/ebiten/v2/internal/graphics" "github.com/hajimehoshi/ebiten/v2/internal/graphicscommand" + "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver" "github.com/hajimehoshi/ebiten/v2/internal/shaderir" ) @@ -43,3 +48,25 @@ func (s *Shader) Dispose() { func (s *Shader) restore() { s.shader = graphicscommand.NewShader(s.ir) } + +var ( + NearestFilterShader *Shader + LinearFilterShader *Shader +) + +func init() { + { + ir, err := graphics.CompileShader([]byte(builtinshader.Shader(graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, false))) + if err != nil { + panic(fmt.Sprintf("restorable: compiling the nearest shader failed: %v", err)) + } + NearestFilterShader = NewShader(ir) + } + { + ir, err := graphics.CompileShader([]byte(builtinshader.Shader(graphicsdriver.FilterLinear, graphicsdriver.AddressUnsafe, false))) + if err != nil { + panic(fmt.Sprintf("restorable: compiling the linear shader failed: %v", err)) + } + LinearFilterShader = NewShader(ir) + } +} diff --git a/internal/restorable/shader_test.go b/internal/restorable/shader_test.go index 0f9ec8e16..6f5c89ac2 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, affine.ColorMIdentity{}, graphicsdriver.CompositeModeClear, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, nil, nil, false) + img.DrawTriangles([graphics.ShaderImageCount]*restorable.Image{emptyImage}, [graphics.ShaderImageCount - 1][2]float32{}, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeClear, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, restorable.NearestFilterShader, nil, false) } func TestShader(t *testing.T) { diff --git a/internal/ui/context.go b/internal/ui/context.go index 392578bf3..68b5147d1 100644 --- a/internal/ui/context.go +++ b/internal/ui/context.go @@ -23,12 +23,12 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/affine" "github.com/hajimehoshi/ebiten/v2/internal/atlas" "github.com/hajimehoshi/ebiten/v2/internal/buffered" - "github.com/hajimehoshi/ebiten/v2/internal/builtinshader" "github.com/hajimehoshi/ebiten/v2/internal/clock" "github.com/hajimehoshi/ebiten/v2/internal/debug" "github.com/hajimehoshi/ebiten/v2/internal/graphics" "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver" "github.com/hajimehoshi/ebiten/v2/internal/hooks" + "github.com/hajimehoshi/ebiten/v2/internal/mipmap" ) const screenShaderSrc = `package main @@ -66,9 +66,9 @@ func Fragment(position vec4, texCoord vec2, color vec4) vec4 { ` var ( - screenShader *Shader - nearestShader *Shader - linearShader *Shader + screenShader *Shader + nearestFilterShader = &Shader{shader: mipmap.NearestFilterShader} + linearFilterShader = &Shader{shader: mipmap.LinearFilterShader} ) func init() { @@ -79,20 +79,6 @@ func init() { } screenShader = NewShader(ir) } - { - ir, err := graphics.CompileShader([]byte(builtinshader.Shader(graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, false))) - if err != nil { - panic(fmt.Sprintf("ui: compiling the nearest shader failed: %v", err)) - } - nearestShader = NewShader(ir) - } - { - ir, err := graphics.CompileShader([]byte(builtinshader.Shader(graphicsdriver.FilterLinear, graphicsdriver.AddressUnsafe, false))) - if err != nil { - panic(fmt.Sprintf("ui: compiling the linear shader failed: %v", err)) - } - linearShader = NewShader(ir) - } } type Game interface { @@ -256,15 +242,15 @@ func (c *context) drawGame(graphicsDriver graphicsdriver.Graphics) { var shader *Shader switch { case !theGlobalState.isScreenFilterEnabled(): - shader = nearestShader + shader = nearestFilterShader case math.Floor(s) == s: - shader = nearestShader + shader = nearestFilterShader case s > 1: shader = screenShader default: // screenShader works with >=1 scale, but does not well with <1 scale. // Use regular FilterLinear instead so far (#669). - shader = linearShader + shader = linearFilterShader } dstRegion := graphicsdriver.Region{ diff --git a/internal/ui/image.go b/internal/ui/image.go index 25462953f..8d821f378 100644 --- a/internal/ui/image.go +++ b/internal/ui/image.go @@ -196,7 +196,7 @@ func (i *Image) resolveDotsCacheIfNeeded() { Width: float32(i.width), Height: float32(i.height), } - i.mipmap.DrawTriangles(srcs, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nil, nil, false, true) + i.mipmap.DrawTriangles(srcs, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nearestFilterShader.shader, nil, false, true) } func DumpImages(dir string) (string, error) { @@ -236,5 +236,5 @@ func (i *Image) Fill(r, g, b, a float32, x, y, width, height int) { srcs := [graphics.ShaderImageCount]*Image{emptyImage} - i.DrawTriangles(srcs, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nearestShader, nil, false, true) + i.DrawTriangles(srcs, vs, is, affine.ColorMIdentity{}, graphicsdriver.CompositeModeCopy, graphicsdriver.FilterNearest, graphicsdriver.AddressUnsafe, dstRegion, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, nearestFilterShader, nil, false, true) }