diff --git a/app/internal/window/window.go b/app/internal/window/window.go index c351fdec..c9c94761 100644 --- a/app/internal/window/window.go +++ b/app/internal/window/window.go @@ -40,6 +40,11 @@ type Context interface { Unlock() } +// ErrDeviceLost is returned from Context.Present when +// the underlying GPU device is gone and should be +// recreated. +var ErrDeviceLost = errors.New("GPU device lost") + // Driver is the interface for the platform implementation // of a window. type Driver interface { diff --git a/app/window.go b/app/window.go index 195e7c0c..e4a15a8b 100644 --- a/app/window.go +++ b/app/window.go @@ -252,8 +252,7 @@ func (w *Window) run(opts *window.Options) { case system.StageEvent: if w.loop != nil { if e2.Stage < system.StageRunning { - w.loop.Release() - w.loop = nil + w.destroyGPU() } else { w.loop.Refresh() } @@ -274,24 +273,10 @@ func (w *Window) run(opts *window.Options) { w.hasNextFrame = false e2.Frame = w.update w.out <- e2.FrameEvent - var err error if w.loop != nil { if e2.Sync { w.loop.Refresh() } - if err = w.loop.Flush(); err != nil { - w.loop.Release() - w.loop = nil - } - } else { - var ctx window.Context - ctx, err = w.driver.NewContext() - if err == nil { - w.loop, err = newLoop(ctx) - if err != nil { - ctx.Release() - } - } } var frame *op.Ops // Wait for either a frame or an ack event to go @@ -303,25 +288,46 @@ func (w *Window) run(opts *window.Options) { gotFrame = true case w.out <- ackEvent: } - if err != nil { - if gotFrame { - w.frameAck <- struct{}{} + var err error + for { + if w.loop != nil { + if err = w.loop.Flush(); err != nil { + w.destroyGPU() + if err != window.ErrDeviceLost { + break + } + } + } + if w.loop == nil { + var ctx window.Context + ctx, err = w.driver.NewContext() + if err != nil { + break + } + w.loop, err = newLoop(ctx) + if err != nil { + ctx.Release() + break + } + } + w.draw(frameStart, e2.Size, frame) + if e2.Sync { + if err = w.loop.Flush(); err != nil { + w.destroyGPU() + } + } + if err != window.ErrDeviceLost { + break } - w.destroy(err) - return } - w.draw(frameStart, e2.Size, frame) if gotFrame { // We're done with frame, let the client continue. w.frameAck <- struct{}{} } - if e2.Sync { - if err := w.loop.Flush(); err != nil { - w.loop.Release() - w.loop = nil - w.destroy(err) - return - } + if err != nil { + w.destroyGPU() + w.destroy(err) + return } case *system.CommandEvent: w.out <- e