diff --git a/internal/graphicsdriver/opengl/context_js.go b/internal/graphicsdriver/opengl/context_js.go index e766c9e15..3290749d9 100644 --- a/internal/graphicsdriver/opengl/context_js.go +++ b/internal/graphicsdriver/opengl/context_js.go @@ -309,9 +309,8 @@ func (c *context) deleteTexture(t textureNative) { } func (c *context) isTexture(t textureNative) bool { - c.ensureGL() - gl := c.gl - return gl.Call("isTexture", js.Value(t)).Bool() + // isTexture should not be called to detect context-lost since this performance is not good (#1175). + panic("opengl: isTexture is not implemented") } func (c *context) newFramebuffer(t textureNative) (framebufferNative, error) { diff --git a/internal/restorable/images.go b/internal/restorable/images.go index 4ffaeac41..fc42b1129 100644 --- a/internal/restorable/images.go +++ b/internal/restorable/images.go @@ -39,9 +39,10 @@ func EnableRestoringForTesting() { // images is a set of Image objects. type images struct { - images map[*Image]struct{} - shaders map[*Shader]struct{} - lastTarget *Image + images map[*Image]struct{} + shaders map[*Shader]struct{} + lastTarget *Image + contextLost bool } // theImages represents the images for the current process. @@ -73,21 +74,27 @@ func RestoreIfNeeded() error { } if !forceRestoring { - r := false - // 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. - for img := range theImages.images { - // The screen image might not have a texture. Skip this. - if img.screen { - continue + var r bool + + if canDetectContextLostExplicitly { + r = theImages.contextLost + } else { + // 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. + 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 { return nil } @@ -257,6 +264,9 @@ func (i *images) restore() error { return err } } + + i.contextLost = false + return nil } @@ -264,3 +274,11 @@ func (i *images) restore() error { func InitializeGraphicsDriverState() error { 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 +} diff --git a/internal/restorable/js.go b/internal/restorable/js.go index 8a14cda21..fe62b4f63 100644 --- a/internal/restorable/js.go +++ b/internal/restorable/js.go @@ -16,7 +16,11 @@ 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 // are already invalidated. Rather, disposing them when restoring causes warnings on the console. - const needsDisposingWhenRestoring = false + +// canDetectContextLostExplicitly reports whether the context lost can be detected by handlers in an explicit way. +const canDetectContextLostExplicitly = true diff --git a/internal/restorable/notjs.go b/internal/restorable/notjs.go index b5989c031..97df2664c 100644 --- a/internal/restorable/notjs.go +++ b/internal/restorable/notjs.go @@ -17,3 +17,5 @@ package restorable const needsDisposingWhenRestoring = true + +const canDetectContextLostExplicitly = false diff --git a/internal/uidriver/js/ui.go b/internal/uidriver/js/ui.go index f8e449b72..e7fd71828 100644 --- a/internal/uidriver/js/ui.go +++ b/internal/uidriver/js/ui.go @@ -27,6 +27,7 @@ import ( "github.com/hajimehoshi/ebiten/internal/graphicsdriver/opengl" "github.com/hajimehoshi/ebiten/internal/hooks" "github.com/hajimehoshi/ebiten/internal/jsutil" + "github.com/hajimehoshi/ebiten/internal/restorable" ) type UserInterface struct { @@ -400,6 +401,7 @@ func init() { e := args[0] e.Call("preventDefault") theUI.contextLost = true + restorable.OnContextLost() return nil })) canvas.Call("addEventListener", "webglcontextrestored", js.FuncOf(func(this js.Value, args []js.Value) interface{} {