restorable: Add tests to dispose shaders

When a shader is disposed, all the images depending on it should
become stale, i.e., discard its all the rendering history items,
because they cannot be restored due to the lack of data on the GPU.
This commit is contained in:
Hajime Hoshi 2020-05-26 00:20:08 +09:00
parent 8e6f19b37a
commit 7b9cc8deb4
3 changed files with 65 additions and 9 deletions

View File

@ -470,6 +470,16 @@ func (i *Image) makeStaleIfDependingOn(target *Image) {
}
}
// makeStaleIfDependingOnShader makes the image stale if the image depends on shader.
func (i *Image) makeStaleIfDependingOnShader(shader *Shader) {
if i.stale {
return
}
if i.dependsOnShader(shader) {
i.makeStale()
}
}
// readPixelsFromGPU reads the pixels from GPU and resolves the image's 'stale' state.
func (i *Image) readPixelsFromGPU() error {
pix, err := i.image.Pixels()
@ -516,6 +526,16 @@ func (i *Image) dependsOn(target *Image) bool {
return false
}
// dependsOnShader reports whether the image depends on shader.
func (i *Image) dependsOnShader(shader *Shader) bool {
for _, c := range i.drawTrianglesHistory {
if c.shader == shader {
return true
}
}
return false
}
// dependingImages returns all images that is depended by the image.
func (i *Image) dependingImages() map[*Image]struct{} {
r := map[*Image]struct{}{}

View File

@ -126,14 +126,12 @@ func (i *images) addShader(shader *Shader) {
// remove removes img from the images.
func (i *images) remove(img *Image) {
i.makeStaleIfDependingOnImpl(img)
i.makeStaleIfDependingOn(img)
delete(i.images, img)
}
func (i *images) removeShader(shader *Shader) {
// TODO: Do we have to make images stale?
// However, dependencies are determiend by uniform variables...
// ??
i.makeStaleIfDependingOnShader(shader)
delete(i.shaders, shader)
}
@ -153,12 +151,8 @@ func (i *images) resolveStaleImages() error {
// When target is modified, all images depending on target can't be restored with target.
// makeStaleIfDependingOn is called in such situation.
func (i *images) makeStaleIfDependingOn(target *Image) {
i.makeStaleIfDependingOnImpl(target)
}
func (i *images) makeStaleIfDependingOnImpl(target *Image) {
if target == nil {
panic("restorable: target must not be nil at makeStaleIfDependingOnImpl")
panic("restorable: target must not be nil at makeStaleIfDependingOn")
}
if i.lastTarget == target {
return
@ -169,6 +163,16 @@ func (i *images) makeStaleIfDependingOnImpl(target *Image) {
}
}
// makeStaleIfDependingOn makes all the images stale that depend on shader.
func (i *images) makeStaleIfDependingOnShader(shader *Shader) {
if shader == nil {
panic("restorable: shader must not be nil at makeStaleIfDependingOnShader")
}
for img := range i.images {
img.makeStaleIfDependingOnShader(shader)
}
}
// restore restores the images.
//
// Restoring means to make all *graphicscommand.Image objects have their textures and framebuffers.

View File

@ -136,3 +136,35 @@ func TestShaderMultipleSources(t *testing.T) {
t.Errorf("got %v, want %v", got, want)
}
}
func TestShaderDispose(t *testing.T) {
if !graphicscommand.IsShaderAvailable() {
t.Skip("shader is not available on this environment")
}
img := NewImage(1, 1, false)
defer img.Dispose()
ir := etesting.ShaderProgramFill(0xff, 0, 0, 0xff)
s := NewShader(&ir)
us := map[int]interface{}{
0: []float32{1, 1},
}
img.DrawTriangles(nil, quadVertices(1, 1, 0, 0), graphics.QuadIndices(), nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, s, us)
// Dispose the shader. This should invalidates (= being stale) all the images using this shader.
s.Dispose()
if err := ResolveStaleImages(); err != nil {
t.Fatal(err)
}
if err := RestoreIfNeeded(); err != nil {
t.Fatal(err)
}
want := color.RGBA{0xff, 0, 0, 0xff}
got := pixelsToColor(img.BasePixelsForTesting(), 0, 0)
if !sameColors(got, want, 1) {
t.Errorf("got %v, want %v", got, want)
}
}