From 3b6a080519469560d3f03016a281f92966840944 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Wed, 8 Jun 2022 10:00:26 +0900 Subject: [PATCH] internal/atlas: bug fix: use the global lock for shaders Closes #2129 --- internal/atlas/shader.go | 6 ++ internal/processtest/testdata/issue2129.go | 70 ++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 internal/processtest/testdata/issue2129.go diff --git a/internal/atlas/shader.go b/internal/atlas/shader.go index 5f14307c0..647f71e4a 100644 --- a/internal/atlas/shader.go +++ b/internal/atlas/shader.go @@ -26,6 +26,9 @@ type Shader struct { } func NewShader(ir *shaderir.Program) *Shader { + backendsM.Lock() + defer backendsM.Unlock() + s := &Shader{ shader: restorable.NewShader(ir), } @@ -39,6 +42,9 @@ func NewShader(ir *shaderir.Program) *Shader { // A function from finalizer must not be blocked, but disposing operation can be blocked. // Defer this operation until it becomes safe. (#913) func (s *Shader) MarkDisposed() { + backendsM.Lock() + defer backendsM.Unlock() + deferredM.Lock() deferred = append(deferred, func() { s.dispose() diff --git a/internal/processtest/testdata/issue2129.go b/internal/processtest/testdata/issue2129.go new file mode 100644 index 000000000..ceaf0bb60 --- /dev/null +++ b/internal/processtest/testdata/issue2129.go @@ -0,0 +1,70 @@ +// Copyright 2022 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. + +//go:build ignore +// +build ignore + +package main + +import ( + "errors" + + "github.com/hajimehoshi/ebiten/v2" +) + +var regularTermination = errors.New("regular termination") + +type Game struct { + count int +} + +func (g *Game) Update() error { + const shaderData = ` +package main + +func Fragment(position vec4, texCoord vec2, color vec4) vec4 { + return vec4(1) +} +` + g.count++ + if g.count == 16 { + return regularTermination + } + + if g.count < 8 { + go func() { + s, err := ebiten.NewShader([]byte(shaderData)) + if err != nil { + panic(err) + } + s.Dispose() + }() + return nil + } + + return nil +} + +func (g *Game) Draw(screen *ebiten.Image) { +} + +func (g *Game) Layout(width, height int) (int, int) { + return width, height +} + +func main() { + if err := ebiten.RunGame(&Game{}); err != nil && err != regularTermination { + panic(err) + } +}