ebiten: make sure panicking with a disposed shader

This commit is contained in:
Hajime Hoshi 2023-11-04 00:28:14 +09:00
parent c01ceeaa6a
commit 95f7204035
3 changed files with 56 additions and 0 deletions

View File

@ -586,6 +586,10 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader
return return
} }
if shader.isDisposed() {
panic("ebiten: the given shader to DrawTrianglesShader must not be disposed")
}
if len(vertices) > graphics.MaxVerticesCount { if len(vertices) > graphics.MaxVerticesCount {
// The last part cannot be specified by indices. Just omit them. // The last part cannot be specified by indices. Just omit them.
vertices = vertices[:graphics.MaxVerticesCount] vertices = vertices[:graphics.MaxVerticesCount]
@ -737,6 +741,10 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR
return return
} }
if shader.isDisposed() {
panic("ebiten: the given shader to DrawRectShader must not be disposed")
}
if options == nil { if options == nil {
options = &DrawRectShaderOptions{} options = &DrawRectShaderOptions{}
} }

View File

@ -57,6 +57,10 @@ func (s *Shader) Dispose() {
s.shader = nil s.shader = nil
} }
func (s *Shader) isDisposed() bool {
return s.shader == nil
}
// Deallocate deallocates the internal state of the shader. // Deallocate deallocates the internal state of the shader.
// Even after Deallocate is called, the shader is still available. // Even after Deallocate is called, the shader is still available.
// In this case, the shader's internal state is allocated again. // In this case, the shader's internal state is allocated again.

View File

@ -2300,6 +2300,50 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {
} }
} }
func TestShaderDispose(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)
}
}
}
s.Dispose()
dst.Clear()
defer func() {
if e := recover(); e == nil {
panic("DrawRectShader with a disposed shader must panic but not")
}
}()
dst.DrawRectShader(w/2, h/2, s, nil)
}
func TestShaderDeallocate(t *testing.T) { func TestShaderDeallocate(t *testing.T) {
const w, h = 16, 16 const w, h = 16, 16