From 2f72682e5d0b9e2115b3062f55f47c90f134db7c Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 1 Aug 2022 09:29:26 -0700 Subject: [PATCH] Add canvas renderer addon --- .eslintrc.json | 1 + build/.webignore | 3 + package.json | 1 + remote/package.json | 1 + remote/web/package.json | 1 + remote/web/yarn.lock | 5 ++ remote/yarn.lock | 5 ++ scripts/update-xterm.js | 1 + src/bootstrap-window.js | 3 +- .../terminal/browser/xterm/xtermTerminal.ts | 66 ++++++++++++++++--- yarn.lock | 5 ++ 11 files changed, 83 insertions(+), 9 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index af34ee181a9..d86f6103a7d 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -259,6 +259,7 @@ "windows-process-tree", "worker_threads", "xterm", + "xterm-addon-canvas", "xterm-addon-search", "xterm-addon-serialize", "xterm-addon-unicode11", diff --git a/build/.webignore b/build/.webignore index 563dfb0000c..1a5b3ee2c10 100644 --- a/build/.webignore +++ b/build/.webignore @@ -20,6 +20,9 @@ vscode-textmate/webpack.config.js xterm/src/** +xterm-addon-canvas/src/** +xterm-addon-canvas/out/** + xterm-addon-search/src/** xterm-addon-search/out/** xterm-addon-search/fixtures/** diff --git a/package.json b/package.json index 5d91cf0a232..23a4ea7b32b 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,7 @@ "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", "xterm": "5.0.0-beta.32", + "xterm-addon-canvas": "0.2.0-beta.15", "xterm-addon-search": "0.10.0-beta.3", "xterm-addon-serialize": "0.8.0-beta.3", "xterm-addon-unicode11": "0.4.0-beta.3", diff --git a/remote/package.json b/remote/package.json index b8da1151d24..68e36b12bc9 100644 --- a/remote/package.json +++ b/remote/package.json @@ -25,6 +25,7 @@ "vscode-regexpp": "^3.1.0", "vscode-textmate": "7.0.1", "xterm": "5.0.0-beta.32", + "xterm-addon-canvas": "0.2.0-beta.15", "xterm-addon-search": "0.10.0-beta.3", "xterm-addon-serialize": "0.8.0-beta.3", "xterm-addon-unicode11": "0.4.0-beta.3", diff --git a/remote/web/package.json b/remote/web/package.json index 7a230e76868..17c98d4f00b 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -12,6 +12,7 @@ "vscode-oniguruma": "1.6.1", "vscode-textmate": "7.0.1", "xterm": "5.0.0-beta.32", + "xterm-addon-canvas": "0.2.0-beta.15", "xterm-addon-search": "0.10.0-beta.3", "xterm-addon-unicode11": "0.4.0-beta.3", "xterm-addon-webgl": "0.13.0-beta.32" diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 87c4c4d35ff..352fc68499b 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -68,6 +68,11 @@ vscode-textmate@7.0.1: resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-7.0.1.tgz#8118a32b02735dccd14f893b495fa5389ad7de79" integrity sha512-zQ5U/nuXAAMsh691FtV0wPz89nSkHbs+IQV8FDk+wew9BlSDhf4UmWGlWJfTR2Ti6xZv87Tj5fENzKf6Qk7aLw== +xterm-addon-canvas@0.2.0-beta.15: + version "0.2.0-beta.15" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.2.0-beta.15.tgz#de863e46410b1de357b153abf1984227777760e4" + integrity sha512-E1pNCDSVTINchwWLysZ9ZD/BPv1WLGV52xRHB00US1PHHELbhtvms+6dZ44WZEDXhtfpptRZ1VBx+QpvfJIuvw== + xterm-addon-search@0.10.0-beta.3: version "0.10.0-beta.3" resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.10.0-beta.3.tgz#5194434d86105637c71f6f20139a9d0b5c1a956a" diff --git a/remote/yarn.lock b/remote/yarn.lock index c729673b610..5e5938f14a9 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -788,6 +788,11 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +xterm-addon-canvas@0.2.0-beta.15: + version "0.2.0-beta.15" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.2.0-beta.15.tgz#de863e46410b1de357b153abf1984227777760e4" + integrity sha512-E1pNCDSVTINchwWLysZ9ZD/BPv1WLGV52xRHB00US1PHHELbhtvms+6dZ44WZEDXhtfpptRZ1VBx+QpvfJIuvw== + xterm-addon-search@0.10.0-beta.3: version "0.10.0-beta.3" resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.10.0-beta.3.tgz#5194434d86105637c71f6f20139a9d0b5c1a956a" diff --git a/scripts/update-xterm.js b/scripts/update-xterm.js index 70637a8493c..ac11b9e3217 100644 --- a/scripts/update-xterm.js +++ b/scripts/update-xterm.js @@ -8,6 +8,7 @@ const path = require('path'); const moduleNames = [ 'xterm', + 'xterm-addon-canvas', 'xterm-addon-search', 'xterm-addon-unicode11', 'xterm-addon-webgl' diff --git a/src/bootstrap-window.js b/src/bootstrap-window.js index 79381017f50..61ca6dd8477 100644 --- a/src/bootstrap-window.js +++ b/src/bootstrap-window.js @@ -136,6 +136,7 @@ 'vscode-textmate': `${baseNodeModulesPath}/vscode-textmate/release/main.js`, 'vscode-oniguruma': `${baseNodeModulesPath}/vscode-oniguruma/release/main.js`, 'xterm': `${baseNodeModulesPath}/xterm/lib/xterm.js`, + 'xterm-addon-canvas': `${baseNodeModulesPath}/xterm-addon-canvas/lib/xterm-addon-canvas.js`, 'xterm-addon-search': `${baseNodeModulesPath}/xterm-addon-search/lib/xterm-addon-search.js`, 'xterm-addon-unicode11': `${baseNodeModulesPath}/xterm-addon-unicode11/lib/xterm-addon-unicode11.js`, 'xterm-addon-webgl': `${baseNodeModulesPath}/xterm-addon-webgl/lib/xterm-addon-webgl.js`, @@ -150,7 +151,7 @@ // which has a fallback to using node.js `require` // (node.js enabled renderers only) if (!safeProcess.sandboxed) { - loaderConfig.amdModulesPattern = /(^vs\/)|(^vscode-textmate$)|(^vscode-oniguruma$)|(^xterm$)|(^xterm-addon-search$)|(^xterm-addon-unicode11$)|(^xterm-addon-webgl$)|(^@vscode\/iconv-lite-umd$)|(^jschardet$)|(^@vscode\/vscode-languagedetection$)|(^vscode-regexp-languagedetection$)|(^tas-client-umd$)/; + loaderConfig.amdModulesPattern = /(^vs\/)|(^vscode-textmate$)|(^vscode-oniguruma$)|(^xterm$)|(^xterm-addon-canvas$)|(^xterm-addon-search$)|(^xterm-addon-unicode11$)|(^xterm-addon-webgl$)|(^@vscode\/iconv-lite-umd$)|(^jschardet$)|(^@vscode\/vscode-languagedetection$)|(^vscode-regexp-languagedetection$)|(^tas-client-umd$)/; } // Signal before require.config() diff --git a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts index 3c60805a553..f4cc3403c1a 100644 --- a/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts @@ -4,10 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import type { IBuffer, IMarker, ITheme, Terminal as RawXtermTerminal } from 'xterm'; +import type { CanvasAddon as CanvasAddonType } from 'xterm-addon-canvas'; import type { ISearchOptions, SearchAddon as SearchAddonType } from 'xterm-addon-search'; import type { Unicode11Addon as Unicode11AddonType } from 'xterm-addon-unicode11'; import type { WebglAddon as WebglAddonType } from 'xterm-addon-webgl'; -import { SerializeAddon as SerializeAddonType } from 'xterm-addon-serialize'; +import type { SerializeAddon as SerializeAddonType } from 'xterm-addon-serialize'; import { IXtermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private'; import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; @@ -42,10 +43,11 @@ import { IGenericMarkProperties } from 'vs/platform/terminal/common/terminalProc const SLOW_CANVAS_RENDER_THRESHOLD = 50; const NUMBER_OF_FRAMES_TO_MEASURE = 20; +let CanvasAddon: typeof CanvasAddonType; let SearchAddon: typeof SearchAddonType; +let SerializeAddon: typeof SerializeAddonType; let Unicode11Addon: typeof Unicode11AddonType; let WebglAddon: typeof WebglAddonType; -let SerializeAddon: typeof SerializeAddonType; /** * Wraps the xterm object with additional functionality. Interaction with the backing process is out @@ -65,6 +67,7 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II private _decorationAddon: DecorationAddon; // Optional addons + private _canvasAddon?: CanvasAddonType; private _searchAddon?: SearchAddonType; private _unicode11Addon?: Unicode11AddonType; private _webglAddon?: WebglAddonType; @@ -140,7 +143,6 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II fastScrollModifier: 'alt', fastScrollSensitivity: config.fastScrollSensitivity, scrollSensitivity: config.mouseWheelScrollSensitivity, - // rendererType: this._getBuiltInXtermRenderer(config.gpuAcceleration, XtermTerminal._suggestedRendererType), wordSeparator: config.wordSeparators, overviewRulerWidth: 10 })); @@ -214,6 +216,9 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II this._container = container; if (this._shouldLoadWebgl()) { this._enableWebglRenderer(); + } else if (this._shouldLoadCanvas()) { + this._enableCanvasRenderer(); + // rendererType: this._getBuiltInXtermRenderer(config.gpuAcceleration, XtermTerminal._suggestedRendererType), } // Screen must be created at this point as xterm.open is called return this._container.querySelector('.xterm-screen')!; @@ -241,8 +246,11 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II this._enableWebglRenderer(); } else { this._disposeOfWebglRenderer(); - // TODO: Fix renderer - // this.raw.options.rendererType = this._getBuiltInXtermRenderer(config.gpuAcceleration, XtermTerminal._suggestedRendererType); + if (this._shouldLoadCanvas()) { + this._enableCanvasRenderer(); + } else { + this._disposeOfCanvasRenderer(); + } } } @@ -250,6 +258,10 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II return !isSafari && (this._configHelper.config.gpuAcceleration === 'auto' && XtermTerminal._suggestedRendererType === undefined) || this._configHelper.config.gpuAcceleration === 'on'; } + private _shouldLoadCanvas(): boolean { + return (this._configHelper.config.gpuAcceleration === 'auto' && (XtermTerminal._suggestedRendererType === undefined || XtermTerminal._suggestedRendererType === 'canvas')) || this._configHelper.config.gpuAcceleration === 'canvas'; + } + forceRedraw() { this._webglAddon?.clearTextureAtlas(); this.raw.clearTextureAtlas(); @@ -436,6 +448,7 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II } const Addon = await this._getWebglAddonConstructor(); this._webglAddon = new Addon(); + this._disposeOfCanvasRenderer(); try { this.raw.loadAddon(this._webglAddon); this._logService.trace('Webgl was loaded'); @@ -458,13 +471,41 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II if (!neverMeasureRenderTime && this._configHelper.config.gpuAcceleration !== 'off') { this._measureRenderTime(); } - // TODO: Fix renderer - // this.raw.options.rendererType = 'canvas'; - // XtermTerminal._suggestedRendererType = 'canvas'; + XtermTerminal._suggestedRendererType = 'canvas'; this._disposeOfWebglRenderer(); + this._enableCanvasRenderer(); } } + private async _enableCanvasRenderer(): Promise { + if (!this.raw.element || this._canvasAddon) { + return; + } + const Addon = await this._getCanvasAddonConstructor(); + this._canvasAddon = new Addon(); + this._disposeOfWebglRenderer(); + try { + this.raw.loadAddon(this._canvasAddon); + this._logService.trace('Canvas was loaded'); + } catch (e) { + this._logService.warn(`Canvas could not be loaded. Falling back to the dom renderer type.`, e); + const neverMeasureRenderTime = this._storageService.getBoolean(TerminalStorageKeys.NeverMeasureRenderTime, StorageScope.APPLICATION, false); + // if it's already set to dom, no need to measure render time + if (!neverMeasureRenderTime && this._configHelper.config.gpuAcceleration !== 'off') { + this._measureRenderTime(); + } + XtermTerminal._suggestedRendererType = 'dom'; + this._disposeOfCanvasRenderer(); + } + } + + protected async _getCanvasAddonConstructor(): Promise { + if (!CanvasAddon) { + CanvasAddon = (await import('xterm-addon-canvas')).CanvasAddon; + } + return CanvasAddon; + } + protected async _getSearchAddonConstructor(): Promise { if (!SearchAddon) { SearchAddon = (await import('xterm-addon-search')).SearchAddon; @@ -493,6 +534,15 @@ export class XtermTerminal extends DisposableStore implements IXtermTerminal, II return SerializeAddon; } + private _disposeOfCanvasRenderer(): void { + try { + this._canvasAddon?.dispose(); + } catch { + // ignore + } + this._canvasAddon = undefined; + } + private _disposeOfWebglRenderer(): void { try { this._webglAddon?.dispose(); diff --git a/yarn.lock b/yarn.lock index c3f1dcc3ba1..11b0d85665c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12072,6 +12072,11 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" +xterm-addon-canvas@0.2.0-beta.15: + version "0.2.0-beta.15" + resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.2.0-beta.15.tgz#de863e46410b1de357b153abf1984227777760e4" + integrity sha512-E1pNCDSVTINchwWLysZ9ZD/BPv1WLGV52xRHB00US1PHHELbhtvms+6dZ44WZEDXhtfpptRZ1VBx+QpvfJIuvw== + xterm-addon-search@0.10.0-beta.3: version "0.10.0-beta.3" resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.10.0-beta.3.tgz#5194434d86105637c71f6f20139a9d0b5c1a956a"