diff --git a/internal/atlas/image.go b/internal/atlas/image.go index 980d24100..154435ed9 100644 --- a/internal/atlas/image.go +++ b/internal/atlas/image.go @@ -27,6 +27,7 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/graphicscommand" "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver" "github.com/hajimehoshi/ebiten/v2/internal/packing" + "github.com/hajimehoshi/ebiten/v2/internal/restorable" "github.com/hajimehoshi/ebiten/v2/internal/shaderir" ) @@ -143,7 +144,7 @@ func (b *backend) extendIfNeeded(width, height int) { graphics.QuadVerticesFromDstAndSrc(vs, 0, 0, float32(sw), float32(sh), 0, 0, float32(sw), float32(sh), 1, 1, 1, 1) is := graphics.QuadIndices() dr := image.Rect(0, 0, sw, sh) - newImg.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader.ensureShader(), nil, graphicsdriver.FillRuleFillAll) + newImg.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader.ensureShader().Shader, nil, graphicsdriver.FillRuleFillAll) b.image.Dispose() b.image = newImg @@ -168,7 +169,7 @@ func clearImage(i *graphicscommand.Image, region image.Rectangle) { vs := make([]float32, 4*graphics.VertexFloatCount) graphics.QuadVerticesFromDstAndSrc(vs, float32(region.Min.X), float32(region.Min.Y), float32(region.Max.X), float32(region.Max.Y), 0, 0, 0, 0, 0, 0, 0, 0) is := graphics.QuadIndices() - i.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendClear, region, [graphics.ShaderSrcImageCount]image.Rectangle{}, clearShader.ensureShader(), nil, graphicsdriver.FillRuleFillAll) + i.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendClear, region, [graphics.ShaderSrcImageCount]image.Rectangle{}, restorable.ClearShader.Shader, nil, graphicsdriver.FillRuleFillAll) } func (b *backend) clearPixels(region image.Rectangle) { @@ -520,7 +521,7 @@ func (i *Image) drawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertice imgs[i] = src.backend.image } - i.backend.image.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader.ensureShader(), uniforms, fillRule) + i.backend.image.DrawTriangles(imgs, vertices, indices, blend, dstRegion, srcRegions, shader.ensureShader().Shader, uniforms, fillRule) for _, src := range srcs { if src == nil { diff --git a/internal/atlas/shader.go b/internal/atlas/shader.go index 32d2312f0..566b08534 100644 --- a/internal/atlas/shader.go +++ b/internal/atlas/shader.go @@ -15,20 +15,15 @@ package atlas import ( - "fmt" "runtime" - "golang.org/x/sync/errgroup" - - "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/restorable" "github.com/hajimehoshi/ebiten/v2/internal/shaderir" ) type Shader struct { ir *shaderir.Program - shader *graphicscommand.Shader + shader *restorable.Shader } func NewShader(ir *shaderir.Program) *Shader { @@ -46,11 +41,11 @@ func (s *Shader) finalize() { }) } -func (s *Shader) ensureShader() *graphicscommand.Shader { +func (s *Shader) ensureShader() *restorable.Shader { if s.shader != nil { return s.shader } - s.shader = graphicscommand.NewShader(s.ir) + s.shader = restorable.NewShader(s.ir) runtime.SetFinalizer(s, (*Shader).finalize) return s.shader } @@ -75,43 +70,18 @@ func (s *Shader) deallocate() { if s.shader == nil { return } - s.shader.Dispose() + s.shader.Shader.Dispose() + s.shader.Shader = nil s.shader = nil } var ( - NearestFilterShader *Shader - LinearFilterShader *Shader - clearShader *Shader -) - -func init() { - var wg errgroup.Group - wg.Go(func() error { - ir, err := graphics.CompileShader([]byte(builtinshader.ShaderSource(builtinshader.FilterNearest, builtinshader.AddressUnsafe, false))) - if err != nil { - return fmt.Errorf("atlas: compiling the nearest shader failed: %w", err) - } - NearestFilterShader = NewShader(ir) - return nil - }) - wg.Go(func() error { - ir, err := graphics.CompileShader([]byte(builtinshader.ShaderSource(builtinshader.FilterLinear, builtinshader.AddressUnsafe, false))) - if err != nil { - return fmt.Errorf("atlas: compiling the linear shader failed: %w", err) - } - LinearFilterShader = NewShader(ir) - return nil - }) - wg.Go(func() error { - ir, err := graphics.CompileShader([]byte(builtinshader.ClearShaderSource)) - if err != nil { - return fmt.Errorf("atlas: compiling the clear shader failed: %w", err) - } - clearShader = NewShader(ir) - return nil - }) - if err := wg.Wait(); err != nil { - panic(err) + NearestFilterShader = &Shader{ + shader: restorable.NearestFilterShader, + ir: restorable.LinearFilterShaderIR, } -} + LinearFilterShader = &Shader{ + shader: restorable.LinearFilterShader, + ir: restorable.LinearFilterShaderIR, + } +) diff --git a/internal/restorable/doc.go b/internal/restorable/doc.go new file mode 100644 index 000000000..adc4c448f --- /dev/null +++ b/internal/restorable/doc.go @@ -0,0 +1,22 @@ +// Copyright 2017 The Ebiten Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package restorable used to offer an Image struct that stores image commands +// and restores its pixel data from the commands when context lost happens. +// +// However, now Ebitengine doesn't handle context losts, and this package is +// just a thin wrapper. +// +// TODO: Integrate this package into internal/atlas and internal/graphicscommand (#805). +package restorable diff --git a/internal/restorable/shader.go b/internal/restorable/shader.go new file mode 100644 index 000000000..c09a8c4fe --- /dev/null +++ b/internal/restorable/shader.go @@ -0,0 +1,82 @@ +// Copyright 2020 The Ebiten Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package restorable + +import ( + "fmt" + + "golang.org/x/sync/errgroup" + + "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/shaderir" +) + +type Shader struct { + Shader *graphicscommand.Shader +} + +func NewShader(ir *shaderir.Program) *Shader { + s := &Shader{ + Shader: graphicscommand.NewShader(ir), + } + return s +} + +var ( + NearestFilterShader *Shader + NearestFilterShaderIR *shaderir.Program + LinearFilterShader *Shader + LinearFilterShaderIR *shaderir.Program + ClearShader *Shader +) + +func init() { + var wg errgroup.Group + var nearestIR, linearIR, clearIR *shaderir.Program + wg.Go(func() error { + ir, err := graphics.CompileShader([]byte(builtinshader.ShaderSource(builtinshader.FilterNearest, builtinshader.AddressUnsafe, false))) + if err != nil { + return fmt.Errorf("restorable: compiling the nearest shader failed: %w", err) + } + nearestIR = ir + return nil + }) + wg.Go(func() error { + ir, err := graphics.CompileShader([]byte(builtinshader.ShaderSource(builtinshader.FilterLinear, builtinshader.AddressUnsafe, false))) + if err != nil { + return fmt.Errorf("restorable: compiling the linear shader failed: %w", err) + } + linearIR = ir + return nil + }) + wg.Go(func() error { + ir, err := graphics.CompileShader([]byte(builtinshader.ClearShaderSource)) + if err != nil { + return fmt.Errorf("restorable: compiling the clear shader failed: %w", err) + } + clearIR = ir + return nil + }) + if err := wg.Wait(); err != nil { + panic(err) + } + NearestFilterShaderIR = nearestIR + NearestFilterShader = NewShader(nearestIR) + LinearFilterShaderIR = linearIR + LinearFilterShader = NewShader(linearIR) + ClearShader = NewShader(clearIR) +}