Skip to content

Commit

Permalink
Remove xterm canvas renderer from fallback logic
Browse files Browse the repository at this point in the history
This simplifies things a lot, the plan is to remove the canvas renderer
completely from VS Code if all goes well (#209276).

Fixes #209275
  • Loading branch information
Tyriar committed Apr 1, 2024
1 parent b85a659 commit 596ee31
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 83 deletions.
4 changes: 1 addition & 3 deletions src/vs/workbench/contrib/terminal/browser/xterm-private.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ export interface IXtermCore {
}
},
_renderer: {
value?: {
_renderLayers?: any[];
}
value?: unknown;
};
_handleIntersectionChange: any;
};
Expand Down
88 changes: 9 additions & 79 deletions src/vs/workbench/contrib/terminal/browser/xterm/xtermTerminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type { SerializeAddon as SerializeAddonType } from '@xterm/addon-serializ
import type { ImageAddon as ImageAddonType } from '@xterm/addon-image';
import * as dom from 'vs/base/browser/dom';
import { IXtermCore } from 'vs/workbench/contrib/terminal/browser/xterm-private';
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
Expand All @@ -21,9 +21,7 @@ import { ITerminalFont, ITerminalConfiguration } from 'vs/workbench/contrib/term
import { isSafari } from 'vs/base/browser/browser';
import { IMarkTracker, IInternalXtermTerminal, IXtermTerminal, IXtermColorProvider, XtermTerminalConstants, IXtermAttachToElementOptions, IDetachedXtermTerminal, ITerminalConfigurationService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { LogLevel } from 'vs/platform/log/common/log';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { TerminalStorageKeys } from 'vs/workbench/contrib/terminal/common/terminalStorageKeys';
import { INotificationService, IPromptChoice, Severity } from 'vs/platform/notification/common/notification';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { MarkNavigationAddon, ScrollPosition } from 'vs/workbench/contrib/terminal/browser/xterm/markNavigationAddon';
import { localize } from 'vs/nls';
import { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService';
Expand All @@ -46,12 +44,6 @@ import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
import { AccessibilitySignal, IAccessibilitySignalService } from 'vs/platform/accessibilitySignal/browser/accessibilitySignalService';

const enum RenderConstants {
/**
* How long in milliseconds should an average frame take to render for a notification to appear
* which suggests the fallback DOM-based renderer.
*/
SlowCanvasRenderThreshold = 50,
NumberOfFramestoMeasure = 20,
SmoothScrollDuration = 125
}

Expand Down Expand Up @@ -120,7 +112,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach
/** The raw xterm.js instance */
readonly raw: RawXtermTerminal;
private _core: IXtermCore;
private static _suggestedRendererType: 'canvas' | 'dom' | undefined = undefined;
private static _suggestedRendererType: 'dom' | undefined = undefined;
private static _checkedWebglCompatible = false;
private _attached?: { container: HTMLElement; options: IXtermAttachToElementOptions };
private _isPhysicalMouseWheel = MouseWheelClassifier.INSTANCE.isPhysicalMouseWheel();
Expand Down Expand Up @@ -200,7 +192,6 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@ITerminalLogService private readonly _logService: ITerminalLogService,
@INotificationService private readonly _notificationService: INotificationService,
@IStorageService private readonly _storageService: IStorageService,
@IThemeService private readonly _themeService: IThemeService,
@ITelemetryService private readonly _telemetryService: ITelemetryService,
@ITerminalConfigurationService private readonly _terminalConfigurationService: ITerminalConfigurationService,
Expand Down Expand Up @@ -431,7 +422,7 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach
}

private _shouldLoadCanvas(): boolean {
return (this._terminalConfigurationService.config.gpuAcceleration === 'auto' && (XtermTerminal._suggestedRendererType === undefined || XtermTerminal._suggestedRendererType === 'canvas')) || this._terminalConfigurationService.config.gpuAcceleration === 'canvas';
return this._terminalConfigurationService.config.gpuAcceleration === 'canvas';
}

forceRedraw() {
Expand Down Expand Up @@ -716,22 +707,19 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach
// }
// }, 5000);
} catch (e) {
this._logService.warn(`Webgl could not be loaded. Falling back to the canvas 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._terminalConfigurationService.config.gpuAcceleration !== 'off') {
this._measureRenderTime();
}
this._logService.warn(`Webgl could not be loaded. Falling back to the DOM renderer`, e);
this._disableWebglForThisSession();
}
}

private _disableWebglForThisSession() {
XtermTerminal._suggestedRendererType = 'canvas';
XtermTerminal._suggestedRendererType = 'dom';
this._disposeOfWebglRenderer();
this._enableCanvasRenderer();
}

/**
* @deprecated This will be removed in the future, see https://github.com/microsoft/vscode/issues/209276
*/
private async _enableCanvasRenderer(): Promise<void> {
if (!this.raw.element || this._canvasAddon) {
return;
Expand All @@ -744,11 +732,6 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach
this._logService.trace('Canvas renderer was loaded');
} catch (e) {
this._logService.warn(`Canvas renderer could not be loaded, falling back to dom renderer`, 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._terminalConfigurationService.config.gpuAcceleration !== 'off') {
this._measureRenderTime();
}
XtermTerminal._suggestedRendererType = 'dom';
this._disposeOfCanvasRenderer();
}
Expand Down Expand Up @@ -836,59 +819,6 @@ export class XtermTerminal extends Disposable implements IXtermTerminal, IDetach
this._refreshImageAddon();
}

private async _measureRenderTime(): Promise<void> {
const frameTimes: number[] = [];
if (!this._core._renderService?._renderer.value?._renderLayers) {
return;
}
const textRenderLayer = this._core._renderService._renderer.value._renderLayers[0];
const originalOnGridChanged = textRenderLayer?.onGridChanged;
const evaluateCanvasRenderer = () => {
// Discard first frame time as it's normal to take longer
frameTimes.shift();

const medianTime = frameTimes.sort((a, b) => a - b)[Math.floor(frameTimes.length / 2)];
if (medianTime > RenderConstants.SlowCanvasRenderThreshold) {
if (this._terminalConfigurationService.config.gpuAcceleration === 'auto') {
XtermTerminal._suggestedRendererType = 'dom';
this.updateConfig();
} else {
const promptChoices: IPromptChoice[] = [
{
label: localize('yes', "Yes"),
run: () => this._configurationService.updateValue(TerminalSettingId.GpuAcceleration, 'off', ConfigurationTarget.USER)
} as IPromptChoice,
{
label: localize('no', "No"),
run: () => { }
} as IPromptChoice,
{
label: localize('dontShowAgain', "Don't Show Again"),
isSecondary: true,
run: () => this._storageService.store(TerminalStorageKeys.NeverMeasureRenderTime, true, StorageScope.APPLICATION, StorageTarget.MACHINE)
} as IPromptChoice
];
this._notificationService.prompt(
Severity.Warning,
localize('terminal.slowRendering', 'Terminal GPU acceleration appears to be slow on your computer. Would you like to switch to disable it which may improve performance? [Read more about terminal settings](https://code.visualstudio.com/docs/editor/integrated-terminal#_changing-how-the-terminal-is-rendered).'),
promptChoices
);
}
}
};

textRenderLayer.onGridChanged = (terminal: RawXtermTerminal, firstRow: number, lastRow: number) => {
const startTime = performance.now();
originalOnGridChanged.call(textRenderLayer, terminal, firstRow, lastRow);
frameTimes.push(performance.now() - startTime);
if (frameTimes.length === RenderConstants.NumberOfFramestoMeasure) {
evaluateCanvasRenderer();
// Restore original function
textRenderLayer.onGridChanged = originalOnGridChanged;
}
};
}

getXtermTheme(theme?: IColorTheme): ITheme {
if (!theme) {
theme = this._themeService.getColorTheme();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/

export const enum TerminalStorageKeys {
NeverMeasureRenderTime = 'terminal.integrated.neverMeasureRenderTime',
SuggestedRendererType = 'terminal.integrated.suggestedRendererType',
TabsListWidthHorizontal = 'tabs-list-width-horizontal',
TabsListWidthVertical = 'tabs-list-width-vertical',
Expand Down

0 comments on commit 596ee31

Please sign in to comment.