Skip to content

Commit ffc6125

Browse files
authored
Merge pull request #5278 from Tyriar/liga_texture_limit
Handle glyph widths up to the maximum device texture size
2 parents a095c10 + 04c1782 commit ffc6125

File tree

6 files changed

+37
-6
lines changed

6 files changed

+37
-6
lines changed

addons/addon-webgl/src/WebglRenderer.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
3333
private _charAtlasDisposable = this._register(new MutableDisposable());
3434
private _charAtlas: ITextureAtlas | undefined;
3535
private _devicePixelRatio: number;
36+
private _deviceMaxTextureSize: number;
3637
private _observerDisposable = this._register(new MutableDisposable());
3738

3839
private _model: RenderModel = new RenderModel();
@@ -102,6 +103,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
102103
throw new Error('WebGL2 not supported ' + this._gl);
103104
}
104105

106+
this._deviceMaxTextureSize = this._gl.getParameter(this._gl.MAX_TEXTURE_SIZE);
107+
105108
this._register(addDisposableListener(this._canvas, 'webglcontextlost', (e) => {
106109
console.log('webglcontextlost event received');
107110
// Prevent the default behavior in order to enable WebGL context restoration.
@@ -272,7 +275,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
272275
this.dimensions.device.cell.height,
273276
this.dimensions.device.char.width,
274277
this.dimensions.device.char.height,
275-
this._coreBrowserService.dpr
278+
this._coreBrowserService.dpr,
279+
this._deviceMaxTextureSize
276280
);
277281
if (this._charAtlas !== atlas) {
278282
this._onChangeTextureAtlas.fire(atlas.pages[0].canvas);

addons/addon-webgl/src/renderLayer/BaseRenderLayer.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer
9494
if (this._deviceCharWidth <= 0 && this._deviceCharHeight <= 0) {
9595
return;
9696
}
97-
this._charAtlas = acquireTextureAtlas(terminal, this._optionsService.rawOptions, colorSet, this._deviceCellWidth, this._deviceCellHeight, this._deviceCharWidth, this._deviceCharHeight, this._coreBrowserService.dpr);
97+
98+
this._charAtlas = acquireTextureAtlas(terminal, this._optionsService.rawOptions, colorSet, this._deviceCellWidth, this._deviceCellHeight, this._deviceCharWidth, this._deviceCharHeight, this._coreBrowserService.dpr, 2048);
9899
this._charAtlas.warmUp();
99100
}
100101

src/browser/renderer/shared/CharAtlasCache.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ export function acquireTextureAtlas(
3131
deviceCellHeight: number,
3232
deviceCharWidth: number,
3333
deviceCharHeight: number,
34-
devicePixelRatio: number
34+
devicePixelRatio: number,
35+
deviceMaxTextureSize: number
3536
): ITextureAtlas {
36-
const newConfig = generateConfig(deviceCellWidth, deviceCellHeight, deviceCharWidth, deviceCharHeight, options, colors, devicePixelRatio);
37+
const newConfig = generateConfig(deviceCellWidth, deviceCellHeight, deviceCharWidth, deviceCharHeight, options, colors, devicePixelRatio, deviceMaxTextureSize);
3738

3839
// Check to see if the terminal already owns this config
3940
for (let i = 0; i < charAtlasCache.length; i++) {

src/browser/renderer/shared/CharAtlasUtils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { ITerminalOptions } from '@xterm/xterm';
99
import { IColorSet, ReadonlyColorSet } from 'browser/Types';
1010
import { NULL_COLOR } from 'common/Color';
1111

12-
export function generateConfig(deviceCellWidth: number, deviceCellHeight: number, deviceCharWidth: number, deviceCharHeight: number, options: Required<ITerminalOptions>, colors: ReadonlyColorSet, devicePixelRatio: number): ICharAtlasConfig {
12+
export function generateConfig(deviceCellWidth: number, deviceCellHeight: number, deviceCharWidth: number, deviceCharHeight: number, options: Required<ITerminalOptions>, colors: ReadonlyColorSet, devicePixelRatio: number, deviceMaxTextureSize: number): ICharAtlasConfig {
1313
// null out some fields that don't matter
1414
const clonedColors: IColorSet = {
1515
foreground: colors.foreground,
@@ -34,6 +34,7 @@ export function generateConfig(deviceCellWidth: number, deviceCellHeight: number
3434
return {
3535
customGlyphs: options.customGlyphs,
3636
devicePixelRatio,
37+
deviceMaxTextureSize,
3738
letterSpacing: options.letterSpacing,
3839
lineHeight: options.lineHeight,
3940
deviceCellWidth: deviceCellWidth,

src/browser/renderer/shared/TextureAtlas.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export class TextureAtlas implements ITextureAtlas {
6666

6767
// The set of atlas pages that can be written to
6868
private _activePages: AtlasPage[] = [];
69+
private _overflowSizePage: AtlasPage | undefined;
6970

7071
private _tmpCanvas: HTMLCanvasElement;
7172
// A temporary context that glyphs are drawn to before being transfered to the atlas.
@@ -431,7 +432,7 @@ export class TextureAtlas implements ITextureAtlas {
431432
// Allow 1 cell width per character, with a minimum of 2 (CJK), plus some padding. This is used
432433
// to draw the glyph to the canvas as well as to restrict the bounding box search to ensure
433434
// giant ligatures (eg. =====>) don't impact overall performance.
434-
const allowedWidth = Math.min(this._config.deviceCellWidth * Math.max(chars.length, 2) + TMP_CANVAS_GLYPH_PADDING * 2, this._textureSize);
435+
const allowedWidth = Math.min(this._config.deviceCellWidth * Math.max(chars.length, 2) + TMP_CANVAS_GLYPH_PADDING * 2, this._config.deviceMaxTextureSize);
435436
if (this._tmpCanvas.width < allowedWidth) {
436437
this._tmpCanvas.width = allowedWidth;
437438
}
@@ -772,6 +773,27 @@ export class TextureAtlas implements ITextureAtlas {
772773
}
773774
}
774775

776+
// Create a new page for oversized glyphs as they come up
777+
if (rasterizedGlyph.size.x > this._textureSize) {
778+
if (!this._overflowSizePage) {
779+
this._overflowSizePage = new AtlasPage(this._document, this._config.deviceMaxTextureSize);
780+
this.pages.push(this._overflowSizePage);
781+
782+
// Request the model to be cleared to refresh all texture pages.
783+
this._requestClearModel = true;
784+
this._onAddTextureAtlasCanvas.fire(this._overflowSizePage.canvas);
785+
}
786+
activePage = this._overflowSizePage;
787+
activeRow = this._overflowSizePage.currentRow;
788+
// Move to next row if necessary
789+
if (activeRow.x + rasterizedGlyph.size.x >= activePage.canvas.width) {
790+
activeRow.x = 0;
791+
activeRow.y += activeRow.height;
792+
activeRow.height = 0;
793+
}
794+
break;
795+
}
796+
775797
// Create a new page if too much vertical space would be wasted or there is not enough room
776798
// left in the page. The previous active row will become fixed in the process as it now has a
777799
// fixed height
@@ -782,6 +804,7 @@ export class TextureAtlas implements ITextureAtlas {
782804
if (activePage.currentRow.y + activePage.currentRow.height + rasterizedGlyph.size.y >= activePage.canvas.height) {
783805
// Find the first page with room to create the new row on
784806
let candidatePage: AtlasPage | undefined;
807+
785808
for (const p of this._activePages) {
786809
if (p.currentRow.y + p.currentRow.height + rasterizedGlyph.size.y < p.canvas.height) {
787810
candidatePage = p;

src/browser/renderer/shared/Types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import type { Event } from 'vs/base/common/event';
1111
export interface ICharAtlasConfig {
1212
customGlyphs: boolean;
1313
devicePixelRatio: number;
14+
deviceMaxTextureSize: number;
1415
letterSpacing: number;
1516
lineHeight: number;
1617
fontSize: number;

0 commit comments

Comments
 (0)