restorable: Add an explicit way to detect context-lost

isTexture was used to detect context-lost and called every frame.
This was not good for performance.

This change adds a way to notify context-lost from the WebGL
handlers directly, and the package restorable uses it instead of
calling (*Image).isInvalaidated.

Fixes #1175
This commit is contained in:
Hajime Hoshi 2020-05-30 19:43:59 +09:00
parent 117fd61d27
commit 2bdef2e8c4
5 changed files with 45 additions and 20 deletions

View File

@ -309,9 +309,8 @@ func (c *context) deleteTexture(t textureNative) {
} }
func (c *context) isTexture(t textureNative) bool { func (c *context) isTexture(t textureNative) bool {
c.ensureGL() // isTexture should not be called to detect context-lost since this performance is not good (#1175).
gl := c.gl panic("opengl: isTexture is not implemented")
return gl.Call("isTexture", js.Value(t)).Bool()
} }
func (c *context) newFramebuffer(t textureNative) (framebufferNative, error) { func (c *context) newFramebuffer(t textureNative) (framebufferNative, error) {

View File

@ -39,9 +39,10 @@ func EnableRestoringForTesting() {
// images is a set of Image objects. // images is a set of Image objects.
type images struct { type images struct {
images map[*Image]struct{} images map[*Image]struct{}
shaders map[*Shader]struct{} shaders map[*Shader]struct{}
lastTarget *Image lastTarget *Image
contextLost bool
} }
// theImages represents the images for the current process. // theImages represents the images for the current process.
@ -73,21 +74,27 @@ func RestoreIfNeeded() error {
} }
if !forceRestoring { if !forceRestoring {
r := false var r bool
// As isInvalidated() is expensive, call this only for one image.
// This assumes that if there is one image that is invalidated, all images are invalidated. if canDetectContextLostExplicitly {
for img := range theImages.images { r = theImages.contextLost
// The screen image might not have a texture. Skip this. } else {
if img.screen { // As isInvalidated() is expensive, call this only for one image.
continue // This assumes that if there is one image that is invalidated, all images are invalidated.
for img := range theImages.images {
// The screen image might not have a texture. Skip this.
if img.screen {
continue
}
var err error
r, err = img.isInvalidated()
if err != nil {
return err
}
break
} }
var err error
r, err = img.isInvalidated()
if err != nil {
return err
}
break
} }
if !r { if !r {
return nil return nil
} }
@ -257,6 +264,9 @@ func (i *images) restore() error {
return err return err
} }
} }
i.contextLost = false
return nil return nil
} }
@ -264,3 +274,11 @@ func (i *images) restore() error {
func InitializeGraphicsDriverState() error { func InitializeGraphicsDriverState() error {
return graphicscommand.ResetGraphicsDriverState() return graphicscommand.ResetGraphicsDriverState()
} }
// OnContextLost is called when the context lost is detected in an explicit way.
func OnContextLost() {
if !canDetectContextLostExplicitly {
panic("restorable: OnContextLost cannot be called in this environment")
}
theImages.contextLost = true
}

View File

@ -16,7 +16,11 @@
package restorable package restorable
// needsDisposingWhenRestoring reports whether disposing resources is necessary or not when restoring.
//
// On browsers, disposing resources is not required since the objects are already managed by JavaScript GC and they // On browsers, disposing resources is not required since the objects are already managed by JavaScript GC and they
// are already invalidated. Rather, disposing them when restoring causes warnings on the console. // are already invalidated. Rather, disposing them when restoring causes warnings on the console.
const needsDisposingWhenRestoring = false const needsDisposingWhenRestoring = false
// canDetectContextLostExplicitly reports whether the context lost can be detected by handlers in an explicit way.
const canDetectContextLostExplicitly = true

View File

@ -17,3 +17,5 @@
package restorable package restorable
const needsDisposingWhenRestoring = true const needsDisposingWhenRestoring = true
const canDetectContextLostExplicitly = false

View File

@ -27,6 +27,7 @@ import (
"github.com/hajimehoshi/ebiten/internal/graphicsdriver/opengl" "github.com/hajimehoshi/ebiten/internal/graphicsdriver/opengl"
"github.com/hajimehoshi/ebiten/internal/hooks" "github.com/hajimehoshi/ebiten/internal/hooks"
"github.com/hajimehoshi/ebiten/internal/jsutil" "github.com/hajimehoshi/ebiten/internal/jsutil"
"github.com/hajimehoshi/ebiten/internal/restorable"
) )
type UserInterface struct { type UserInterface struct {
@ -400,6 +401,7 @@ func init() {
e := args[0] e := args[0]
e.Call("preventDefault") e.Call("preventDefault")
theUI.contextLost = true theUI.contextLost = true
restorable.OnContextLost()
return nil return nil
})) }))
canvas.Call("addEventListener", "webglcontextrestored", js.FuncOf(func(this js.Value, args []js.Value) interface{} { canvas.Call("addEventListener", "webglcontextrestored", js.FuncOf(func(this js.Value, args []js.Value) interface{} {