mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-12 22:17:26 +01:00
parent
97d1e073e2
commit
bdd8916bb1
@ -38,25 +38,22 @@ func (s *Shader) ensureShader() *restorable.Shader {
|
|||||||
return s.shader
|
return s.shader
|
||||||
}
|
}
|
||||||
s.shader = restorable.NewShader(s.ir)
|
s.shader = restorable.NewShader(s.ir)
|
||||||
s.ir = nil
|
runtime.SetFinalizer(s, func(s *Shader) {
|
||||||
|
// A function from finalizer must not be blocked, but disposing operation can be blocked.
|
||||||
|
// Defer this operation until it becomes safe. (#913)
|
||||||
|
appendDeferred(func() {
|
||||||
|
s.deallocate()
|
||||||
|
})
|
||||||
|
})
|
||||||
return s.shader
|
return s.shader
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarkDisposed marks the shader as disposed. The actual operation is deferred.
|
// Deallocate deallocates the internal state.
|
||||||
// MarkDisposed can be called from finalizers.
|
func (s *Shader) Deallocate() {
|
||||||
//
|
s.deallocate()
|
||||||
// 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() {
|
|
||||||
// As MarkDisposed can be invoked from finalizers, backendsM should not be used.
|
|
||||||
deferredM.Lock()
|
|
||||||
deferred = append(deferred, func() {
|
|
||||||
s.dispose()
|
|
||||||
})
|
|
||||||
deferredM.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Shader) dispose() {
|
func (s *Shader) deallocate() {
|
||||||
runtime.SetFinalizer(s, nil)
|
runtime.SetFinalizer(s, nil)
|
||||||
if s.shader == nil {
|
if s.shader == nil {
|
||||||
return
|
return
|
||||||
|
@ -40,9 +40,8 @@ func NewShader(ir *shaderir.Program) *Shader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Shader) MarkDisposed() {
|
func (s *Shader) Deallocate() {
|
||||||
s.shader.MarkDisposed()
|
s.shader.Deallocate()
|
||||||
s.shader = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Shader) AppendUniforms(dst []uint32, uniforms map[string]any) []uint32 {
|
func (s *Shader) AppendUniforms(dst []uint32, uniforms map[string]any) []uint32 {
|
||||||
|
15
shader.go
15
shader.go
@ -50,11 +50,24 @@ func NewShader(src []byte) (*Shader, error) {
|
|||||||
|
|
||||||
// Dispose disposes the shader program.
|
// Dispose disposes the shader program.
|
||||||
// After disposing, the shader is no longer available.
|
// After disposing, the shader is no longer available.
|
||||||
|
//
|
||||||
|
// Deprecated: as of v2.7. Use Deallocate instead.
|
||||||
func (s *Shader) Dispose() {
|
func (s *Shader) Dispose() {
|
||||||
s.shader.MarkDisposed()
|
s.shader.Deallocate()
|
||||||
s.shader = nil
|
s.shader = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deallocate deallocates the internal state of shader.
|
||||||
|
// Even after Deallocate is called, the shader is still available.
|
||||||
|
// In this case, the shader's internal state is allocated again.
|
||||||
|
//
|
||||||
|
// Usually, you don't have to call Deallocate since the internal state is automatically released by GC.
|
||||||
|
// However, if you are sure that the shader is no longer used but not sure how this shader object is referred,
|
||||||
|
// you can call Deallocate to make sure that the internal state is deallocated.
|
||||||
|
func (s *Shader) Deallocate() {
|
||||||
|
s.shader.Deallocate()
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Shader) appendUniforms(dst []uint32, uniforms map[string]any) []uint32 {
|
func (s *Shader) appendUniforms(dst []uint32, uniforms map[string]any) []uint32 {
|
||||||
return s.shader.AppendUniforms(dst, uniforms)
|
return s.shader.AppendUniforms(dst, uniforms)
|
||||||
}
|
}
|
||||||
|
@ -2299,3 +2299,54 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestShaderDeallocate(t *testing.T) {
|
||||||
|
const w, h = 16, 16
|
||||||
|
|
||||||
|
dst := ebiten.NewImage(w, h)
|
||||||
|
s, err := ebiten.NewShader([]byte(`//kage:unit pixels
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {
|
||||||
|
return vec4(1, 0, 0, 1)
|
||||||
|
}
|
||||||
|
`))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dst.DrawRectShader(w/2, h/2, s, nil)
|
||||||
|
|
||||||
|
for j := 0; j < h; j++ {
|
||||||
|
for i := 0; i < w; i++ {
|
||||||
|
got := dst.At(i, j).(color.RGBA)
|
||||||
|
var want color.RGBA
|
||||||
|
if i < w/2 && j < h/2 {
|
||||||
|
want = color.RGBA{R: 0xff, A: 0xff}
|
||||||
|
}
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Even after Deallocate is called, the shader is still available.
|
||||||
|
s.Deallocate()
|
||||||
|
|
||||||
|
dst.Clear()
|
||||||
|
dst.DrawRectShader(w/2, h/2, s, nil)
|
||||||
|
|
||||||
|
for j := 0; j < h; j++ {
|
||||||
|
for i := 0; i < w; i++ {
|
||||||
|
got := dst.At(i, j).(color.RGBA)
|
||||||
|
var want color.RGBA
|
||||||
|
if i < w/2 && j < h/2 {
|
||||||
|
want = color.RGBA{R: 0xff, A: 0xff}
|
||||||
|
}
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user