@@ -46,13 +46,14 @@ export class WebglRenderer extends Disposable implements IRenderer {
4646
4747 private _canvas : HTMLCanvasElement ;
4848 private _gl : IWebGL2RenderingContext ;
49- private _rectangleRenderer : RectangleRenderer ;
50- private _glyphRenderer : GlyphRenderer ;
49+ private _rectangleRenderer ! : RectangleRenderer ;
50+ private _glyphRenderer ! : GlyphRenderer ;
5151
5252 public dimensions : IRenderDimensions ;
5353
5454 private _core : ITerminal ;
5555 private _isAttached : boolean ;
56+ private _contextRestorationTimeout : number | undefined ;
5657
5758 private _onChangeTextureAtlas = new EventEmitter < HTMLCanvasElement > ( ) ;
5859 public get onChangeTextureAtlas ( ) : IEvent < HTMLCanvasElement > { return this . _onChangeTextureAtlas . event ; }
@@ -108,16 +109,34 @@ export class WebglRenderer extends Disposable implements IRenderer {
108109 throw new Error ( 'WebGL2 not supported ' + this . _gl ) ;
109110 }
110111
111- this . register ( addDisposableDomListener ( this . _canvas , 'webglcontextlost' , ( e ) => { this . _onContextLoss . fire ( e ) ; } ) ) ;
112+ this . register ( addDisposableDomListener ( this . _canvas , 'webglcontextlost' , ( e ) => {
113+ console . log ( 'webglcontextlost event received' ) ;
114+ // Prevent the default behavior in order to enable WebGL context restoration.
115+ e . preventDefault ( ) ;
116+ // Wait a few seconds to see if the 'webglcontextrestored' event is fired.
117+ // If not, dispatch the onContextLoss notification to observers.
118+ this . _contextRestorationTimeout = setTimeout ( ( ) => {
119+ this . _contextRestorationTimeout = undefined ;
120+ console . warn ( 'webgl context not restored; firing onContextLoss' ) ;
121+ this . _onContextLoss . fire ( e ) ;
122+ } , 3000 /* ms */ ) ;
123+ } ) ) ;
124+ this . register ( addDisposableDomListener ( this . _canvas , 'webglcontextrestored' , ( e ) => {
125+ console . warn ( 'webglcontextrestored event received' ) ;
126+ clearTimeout ( this . _contextRestorationTimeout ) ;
127+ this . _contextRestorationTimeout = undefined ;
128+ // The texture atlas and glyph renderer must be fully reinitialized
129+ // because their contents have been lost.
130+ removeTerminalFromCache ( this . _terminal ) ;
131+ this . _initializeWebGLState ( ) ;
132+ this . _requestRedrawViewport ( ) ;
133+ } ) ) ;
134+
112135 this . register ( observeDevicePixelDimensions ( this . _canvas , ( w , h ) => this . _setCanvasDevicePixelDimensions ( w , h ) ) ) ;
113136
114137 this . _core . screenElement ! . appendChild ( this . _canvas ) ;
115138
116- this . _rectangleRenderer = this . register ( new RectangleRenderer ( this . _terminal , this . _colors , this . _gl , this . dimensions ) ) ;
117- this . _glyphRenderer = this . register ( new GlyphRenderer ( this . _terminal , this . _colors , this . _gl , this . dimensions ) ) ;
118-
119- // Update dimensions and acquire char atlas
120- this . onCharSizeChanged ( ) ;
139+ this . _initializeWebGLState ( ) ;
121140
122141 this . _isAttached = document . body . contains ( this . _core . screenElement ! ) ;
123142 }
@@ -235,6 +254,21 @@ export class WebglRenderer extends Disposable implements IRenderer {
235254 this . _refreshCharAtlas ( ) ;
236255 }
237256
257+ /**
258+ * Initializes members dependent on WebGL context state.
259+ */
260+ private _initializeWebGLState ( ) : void {
261+ // Dispose any previous rectangle and glyph renderers before creating new ones.
262+ this . _rectangleRenderer ?. dispose ( ) ;
263+ this . _glyphRenderer ?. dispose ( ) ;
264+
265+ this . _rectangleRenderer = new RectangleRenderer ( this . _terminal , this . _colors , this . _gl , this . dimensions ) ;
266+ this . _glyphRenderer = new GlyphRenderer ( this . _terminal , this . _colors , this . _gl , this . dimensions ) ;
267+
268+ // Update dimensions and acquire char atlas
269+ this . onCharSizeChanged ( ) ;
270+ }
271+
238272 /**
239273 * Refreshes the char atlas, aquiring a new one if necessary.
240274 * @param terminal The terminal.
0 commit comments