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 {
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) {

View File

@ -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
}

View File

@ -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

View File

@ -17,3 +17,5 @@
package restorable
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/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{} {