Merge pull request #5278 from Tyriar/liga_texture_limit
Handle glyph widths up to the maximum device texture size
This commit is contained in:
@@ -33,6 +33,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
private _charAtlasDisposable = this._register(new MutableDisposable());
|
private _charAtlasDisposable = this._register(new MutableDisposable());
|
||||||
private _charAtlas: ITextureAtlas | undefined;
|
private _charAtlas: ITextureAtlas | undefined;
|
||||||
private _devicePixelRatio: number;
|
private _devicePixelRatio: number;
|
||||||
|
private _deviceMaxTextureSize: number;
|
||||||
private _observerDisposable = this._register(new MutableDisposable());
|
private _observerDisposable = this._register(new MutableDisposable());
|
||||||
|
|
||||||
private _model: RenderModel = new RenderModel();
|
private _model: RenderModel = new RenderModel();
|
||||||
@@ -102,6 +103,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
throw new Error('WebGL2 not supported ' + this._gl);
|
throw new Error('WebGL2 not supported ' + this._gl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._deviceMaxTextureSize = this._gl.getParameter(this._gl.MAX_TEXTURE_SIZE);
|
||||||
|
|
||||||
this._register(addDisposableListener(this._canvas, 'webglcontextlost', (e) => {
|
this._register(addDisposableListener(this._canvas, 'webglcontextlost', (e) => {
|
||||||
console.log('webglcontextlost event received');
|
console.log('webglcontextlost event received');
|
||||||
// Prevent the default behavior in order to enable WebGL context restoration.
|
// Prevent the default behavior in order to enable WebGL context restoration.
|
||||||
@@ -272,7 +275,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
this.dimensions.device.cell.height,
|
this.dimensions.device.cell.height,
|
||||||
this.dimensions.device.char.width,
|
this.dimensions.device.char.width,
|
||||||
this.dimensions.device.char.height,
|
this.dimensions.device.char.height,
|
||||||
this._coreBrowserService.dpr
|
this._coreBrowserService.dpr,
|
||||||
|
this._deviceMaxTextureSize
|
||||||
);
|
);
|
||||||
if (this._charAtlas !== atlas) {
|
if (this._charAtlas !== atlas) {
|
||||||
this._onChangeTextureAtlas.fire(atlas.pages[0].canvas);
|
this._onChangeTextureAtlas.fire(atlas.pages[0].canvas);
|
||||||
|
|||||||
@@ -94,7 +94,8 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer
|
|||||||
if (this._deviceCharWidth <= 0 && this._deviceCharHeight <= 0) {
|
if (this._deviceCharWidth <= 0 && this._deviceCharHeight <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._charAtlas = acquireTextureAtlas(terminal, this._optionsService.rawOptions, colorSet, this._deviceCellWidth, this._deviceCellHeight, this._deviceCharWidth, this._deviceCharHeight, this._coreBrowserService.dpr);
|
|
||||||
|
this._charAtlas = acquireTextureAtlas(terminal, this._optionsService.rawOptions, colorSet, this._deviceCellWidth, this._deviceCellHeight, this._deviceCharWidth, this._deviceCharHeight, this._coreBrowserService.dpr, 2048);
|
||||||
this._charAtlas.warmUp();
|
this._charAtlas.warmUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,9 +31,10 @@ export function acquireTextureAtlas(
|
|||||||
deviceCellHeight: number,
|
deviceCellHeight: number,
|
||||||
deviceCharWidth: number,
|
deviceCharWidth: number,
|
||||||
deviceCharHeight: number,
|
deviceCharHeight: number,
|
||||||
devicePixelRatio: number
|
devicePixelRatio: number,
|
||||||
|
deviceMaxTextureSize: number
|
||||||
): ITextureAtlas {
|
): ITextureAtlas {
|
||||||
const newConfig = generateConfig(deviceCellWidth, deviceCellHeight, deviceCharWidth, deviceCharHeight, options, colors, devicePixelRatio);
|
const newConfig = generateConfig(deviceCellWidth, deviceCellHeight, deviceCharWidth, deviceCharHeight, options, colors, devicePixelRatio, deviceMaxTextureSize);
|
||||||
|
|
||||||
// Check to see if the terminal already owns this config
|
// Check to see if the terminal already owns this config
|
||||||
for (let i = 0; i < charAtlasCache.length; i++) {
|
for (let i = 0; i < charAtlasCache.length; i++) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { ITerminalOptions } from '@xterm/xterm';
|
|||||||
import { IColorSet, ReadonlyColorSet } from 'browser/Types';
|
import { IColorSet, ReadonlyColorSet } from 'browser/Types';
|
||||||
import { NULL_COLOR } from 'common/Color';
|
import { NULL_COLOR } from 'common/Color';
|
||||||
|
|
||||||
export function generateConfig(deviceCellWidth: number, deviceCellHeight: number, deviceCharWidth: number, deviceCharHeight: number, options: Required<ITerminalOptions>, colors: ReadonlyColorSet, devicePixelRatio: number): ICharAtlasConfig {
|
export function generateConfig(deviceCellWidth: number, deviceCellHeight: number, deviceCharWidth: number, deviceCharHeight: number, options: Required<ITerminalOptions>, colors: ReadonlyColorSet, devicePixelRatio: number, deviceMaxTextureSize: number): ICharAtlasConfig {
|
||||||
// null out some fields that don't matter
|
// null out some fields that don't matter
|
||||||
const clonedColors: IColorSet = {
|
const clonedColors: IColorSet = {
|
||||||
foreground: colors.foreground,
|
foreground: colors.foreground,
|
||||||
@@ -34,6 +34,7 @@ export function generateConfig(deviceCellWidth: number, deviceCellHeight: number
|
|||||||
return {
|
return {
|
||||||
customGlyphs: options.customGlyphs,
|
customGlyphs: options.customGlyphs,
|
||||||
devicePixelRatio,
|
devicePixelRatio,
|
||||||
|
deviceMaxTextureSize,
|
||||||
letterSpacing: options.letterSpacing,
|
letterSpacing: options.letterSpacing,
|
||||||
lineHeight: options.lineHeight,
|
lineHeight: options.lineHeight,
|
||||||
deviceCellWidth: deviceCellWidth,
|
deviceCellWidth: deviceCellWidth,
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|||||||
|
|
||||||
// The set of atlas pages that can be written to
|
// The set of atlas pages that can be written to
|
||||||
private _activePages: AtlasPage[] = [];
|
private _activePages: AtlasPage[] = [];
|
||||||
|
private _overflowSizePage: AtlasPage | undefined;
|
||||||
|
|
||||||
private _tmpCanvas: HTMLCanvasElement;
|
private _tmpCanvas: HTMLCanvasElement;
|
||||||
// A temporary context that glyphs are drawn to before being transfered to the atlas.
|
// A temporary context that glyphs are drawn to before being transfered to the atlas.
|
||||||
@@ -431,7 +432,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|||||||
// Allow 1 cell width per character, with a minimum of 2 (CJK), plus some padding. This is used
|
// Allow 1 cell width per character, with a minimum of 2 (CJK), plus some padding. This is used
|
||||||
// to draw the glyph to the canvas as well as to restrict the bounding box search to ensure
|
// to draw the glyph to the canvas as well as to restrict the bounding box search to ensure
|
||||||
// giant ligatures (eg. =====>) don't impact overall performance.
|
// giant ligatures (eg. =====>) don't impact overall performance.
|
||||||
const allowedWidth = Math.min(this._config.deviceCellWidth * Math.max(chars.length, 2) + TMP_CANVAS_GLYPH_PADDING * 2, this._textureSize);
|
const allowedWidth = Math.min(this._config.deviceCellWidth * Math.max(chars.length, 2) + TMP_CANVAS_GLYPH_PADDING * 2, this._config.deviceMaxTextureSize);
|
||||||
if (this._tmpCanvas.width < allowedWidth) {
|
if (this._tmpCanvas.width < allowedWidth) {
|
||||||
this._tmpCanvas.width = allowedWidth;
|
this._tmpCanvas.width = allowedWidth;
|
||||||
}
|
}
|
||||||
@@ -772,6 +773,27 @@ export class TextureAtlas implements ITextureAtlas {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a new page for oversized glyphs as they come up
|
||||||
|
if (rasterizedGlyph.size.x > this._textureSize) {
|
||||||
|
if (!this._overflowSizePage) {
|
||||||
|
this._overflowSizePage = new AtlasPage(this._document, this._config.deviceMaxTextureSize);
|
||||||
|
this.pages.push(this._overflowSizePage);
|
||||||
|
|
||||||
|
// Request the model to be cleared to refresh all texture pages.
|
||||||
|
this._requestClearModel = true;
|
||||||
|
this._onAddTextureAtlasCanvas.fire(this._overflowSizePage.canvas);
|
||||||
|
}
|
||||||
|
activePage = this._overflowSizePage;
|
||||||
|
activeRow = this._overflowSizePage.currentRow;
|
||||||
|
// Move to next row if necessary
|
||||||
|
if (activeRow.x + rasterizedGlyph.size.x >= activePage.canvas.width) {
|
||||||
|
activeRow.x = 0;
|
||||||
|
activeRow.y += activeRow.height;
|
||||||
|
activeRow.height = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Create a new page if too much vertical space would be wasted or there is not enough room
|
// Create a new page if too much vertical space would be wasted or there is not enough room
|
||||||
// left in the page. The previous active row will become fixed in the process as it now has a
|
// left in the page. The previous active row will become fixed in the process as it now has a
|
||||||
// fixed height
|
// fixed height
|
||||||
@@ -782,6 +804,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|||||||
if (activePage.currentRow.y + activePage.currentRow.height + rasterizedGlyph.size.y >= activePage.canvas.height) {
|
if (activePage.currentRow.y + activePage.currentRow.height + rasterizedGlyph.size.y >= activePage.canvas.height) {
|
||||||
// Find the first page with room to create the new row on
|
// Find the first page with room to create the new row on
|
||||||
let candidatePage: AtlasPage | undefined;
|
let candidatePage: AtlasPage | undefined;
|
||||||
|
|
||||||
for (const p of this._activePages) {
|
for (const p of this._activePages) {
|
||||||
if (p.currentRow.y + p.currentRow.height + rasterizedGlyph.size.y < p.canvas.height) {
|
if (p.currentRow.y + p.currentRow.height + rasterizedGlyph.size.y < p.canvas.height) {
|
||||||
candidatePage = p;
|
candidatePage = p;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import type { Event } from 'vs/base/common/event';
|
|||||||
export interface ICharAtlasConfig {
|
export interface ICharAtlasConfig {
|
||||||
customGlyphs: boolean;
|
customGlyphs: boolean;
|
||||||
devicePixelRatio: number;
|
devicePixelRatio: number;
|
||||||
|
deviceMaxTextureSize: number;
|
||||||
letterSpacing: number;
|
letterSpacing: number;
|
||||||
lineHeight: number;
|
lineHeight: number;
|
||||||
fontSize: number;
|
fontSize: number;
|
||||||
|
|||||||
Reference in New Issue
Block a user