From e07b9684bb0e76b7bc4ef44747d66847a3745e17 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 6 Sep 2020 14:50:07 -0700 Subject: [PATCH] Expose API to clear texture atlas Using canvases on Electron (and plain Chromium I believe), when resuming from sleep the graphics card may release the texture which results in the terminal display and char atlas being corrupt. This API allows the consumer to clear the texture atlas right after resuming, atlas warm up is not done to simplify this process because the fact that atlases are shared between multiple terminals complicates this. Related microsoft/vscode#69665 --- addons/xterm-addon-webgl/src/RenderModel.ts | 1 - addons/xterm-addon-webgl/src/WebglAddon.ts | 4 ++++ addons/xterm-addon-webgl/src/WebglRenderer.ts | 11 +++++++++ .../src/atlas/WebglCharAtlas.ts | 23 +++++++++++++------ .../typings/xterm-addon-webgl.d.ts | 9 ++++++-- src/browser/renderer/atlas/BaseCharAtlas.ts | 2 +- 6 files changed, 39 insertions(+), 11 deletions(-) diff --git a/addons/xterm-addon-webgl/src/RenderModel.ts b/addons/xterm-addon-webgl/src/RenderModel.ts index 194f1778..b93e1e85 100644 --- a/addons/xterm-addon-webgl/src/RenderModel.ts +++ b/addons/xterm-addon-webgl/src/RenderModel.ts @@ -43,7 +43,6 @@ export class RenderModel implements IRenderModel { public clear(): void { fill(this.cells, 0, 0); fill(this.lineLengths, 0, 0); - this.clearSelection(); } public clearSelection(): void { diff --git a/addons/xterm-addon-webgl/src/WebglAddon.ts b/addons/xterm-addon-webgl/src/WebglAddon.ts index 77812a6f..aef1301e 100644 --- a/addons/xterm-addon-webgl/src/WebglAddon.ts +++ b/addons/xterm-addon-webgl/src/WebglAddon.ts @@ -40,4 +40,8 @@ export class WebglAddon implements ITerminalAddon { public get textureAtlas(): HTMLCanvasElement | undefined { return this._renderer?.textureAtlas; } + + public clearTextureAtlas(): void { + this._renderer?.clearCharAtlas(); + } } diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index ac997c96..9f982165 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -121,6 +121,7 @@ export class WebglRenderer extends Disposable implements IRenderer { // Force a full refresh this._model.clear(); + this._model.clearSelection(); } public onDevicePixelRatioChange(): void { @@ -158,6 +159,7 @@ export class WebglRenderer extends Disposable implements IRenderer { // Force a full refresh this._model.clear(); + this._model.clearSelection(); } public onCharSizeChanged(): void { @@ -214,6 +216,14 @@ export class WebglRenderer extends Disposable implements IRenderer { this._glyphRenderer.setAtlas(this._charAtlas); } + public clearCharAtlas(): void { + this._charAtlas?.clearTexture(); + this._model.clear(); + this._updateModel(0, this._terminal.rows - 1); + this._glyphRenderer.updateSelection(this._model); + this._onRequestRedraw.fire({ start: 0, end: this._terminal.rows - 1 }); + } + public clear(): void { this._renderLayers.forEach(l => l.reset(this._terminal)); } @@ -243,6 +253,7 @@ export class WebglRenderer extends Disposable implements IRenderer { // Tell renderer the frame is beginning if (this._glyphRenderer.beginFrame()) { this._model.clear(); + this._model.clearSelection(); } // Update model to reflect what's drawn diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index d9475cb4..223ec16a 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -101,7 +101,7 @@ export class WebglCharAtlas implements IDisposable { } } - protected _doWarmUp(): void { + private _doWarmUp(): void { // Pre-fill with ASCII 33-126 for (let i = 33; i < 126; i++) { const rasterizedGlyph = this._drawToCache(i, DEFAULT_COLOR, DEFAULT_COLOR); @@ -115,17 +115,26 @@ export class WebglCharAtlas implements IDisposable { public beginFrame(): boolean { if (this._currentRowY > TEXTURE_CAPACITY) { - this._cacheCtx.clearRect(0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT); - this._cacheMap = {}; - this._currentRowHeight = 0; - this._currentRowX = 0; - this._currentRowY = 0; - this._doWarmUp(); + this.clearTexture(); + this.warmUp(); return true; } return false; } + public clearTexture(): void { + if (this._currentRowX === 0 && this._currentRowY === 0) { + return; + } + this._cacheCtx.clearRect(0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT); + this._cacheMap = {}; + this._cacheMapCombined = {}; + this._currentRowHeight = 0; + this._currentRowX = 0; + this._currentRowY = 0; + this._didWarmUp = false; + } + public getRasterizedGlyphCombinedChar(chars: string, bg: number, fg: number): IRasterizedGlyph { let rasterizedGlyphSet = this._cacheMapCombined[chars]; if (!rasterizedGlyphSet) { diff --git a/addons/xterm-addon-webgl/typings/xterm-addon-webgl.d.ts b/addons/xterm-addon-webgl/typings/xterm-addon-webgl.d.ts index 9586433a..5c15aa17 100644 --- a/addons/xterm-addon-webgl/typings/xterm-addon-webgl.d.ts +++ b/addons/xterm-addon-webgl/typings/xterm-addon-webgl.d.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { Terminal, IDisposable, ITerminalAddon } from 'xterm'; +import { Terminal, ITerminalAddon } from 'xterm'; declare module 'xterm-addon-webgl' { /** @@ -15,7 +15,7 @@ declare module 'xterm-addon-webgl' { constructor(preserveDrawingBuffer?: boolean); /** - * Activates the addon + * Activates the addon. * @param terminal The terminal the addon is being loaded in. */ public activate(terminal: Terminal): void; @@ -24,5 +24,10 @@ declare module 'xterm-addon-webgl' { * Disposes the addon. */ public dispose(): void; + + /** + * Clears the terminal's texture atlas and triggers a redraw. + */ + public clearTextureAtlas(): void; } } diff --git a/src/browser/renderer/atlas/BaseCharAtlas.ts b/src/browser/renderer/atlas/BaseCharAtlas.ts index dc114601..4ebaaa47 100644 --- a/src/browser/renderer/atlas/BaseCharAtlas.ts +++ b/src/browser/renderer/atlas/BaseCharAtlas.ts @@ -26,7 +26,7 @@ export abstract class BaseCharAtlas implements IDisposable { * Perform any work needed to warm the cache before it can be used. Used by the default * implementation of warmUp(), and will only be called once. */ - protected _doWarmUp(): void { } + private _doWarmUp(): void { } /** * Called when we start drawing a new frame.