From 54ee698ba6724e22695afd0273520c4e771ebcbe Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 1 Nov 2022 09:07:38 -0700 Subject: [PATCH 1/9] Basic merging working Part of #4243 --- src/browser/renderer/shared/TextureAtlas.ts | 118 +++++++++++++++++++- 1 file changed, 115 insertions(+), 3 deletions(-) diff --git a/src/browser/renderer/shared/TextureAtlas.ts b/src/browser/renderer/shared/TextureAtlas.ts index 22c33c50..b00cd4bd 100644 --- a/src/browser/renderer/shared/TextureAtlas.ts +++ b/src/browser/renderer/shared/TextureAtlas.ts @@ -133,18 +133,112 @@ export class TextureAtlas implements ITextureAtlas { this._didWarmUp = false; } + private _hasMerged = false; + private _createNewPage(): AtlasPage { - if (this._pages.length === 4 || this._pages.length === 7) { - this._increaseTextureSize(); + // if (this._pages.length === 4 || this._pages.length === 7) { + // this._increaseTextureSize(); + // } + + if (!this._hasMerged && this._pages.length === 6) { + this._hasMerged = true; + console.log('try merge'); + console.time('merge'); + + // TODO: Track the most filled pages (pixels used of total) and use them? + + // Migrate over 1 page at a time due to the time it takes to iterate over glyphs + + // Get the 4 most used pages + // TODO: This is slow, need to sort after slice so _pages doesn't get sorted + const mergingPages = this._pages.slice().sort((a, b) => a.percentageUsed < b.percentageUsed ? 1 : -1).slice(0, 4); + const sortedMergingPagesIndexes = mergingPages.map(e => e.glyphs[0].texturePage).sort(); + // TODO: Pull texture page index in a nicer way + const mergedPageIndex = sortedMergingPagesIndexes[0]; + const mergedPage = this._mergePages(mergingPages, mergedPageIndex); + + console.timeEnd('merge'); + + (console as any).image(mergedPage.canvas); + + mergedPage.hasCanvasChanged = true; + // this._pages[0] = mergedPage; + // Replace an old merging page with the merged + this._pages[mergedPageIndex] = mergedPage; + + console.log('before adjust', this._pages); + + console.log({ mergedPageIndex }); + + // TODO: Splice other 3 pages, shifting all other texture page props + for (let i = sortedMergingPagesIndexes.length - 1; i >= 1; i--) { + // TODO: Optimize, this is slow + const mergingPageIndex = sortedMergingPagesIndexes[i]; + + console.log('splice', mergingPageIndex); + this._pages.splice(mergingPageIndex, 1); + for (let j = mergingPageIndex; j < this._pages.length; j++) { + const adjustingPage = this._pages[j]; + console.log('adjust', j); + // if (mergingPages.includes(adjustingPage)) { + // continue; + // } + for (const g of adjustingPage.glyphs) { + g.texturePage--; + } + adjustingPage.hasCanvasChanged = true; + } + } + + this._onAddTextureAtlasCanvas.fire(mergedPage.canvas); + + // TODO: Force a refresh because atlas pages changed? + + // Continue with creating the new page as a glyph may be getting drawn + + // mergedPage.ctx.drawImage(this._pages[1].canvas, this._textureSize, 0); + // mergedPage.ctx.drawImage(this._pages[2].canvas, 0, this._textureSize); + // mergedPage.ctx.drawImage(this._pages[3].canvas, this._textureSize, this._textureSize); } + // TODO: Ensure pages aren't created beyond the maximum supported const newPage = new AtlasPage(this._document, this._textureSize); this._pages.push(newPage); + console.log('pages', this._pages); this._activePages.push(newPage); this._onAddTextureAtlasCanvas.fire(newPage.canvas); return newPage; } + private _mergePages(mergingPages: AtlasPage[], mergedPageIndex: number): AtlasPage { + const mergedSize = this._textureSize * 2; + const mergedPage = new AtlasPage(this._document, mergedSize, mergingPages); + for (const [i, p] of mergingPages.entries()) { + const xOffset = i * p.canvas.width % mergedSize; + const yOffset = Math.floor(i / 2) * p.canvas.height; + mergedPage.ctx.drawImage(p.canvas, xOffset, yOffset); + for (const g of p.glyphs) { + g.texturePage = mergedPageIndex; + g.sizeClipSpace.x = g.size.x / mergedSize; + g.sizeClipSpace.y = g.size.y / mergedSize; + g.texturePosition.x += xOffset; + g.texturePosition.y += yOffset; + g.texturePositionClipSpace.x = g.texturePosition.x / mergedSize; + g.texturePositionClipSpace.y = g.texturePosition.y / mergedSize; + } + + p.ctx.clearRect(0, 0, p.canvas.width, p.canvas.height); + p.ctx.fillText('merged', 100, 100); + + // Remove the merging page from active pages if it was there + const index = this._activePages.indexOf(p); + if (index !== -1) { + this._activePages.splice(index, 1); + } + } + return mergedPage; + } + /** * Doubles the texture size of new atlas pages if allowed. */ @@ -730,6 +824,7 @@ export class TextureAtlas implements ITextureAtlas { rasterizedGlyph.size.x, rasterizedGlyph.size.y ); + activePage.addGlyph(rasterizedGlyph); activePage.hasCanvasChanged = true; return rasterizedGlyph; @@ -829,6 +924,16 @@ class AtlasPage { public readonly canvas: HTMLCanvasElement; public readonly ctx: CanvasRenderingContext2D; + private _usedPixels: number = 0; + public get percentageUsed(): number { return this._usedPixels / (this.canvas.width * this.canvas.height); } + + private readonly _glyphs: IRasterizedGlyph[] = []; + public get glyphs(): ReadonlyArray { return this._glyphs; } + public addGlyph(glyph: IRasterizedGlyph): void { + this._glyphs.push(glyph); + this._usedPixels += glyph.size.x * glyph.size.y; + } + /** * Whether the canvas of the atlas page has changed, this is only set to true by the atlas, the * user of the boolean is required to reset its value to false. @@ -854,8 +959,15 @@ class AtlasPage { constructor( document: Document, - size: number + size: number, + sourcePages?: AtlasPage[] ) { + if (sourcePages) { + for (const p of sourcePages) { + this._glyphs.push(...p.glyphs); + this._usedPixels += p._usedPixels; + } + } this.canvas = createCanvas(document, size, size); // The canvas needs alpha because we use clearColor to convert the background color to alpha. // It might also contain some characters with transparent backgrounds if allowTransparency is From c9bacc80d747b49b9dca14c7e72738fa46b6fb3c Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 1 Nov 2022 10:08:00 -0700 Subject: [PATCH 2/9] Merge when max atlas pages is reached --- addons/xterm-addon-webgl/src/GlyphRenderer.ts | 15 ++++----- src/browser/renderer/shared/TextureAtlas.ts | 32 +++++++++---------- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/addons/xterm-addon-webgl/src/GlyphRenderer.ts b/addons/xterm-addon-webgl/src/GlyphRenderer.ts index f5ce46eb..818d0cbc 100644 --- a/addons/xterm-addon-webgl/src/GlyphRenderer.ts +++ b/addons/xterm-addon-webgl/src/GlyphRenderer.ts @@ -11,6 +11,7 @@ import { Terminal } from 'xterm'; import { IRasterizedGlyph, IRenderDimensions, ITextureAtlas } from 'browser/renderer/shared/Types'; import { Disposable, toDisposable } from 'common/Lifecycle'; import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils'; +import { TextureAtlas } from 'browser/renderer/shared/TextureAtlas'; interface IVertices { attributes: Float32Array; @@ -108,8 +109,6 @@ export class GlyphRenderer extends Disposable { ] }; - private static _maxAtlasPages: number | undefined; - constructor( private readonly _terminal: Terminal, private readonly _gl: IWebGL2RenderingContext, @@ -119,11 +118,11 @@ export class GlyphRenderer extends Disposable { const gl = this._gl; - if (GlyphRenderer._maxAtlasPages === undefined) { - GlyphRenderer._maxAtlasPages = throwIfFalsy(gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS) as number | null); + if (TextureAtlas.maxAtlasPages === undefined) { + TextureAtlas.maxAtlasPages = throwIfFalsy(gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS) as number | null); } - this._program = throwIfFalsy(createProgram(gl, vertexShaderSource, createFragmentShaderSource(GlyphRenderer._maxAtlasPages))); + this._program = throwIfFalsy(createProgram(gl, vertexShaderSource, createFragmentShaderSource(TextureAtlas.maxAtlasPages))); this.register(toDisposable(() => gl.deleteProgram(this._program))); // Uniform locations @@ -178,8 +177,8 @@ export class GlyphRenderer extends Disposable { // Setup static uniforms gl.useProgram(this._program); - const textureUnits = new Int32Array(GlyphRenderer._maxAtlasPages); - for (let i = 0; i < GlyphRenderer._maxAtlasPages; i++) { + const textureUnits = new Int32Array(TextureAtlas.maxAtlasPages); + for (let i = 0; i < TextureAtlas.maxAtlasPages; i++) { textureUnits[i] = i; } gl.uniform1iv(this._textureLocation, textureUnits); @@ -188,7 +187,7 @@ export class GlyphRenderer extends Disposable { // Setup 1x1 red pixel textures for all potential atlas pages, if one of these invalid textures // is ever drawn it will show characters as red rectangles. this._atlasTextures = []; - for (let i = 0; i < GlyphRenderer._maxAtlasPages; i++) { + for (let i = 0; i < TextureAtlas.maxAtlasPages; i++) { const texture = throwIfFalsy(gl.createTexture()); this.register(toDisposable(() => gl.deleteTexture(texture))); gl.activeTexture(gl.TEXTURE0 + i); diff --git a/src/browser/renderer/shared/TextureAtlas.ts b/src/browser/renderer/shared/TextureAtlas.ts index b00cd4bd..dbc35101 100644 --- a/src/browser/renderer/shared/TextureAtlas.ts +++ b/src/browser/renderer/shared/TextureAtlas.ts @@ -69,6 +69,8 @@ export class TextureAtlas implements ITextureAtlas { private _textureSize: number = 512; + public static maxAtlasPages: number | undefined; + private readonly _onAddTextureAtlasCanvas = new EventEmitter(); public readonly onAddTextureAtlasCanvas = this._onAddTextureAtlasCanvas.event; @@ -140,7 +142,7 @@ export class TextureAtlas implements ITextureAtlas { // this._increaseTextureSize(); // } - if (!this._hasMerged && this._pages.length === 6) { + if (!this._hasMerged && this._pages.length === TextureAtlas.maxAtlasPages) { this._hasMerged = true; console.log('try merge'); console.time('merge'); @@ -172,22 +174,7 @@ export class TextureAtlas implements ITextureAtlas { // TODO: Splice other 3 pages, shifting all other texture page props for (let i = sortedMergingPagesIndexes.length - 1; i >= 1; i--) { - // TODO: Optimize, this is slow - const mergingPageIndex = sortedMergingPagesIndexes[i]; - - console.log('splice', mergingPageIndex); - this._pages.splice(mergingPageIndex, 1); - for (let j = mergingPageIndex; j < this._pages.length; j++) { - const adjustingPage = this._pages[j]; - console.log('adjust', j); - // if (mergingPages.includes(adjustingPage)) { - // continue; - // } - for (const g of adjustingPage.glyphs) { - g.texturePage--; - } - adjustingPage.hasCanvasChanged = true; - } + this._deletePage(sortedMergingPagesIndexes[i]); } this._onAddTextureAtlasCanvas.fire(mergedPage.canvas); @@ -239,6 +226,17 @@ export class TextureAtlas implements ITextureAtlas { return mergedPage; } + private _deletePage(pageIndex: number): void { + this._pages.splice(pageIndex, 1); + for (let j = pageIndex; j < this._pages.length; j++) { + const adjustingPage = this._pages[j]; + for (const g of adjustingPage.glyphs) { + g.texturePage--; + } + adjustingPage.hasCanvasChanged = true; + } + } + /** * Doubles the texture size of new atlas pages if allowed. */ From 805b41b80f878cbc5b564d87ca3f2022b7ab1959 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Tue, 1 Nov 2022 10:26:48 -0700 Subject: [PATCH 3/9] Keep merging default texture size pages --- src/browser/renderer/shared/TextureAtlas.ts | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/browser/renderer/shared/TextureAtlas.ts b/src/browser/renderer/shared/TextureAtlas.ts index dbc35101..2a42246d 100644 --- a/src/browser/renderer/shared/TextureAtlas.ts +++ b/src/browser/renderer/shared/TextureAtlas.ts @@ -142,7 +142,7 @@ export class TextureAtlas implements ITextureAtlas { // this._increaseTextureSize(); // } - if (!this._hasMerged && this._pages.length === TextureAtlas.maxAtlasPages) { + if (this._pages.length === TextureAtlas.maxAtlasPages) { this._hasMerged = true; console.log('try merge'); console.time('merge'); @@ -153,15 +153,22 @@ export class TextureAtlas implements ITextureAtlas { // Get the 4 most used pages // TODO: This is slow, need to sort after slice so _pages doesn't get sorted - const mergingPages = this._pages.slice().sort((a, b) => a.percentageUsed < b.percentageUsed ? 1 : -1).slice(0, 4); - const sortedMergingPagesIndexes = mergingPages.map(e => e.glyphs[0].texturePage).sort(); + const mergingPages = this._pages.filter(e => e.canvas.width === this._textureSize).sort((a, b) => a.percentageUsed < b.percentageUsed ? 1 : -1).slice(0, 4); + console.log({ mergingPages }); + const sortedMergingPagesIndexes = mergingPages.map(e => e.glyphs[0].texturePage).sort((a, b) => a > b ? 1 : -1); // TODO: Pull texture page index in a nicer way const mergedPageIndex = sortedMergingPagesIndexes[0]; + + console.log({ mergedPageIndex, sortedMergingPagesIndexes: [...sortedMergingPagesIndexes] }); + if (mergedPageIndex === -1) { + debugger; + } + const mergedPage = this._mergePages(mergingPages, mergedPageIndex); console.timeEnd('merge'); - (console as any).image(mergedPage.canvas); + // (console as any).image(mergedPage.canvas); mergedPage.hasCanvasChanged = true; // this._pages[0] = mergedPage; @@ -170,8 +177,6 @@ export class TextureAtlas implements ITextureAtlas { console.log('before adjust', this._pages); - console.log({ mergedPageIndex }); - // TODO: Splice other 3 pages, shifting all other texture page props for (let i = sortedMergingPagesIndexes.length - 1; i >= 1; i--) { this._deletePage(sortedMergingPagesIndexes[i]); @@ -214,8 +219,8 @@ export class TextureAtlas implements ITextureAtlas { g.texturePositionClipSpace.y = g.texturePosition.y / mergedSize; } - p.ctx.clearRect(0, 0, p.canvas.width, p.canvas.height); - p.ctx.fillText('merged', 100, 100); + p.ctx.fillStyle = 'green'; + p.ctx.fillRect(0, 0, p.canvas.width, p.canvas.height); // Remove the merging page from active pages if it was there const index = this._activePages.indexOf(p); From 0271fdf49dc024734fe9b410b26984344eaad9b8 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 2 Nov 2022 04:49:02 -0700 Subject: [PATCH 4/9] Merge 4 largest pages --- src/browser/renderer/shared/TextureAtlas.ts | 45 +++++++++++---------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/src/browser/renderer/shared/TextureAtlas.ts b/src/browser/renderer/shared/TextureAtlas.ts index 2a42246d..4b312876 100644 --- a/src/browser/renderer/shared/TextureAtlas.ts +++ b/src/browser/renderer/shared/TextureAtlas.ts @@ -135,34 +135,48 @@ export class TextureAtlas implements ITextureAtlas { this._didWarmUp = false; } - private _hasMerged = false; - private _createNewPage(): AtlasPage { // if (this._pages.length === 4 || this._pages.length === 7) { // this._increaseTextureSize(); // } if (this._pages.length === TextureAtlas.maxAtlasPages) { - this._hasMerged = true; - console.log('try merge'); console.time('merge'); // TODO: Track the most filled pages (pixels used of total) and use them? // Migrate over 1 page at a time due to the time it takes to iterate over glyphs - // Get the 4 most used pages + // Find the set of the largest 4 images with the highest percentages used the 4 most used pages + const pagesBySize = this._pages.slice().sort((a, b) => { + if (b.canvas.width !== a.canvas.width) { + return b.canvas.width - a.canvas.width; + } + return b.percentageUsed - a.percentageUsed; + }); + let sameSizeI = -1; + let size = 0; + for (let i = 0; i < pagesBySize.length; i++) { + if (pagesBySize[i].canvas.width !== size) { + sameSizeI = i; + size = pagesBySize[i].canvas.width; + } else if (i - sameSizeI === 3) { + break; + } + } + + console.log(`4 at ${sameSizeI} of size ${size}`); + + // TODO: This is slow, need to sort after slice so _pages doesn't get sorted - const mergingPages = this._pages.filter(e => e.canvas.width === this._textureSize).sort((a, b) => a.percentageUsed < b.percentageUsed ? 1 : -1).slice(0, 4); + + const mergingPages = pagesBySize.slice(sameSizeI, sameSizeI + 4); // .sort((a, b) => a.percentageUsed < b.percentageUsed ? 1 : -1); console.log({ mergingPages }); const sortedMergingPagesIndexes = mergingPages.map(e => e.glyphs[0].texturePage).sort((a, b) => a > b ? 1 : -1); // TODO: Pull texture page index in a nicer way const mergedPageIndex = sortedMergingPagesIndexes[0]; console.log({ mergedPageIndex, sortedMergingPagesIndexes: [...sortedMergingPagesIndexes] }); - if (mergedPageIndex === -1) { - debugger; - } const mergedPage = this._mergePages(mergingPages, mergedPageIndex); @@ -203,7 +217,7 @@ export class TextureAtlas implements ITextureAtlas { } private _mergePages(mergingPages: AtlasPage[], mergedPageIndex: number): AtlasPage { - const mergedSize = this._textureSize * 2; + const mergedSize = mergingPages[0].canvas.width * 2; const mergedPage = new AtlasPage(this._document, mergedSize, mergingPages); for (const [i, p] of mergingPages.entries()) { const xOffset = i * p.canvas.width % mergedSize; @@ -242,17 +256,6 @@ export class TextureAtlas implements ITextureAtlas { } } - /** - * Doubles the texture size of new atlas pages if allowed. - */ - private _increaseTextureSize(): void { - // 4096 is the minimum texture size in WebGL, but we still want the texture to be reasonably fast - // to upload. We could loosen this limit if it ever becomes a problem. - if (this._textureSize < 2048) { - this._textureSize *= 2; - } - } - public getRasterizedGlyphCombinedChar(chars: string, bg: number, fg: number, ext: number): IRasterizedGlyph { return this._getFromCacheMap(this._cacheMapCombined, chars, bg, fg, ext); } From 6406fd79c13f57ab9cb271eff042e9b620938510 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 2 Nov 2022 05:28:47 -0700 Subject: [PATCH 5/9] Enforce a maximum page merge amount --- .../src/WebLinkProvider.ts | 6 + addons/xterm-addon-webgl/src/GlyphRenderer.ts | 1 + addons/xterm-addon-webgl/src/WebglRenderer.ts | 8 +- src/browser/renderer/shared/TextureAtlas.ts | 146 +++++++++--------- src/browser/renderer/shared/Types.d.ts | 1 + 5 files changed, 90 insertions(+), 72 deletions(-) diff --git a/addons/xterm-addon-web-links/src/WebLinkProvider.ts b/addons/xterm-addon-web-links/src/WebLinkProvider.ts index 2f2ccddf..fafbb614 100644 --- a/addons/xterm-addon-web-links/src/WebLinkProvider.ts +++ b/addons/xterm-addon-web-links/src/WebLinkProvider.ts @@ -47,6 +47,12 @@ export class LinkComputer { const [line, startLineIndex] = LinkComputer._translateBufferLineToStringWithWrap(y - 1, false, terminal); + // Don't try if the wrapped line if excessively large as the regex matching will block the main + // thread. + if (line.length > 1024) { + return []; + } + let match; let stringIndex = -1; const result: ILink[] = []; diff --git a/addons/xterm-addon-webgl/src/GlyphRenderer.ts b/addons/xterm-addon-webgl/src/GlyphRenderer.ts index 818d0cbc..3fbd8788 100644 --- a/addons/xterm-addon-webgl/src/GlyphRenderer.ts +++ b/addons/xterm-addon-webgl/src/GlyphRenderer.ts @@ -120,6 +120,7 @@ export class GlyphRenderer extends Disposable { if (TextureAtlas.maxAtlasPages === undefined) { TextureAtlas.maxAtlasPages = throwIfFalsy(gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS) as number | null); + TextureAtlas.maxTextureSize = throwIfFalsy(gl.getParameter(gl.MAX_TEXTURE_SIZE) as number | null); } this._program = throwIfFalsy(createProgram(gl, vertexShaderSource, createFragmentShaderSource(TextureAtlas.maxAtlasPages))); diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index 8f039033..7570566f 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -16,7 +16,7 @@ import { AttributeData } from 'common/buffer/AttributeData'; import { CellData } from 'common/buffer/CellData'; import { Content, NULL_CELL_CHAR, NULL_CELL_CODE } from 'common/buffer/Constants'; import { EventEmitter, forwardEvent } from 'common/EventEmitter'; -import { Disposable, toDisposable } from 'common/Lifecycle'; +import { Disposable, getDisposeArrayDisposable, toDisposable } from 'common/Lifecycle'; import { ICoreService, IDecorationService, IOptionsService } from 'common/services/Services'; import { CharData, IBufferLine, ICellData } from 'common/Types'; import { IDisposable, Terminal } from 'xterm'; @@ -268,7 +268,10 @@ export class WebglRenderer extends Disposable implements IRenderer { this._charAtlasDisposable?.dispose(); this._onChangeTextureAtlas.fire(atlas.pages[0].canvas); - this._charAtlasDisposable = forwardEvent(atlas.onAddTextureAtlasCanvas, this._onAddTextureAtlasCanvas); + this._charAtlasDisposable = getDisposeArrayDisposable([ + atlas.onRequestRedrawViewport(() => this._requestRedrawViewport()), + forwardEvent(atlas.onAddTextureAtlasCanvas, this._onAddTextureAtlasCanvas) + ]); } this._charAtlas = atlas; this._charAtlas.warmUp(); @@ -327,7 +330,6 @@ export class WebglRenderer extends Disposable implements IRenderer { // Tell renderer the frame is beginning if (this._glyphRenderer.beginFrame()) { this._clearModel(true); - this._model.selection.clear(); } // Update model to reflect what's drawn diff --git a/src/browser/renderer/shared/TextureAtlas.ts b/src/browser/renderer/shared/TextureAtlas.ts index 4b312876..78fe8f24 100644 --- a/src/browser/renderer/shared/TextureAtlas.ts +++ b/src/browser/renderer/shared/TextureAtlas.ts @@ -13,7 +13,7 @@ import { excludeFromContrastRatioDemands, isPowerlineGlyph, isRestrictedPowerlin import { IUnicodeService } from 'common/services/Services'; import { FourKeyMap } from 'common/MultiKeyMap'; import { IdleTaskQueue } from 'common/TaskQueue'; -import { IBoundingBox, ICharAtlasConfig, IRasterizedGlyph, ITextureAtlas } from 'browser/renderer/shared/Types'; +import { IBoundingBox, ICharAtlasConfig, IRasterizedGlyph, IRequestRedrawEvent, ITextureAtlas } from 'browser/renderer/shared/Types'; import { EventEmitter } from 'common/EventEmitter'; /** @@ -35,7 +35,12 @@ const enum Constants { * The amount of pixel padding to allow in each row. Setting this to zero would make the atlas * page pack as tightly as possible, but more pages would end up being created as a result. */ - ROW_PIXEL_THRESHOLD = 2 + ROW_PIXEL_THRESHOLD = 2, + /** + * The maximum texture size regardless of what the actual hardware maximum turns out to be. This + * is enforced to ensure uploading the texture still finishes in a reasonable amount of time. + */ + FORCED_MAX_TEXTURE_SIZE = 4096 } interface ICharAtlasActiveRow { @@ -70,7 +75,10 @@ export class TextureAtlas implements ITextureAtlas { private _textureSize: number = 512; public static maxAtlasPages: number | undefined; + public static maxTextureSize: number | undefined; + private readonly _onRequestRedrawViewport = new EventEmitter(); + public readonly onRequestRedrawViewport = this._onRequestRedrawViewport.event; private readonly _onAddTextureAtlasCanvas = new EventEmitter(); public readonly onAddTextureAtlasCanvas = this._onAddTextureAtlasCanvas.event; @@ -95,6 +103,7 @@ export class TextureAtlas implements ITextureAtlas { for (const page of this.pages) { page.canvas.remove(); } + this._onRequestRedrawViewport.dispose(); this._onAddTextureAtlasCanvas.dispose(); } @@ -118,9 +127,9 @@ export class TextureAtlas implements ITextureAtlas { } } + private _requestClearModel = false; public beginFrame(): boolean { - // TODO: Something should happen to prevent reaching capacity - return false; + return this._requestClearModel; } public clearTexture(): void { @@ -136,81 +145,80 @@ export class TextureAtlas implements ITextureAtlas { } private _createNewPage(): AtlasPage { - // if (this._pages.length === 4 || this._pages.length === 7) { - // this._increaseTextureSize(); - // } - if (this._pages.length === TextureAtlas.maxAtlasPages) { - console.time('merge'); + // Try merge the set of the 4 most used pages of the largest size. This is is deferred to a + // microtask to ensure it does not interrupt textures that will be rendered in the current + // animation frame which would result in blank rendered areas. This is actually not that + // expensive relative to drawing the glyphs, so there is no need to wait for an idle callback. + if (TextureAtlas.maxAtlasPages && this._pages.length === TextureAtlas.maxAtlasPages - 1) { + queueMicrotask(() => { + console.time('merge'); - // TODO: Track the most filled pages (pixels used of total) and use them? + // TODO: Track the most filled pages (pixels used of total) and use them? - // Migrate over 1 page at a time due to the time it takes to iterate over glyphs + // Migrate over 1 page at a time due to the time it takes to iterate over glyphs - // Find the set of the largest 4 images with the highest percentages used the 4 most used pages - const pagesBySize = this._pages.slice().sort((a, b) => { - if (b.canvas.width !== a.canvas.width) { - return b.canvas.width - a.canvas.width; + // Find the set of the largest 4 images below the maximum size with the highest percentages used the 4 most used pages + const pagesBySize = this._pages.filter(e => { + return e.canvas.width * 2 <= (TextureAtlas.maxTextureSize || Constants.FORCED_MAX_TEXTURE_SIZE); + }).sort((a, b) => { + if (b.canvas.width !== a.canvas.width) { + return b.canvas.width - a.canvas.width; + } + return b.percentageUsed - a.percentageUsed; + }); + let sameSizeI = -1; + let size = 0; + for (let i = 0; i < pagesBySize.length; i++) { + if (pagesBySize[i].canvas.width !== size) { + sameSizeI = i; + size = pagesBySize[i].canvas.width; + } else if (i - sameSizeI === 3) { + break; + } } - return b.percentageUsed - a.percentageUsed; + + console.log(`4 at ${sameSizeI} of size ${size}`); + + + // TODO: This is slow, need to sort after slice so _pages doesn't get sorted + + const mergingPages = pagesBySize.slice(sameSizeI, sameSizeI + 4); // .sort((a, b) => a.percentageUsed < b.percentageUsed ? 1 : -1); + console.log({ mergingPages }); + const sortedMergingPagesIndexes = mergingPages.map(e => e.glyphs[0].texturePage).sort((a, b) => a > b ? 1 : -1); + // TODO: Pull texture page index in a nicer way + const mergedPageIndex = sortedMergingPagesIndexes[0]; + + console.log({ mergedPageIndex, sortedMergingPagesIndexes: [...sortedMergingPagesIndexes] }); + + const mergedPage = this._mergePages(mergingPages, mergedPageIndex); + + console.timeEnd('merge'); + + // (console as any).image(mergedPage.canvas); + + mergedPage.hasCanvasChanged = true; + // this._pages[0] = mergedPage; + // Replace an old merging page with the merged + this._pages[mergedPageIndex] = mergedPage; + + console.log('before adjust', this._pages); + + // TODO: Splice other 3 pages, shifting all other texture page props + for (let i = sortedMergingPagesIndexes.length - 1; i >= 1; i--) { + this._deletePage(sortedMergingPagesIndexes[i]); + } + + // Request the model to be cleared to refresh all texture pages. + this._requestClearModel = true; + + this._onAddTextureAtlasCanvas.fire(mergedPage.canvas); }); - let sameSizeI = -1; - let size = 0; - for (let i = 0; i < pagesBySize.length; i++) { - if (pagesBySize[i].canvas.width !== size) { - sameSizeI = i; - size = pagesBySize[i].canvas.width; - } else if (i - sameSizeI === 3) { - break; - } - } - - console.log(`4 at ${sameSizeI} of size ${size}`); - - - // TODO: This is slow, need to sort after slice so _pages doesn't get sorted - - const mergingPages = pagesBySize.slice(sameSizeI, sameSizeI + 4); // .sort((a, b) => a.percentageUsed < b.percentageUsed ? 1 : -1); - console.log({ mergingPages }); - const sortedMergingPagesIndexes = mergingPages.map(e => e.glyphs[0].texturePage).sort((a, b) => a > b ? 1 : -1); - // TODO: Pull texture page index in a nicer way - const mergedPageIndex = sortedMergingPagesIndexes[0]; - - console.log({ mergedPageIndex, sortedMergingPagesIndexes: [...sortedMergingPagesIndexes] }); - - const mergedPage = this._mergePages(mergingPages, mergedPageIndex); - - console.timeEnd('merge'); - - // (console as any).image(mergedPage.canvas); - - mergedPage.hasCanvasChanged = true; - // this._pages[0] = mergedPage; - // Replace an old merging page with the merged - this._pages[mergedPageIndex] = mergedPage; - - console.log('before adjust', this._pages); - - // TODO: Splice other 3 pages, shifting all other texture page props - for (let i = sortedMergingPagesIndexes.length - 1; i >= 1; i--) { - this._deletePage(sortedMergingPagesIndexes[i]); - } - - this._onAddTextureAtlasCanvas.fire(mergedPage.canvas); - - // TODO: Force a refresh because atlas pages changed? - - // Continue with creating the new page as a glyph may be getting drawn - - // mergedPage.ctx.drawImage(this._pages[1].canvas, this._textureSize, 0); - // mergedPage.ctx.drawImage(this._pages[2].canvas, 0, this._textureSize); - // mergedPage.ctx.drawImage(this._pages[3].canvas, this._textureSize, this._textureSize); } - // TODO: Ensure pages aren't created beyond the maximum supported + // All new atlas pages are created small as they are highly dynamic const newPage = new AtlasPage(this._document, this._textureSize); this._pages.push(newPage); - console.log('pages', this._pages); this._activePages.push(newPage); this._onAddTextureAtlasCanvas.fire(newPage.canvas); return newPage; diff --git a/src/browser/renderer/shared/Types.d.ts b/src/browser/renderer/shared/Types.d.ts index 0948aec7..5f4a53ff 100644 --- a/src/browser/renderer/shared/Types.d.ts +++ b/src/browser/renderer/shared/Types.d.ts @@ -89,6 +89,7 @@ export interface IRenderer extends IDisposable { export interface ITextureAtlas extends IDisposable { readonly pages: { canvas: HTMLCanvasElement, hasCanvasChanged: boolean }[]; + onRequestRedrawViewport: IEvent; onAddTextureAtlasCanvas: IEvent; /** From c22e6849042a42bbf1b62d3843ce86a5c4752fad Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 2 Nov 2022 05:40:13 -0700 Subject: [PATCH 6/9] Fix exception when last 4 smallest pages are merged --- addons/xterm-addon-webgl/src/GlyphRenderer.ts | 2 ++ src/browser/renderer/shared/TextureAtlas.ts | 26 ++++++++----------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/addons/xterm-addon-webgl/src/GlyphRenderer.ts b/addons/xterm-addon-webgl/src/GlyphRenderer.ts index 3fbd8788..3f16c680 100644 --- a/addons/xterm-addon-webgl/src/GlyphRenderer.ts +++ b/addons/xterm-addon-webgl/src/GlyphRenderer.ts @@ -119,7 +119,9 @@ export class GlyphRenderer extends Disposable { const gl = this._gl; if (TextureAtlas.maxAtlasPages === undefined) { + // Typically 8 or 16 TextureAtlas.maxAtlasPages = throwIfFalsy(gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS) as number | null); + // Almost all clients will support >= 4096 TextureAtlas.maxTextureSize = throwIfFalsy(gl.getParameter(gl.MAX_TEXTURE_SIZE) as number | null); } diff --git a/src/browser/renderer/shared/TextureAtlas.ts b/src/browser/renderer/shared/TextureAtlas.ts index 78fe8f24..ffa3cb40 100644 --- a/src/browser/renderer/shared/TextureAtlas.ts +++ b/src/browser/renderer/shared/TextureAtlas.ts @@ -150,12 +150,9 @@ export class TextureAtlas implements ITextureAtlas { // microtask to ensure it does not interrupt textures that will be rendered in the current // animation frame which would result in blank rendered areas. This is actually not that // expensive relative to drawing the glyphs, so there is no need to wait for an idle callback. - if (TextureAtlas.maxAtlasPages && this._pages.length === TextureAtlas.maxAtlasPages - 1) { + if (TextureAtlas.maxAtlasPages && this._pages.length >= Math.max(4, TextureAtlas.maxAtlasPages / 2)) { + // TODO: If the viewport has enough glyphs to fill the new page, there will be a webgl error queueMicrotask(() => { - console.time('merge'); - - // TODO: Track the most filled pages (pixels used of total) and use them? - // Migrate over 1 page at a time due to the time it takes to iterate over glyphs // Find the set of the largest 4 images below the maximum size with the highest percentages used the 4 most used pages @@ -178,23 +175,15 @@ export class TextureAtlas implements ITextureAtlas { } } - console.log(`4 at ${sameSizeI} of size ${size}`); - - // TODO: This is slow, need to sort after slice so _pages doesn't get sorted const mergingPages = pagesBySize.slice(sameSizeI, sameSizeI + 4); // .sort((a, b) => a.percentageUsed < b.percentageUsed ? 1 : -1); - console.log({ mergingPages }); const sortedMergingPagesIndexes = mergingPages.map(e => e.glyphs[0].texturePage).sort((a, b) => a > b ? 1 : -1); // TODO: Pull texture page index in a nicer way const mergedPageIndex = sortedMergingPagesIndexes[0]; - console.log({ mergedPageIndex, sortedMergingPagesIndexes: [...sortedMergingPagesIndexes] }); - const mergedPage = this._mergePages(mergingPages, mergedPageIndex); - console.timeEnd('merge'); - // (console as any).image(mergedPage.canvas); mergedPage.hasCanvasChanged = true; @@ -202,8 +191,6 @@ export class TextureAtlas implements ITextureAtlas { // Replace an old merging page with the merged this._pages[mergedPageIndex] = mergedPage; - console.log('before adjust', this._pages); - // TODO: Splice other 3 pages, shifting all other texture page props for (let i = sortedMergingPagesIndexes.length - 1; i >= 1; i--) { this._deletePage(sortedMergingPagesIndexes[i]); @@ -723,6 +710,15 @@ export class TextureAtlas implements ITextureAtlas { let activePage: AtlasPage; let activeRow: ICharAtlasActiveRow; while (true) { + // If there are no active pages (the last smallest 4 were merged), create a new one + if (this._activePages.length === 0) { + const newPage = this._createNewPage(); + activePage = newPage; + activeRow = newPage.currentRow; + activeRow.height = rasterizedGlyph.size.y; + break; + } + // Get the best current row from all active pages activePage = this._activePages[this._activePages.length - 1]; activeRow = activePage.currentRow; From abfe391d91d575fd998d133ad5f77e292bf323f0 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 2 Nov 2022 05:46:40 -0700 Subject: [PATCH 7/9] Add CJK with random SGR test button This is good as a stress test for the renderer --- demo/client.ts | 20 ++++++++++++++++++++ demo/index.html | 1 + 2 files changed, 21 insertions(+) diff --git a/demo/client.ts b/demo/client.ts index 033ea41b..67ad0284 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -220,6 +220,7 @@ if (document.location.pathname === '/test') { document.getElementById('custom-glyph').addEventListener('click', writeCustomGlyphHandler); document.getElementById('load-test').addEventListener('click', loadTest); document.getElementById('print-cjk').addEventListener('click', addCjk); + document.getElementById('print-cjk-sgr').addEventListener('click', addCjkRandomSgr); document.getElementById('powerline-symbol-test').addEventListener('click', powerlineSymbolTest); document.getElementById('underline-test').addEventListener('click', underlineTest); document.getElementById('ansi-colors').addEventListener('click', ansiColorsTest); @@ -989,6 +990,25 @@ function addCjk(): void { } } +/** + * Prints the 20977 characters from the CJK Unified Ideographs unicode block with randomized styles. + */ +function addCjkRandomSgr(): void { + term.write('\n\n\r'); + for (let i = 0x4E00; i < 0x9FCC; i++) { + term.write(`\x1b[${getRandomSgr()}m${String.fromCharCode(i)}\x1b[0m`); + } +} +const randomSgrAttributes = [ + '1', '2', '3', '4', '5', '6', '7', '9', + '21', '22', '23', '24', '25', '26', '27', '28', '29', + '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', + '40', '41', '42', '43', '44', '45', '46', '47', '48', '49' +]; +function getRandomSgr(): string { + return randomSgrAttributes[Math.floor(Math.random() * randomSgrAttributes.length)]; +} + function addDecoration(): void { term.options['overviewRulerWidth'] = 15; const marker = term.registerMarker(1); diff --git a/demo/index.html b/demo/index.html index 26dcc53d..f62d535c 100644 --- a/demo/index.html +++ b/demo/index.html @@ -75,6 +75,7 @@
Performance
+
Styles
From d82da195f305e0e0f82a9de8db34d0a726ae20a1 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Wed, 2 Nov 2022 06:02:53 -0700 Subject: [PATCH 8/9] Remove atlas pages from demo when they're merged --- addons/xterm-addon-webgl/src/WebglAddon.ts | 3 ++ addons/xterm-addon-webgl/src/WebglRenderer.ts | 5 ++- demo/client.ts | 4 +++ src/browser/renderer/shared/TextureAtlas.ts | 32 ++++++++----------- src/browser/renderer/shared/Types.d.ts | 1 + 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglAddon.ts b/addons/xterm-addon-webgl/src/WebglAddon.ts index 5262da8e..9ae6df5a 100644 --- a/addons/xterm-addon-webgl/src/WebglAddon.ts +++ b/addons/xterm-addon-webgl/src/WebglAddon.ts @@ -21,6 +21,8 @@ export class WebglAddon extends Disposable implements ITerminalAddon { public readonly onChangeTextureAtlas = this._onChangeTextureAtlas.event; private readonly _onAddTextureAtlasCanvas = this.register(new EventEmitter()); public readonly onAddTextureAtlasCanvas = this._onAddTextureAtlasCanvas.event; + private readonly _onRemoveTextureAtlasCanvas = this.register(new EventEmitter()); + public readonly onRemoveTextureAtlasCanvas = this._onRemoveTextureAtlasCanvas.event; private readonly _onContextLoss = this.register(new EventEmitter()); public readonly onContextLoss = this._onContextLoss.event; @@ -67,6 +69,7 @@ export class WebglAddon extends Disposable implements ITerminalAddon { this.register(forwardEvent(this._renderer.onContextLoss, this._onContextLoss)); this.register(forwardEvent(this._renderer.onChangeTextureAtlas, this._onChangeTextureAtlas)); this.register(forwardEvent(this._renderer.onAddTextureAtlasCanvas, this._onAddTextureAtlasCanvas)); + this.register(forwardEvent(this._renderer.onRemoveTextureAtlasCanvas, this._onRemoveTextureAtlasCanvas)); renderService.setRenderer(this._renderer); this.register(toDisposable(() => { diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index 7570566f..7941b2a5 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -53,6 +53,8 @@ export class WebglRenderer extends Disposable implements IRenderer { public readonly onChangeTextureAtlas = this._onChangeTextureAtlas.event; private readonly _onAddTextureAtlasCanvas = this.register(new EventEmitter()); public readonly onAddTextureAtlasCanvas = this._onAddTextureAtlasCanvas.event; + private readonly _onRemoveTextureAtlasCanvas = this.register(new EventEmitter()); + public readonly onRemoveTextureAtlasCanvas = this._onRemoveTextureAtlasCanvas.event; private readonly _onRequestRedraw = this.register(new EventEmitter()); public readonly onRequestRedraw = this._onRequestRedraw.event; private readonly _onContextLoss = this.register(new EventEmitter()); @@ -270,7 +272,8 @@ export class WebglRenderer extends Disposable implements IRenderer { this._onChangeTextureAtlas.fire(atlas.pages[0].canvas); this._charAtlasDisposable = getDisposeArrayDisposable([ atlas.onRequestRedrawViewport(() => this._requestRedrawViewport()), - forwardEvent(atlas.onAddTextureAtlasCanvas, this._onAddTextureAtlasCanvas) + forwardEvent(atlas.onAddTextureAtlasCanvas, this._onAddTextureAtlasCanvas), + forwardEvent(atlas.onRemoveTextureAtlasCanvas, this._onRemoveTextureAtlasCanvas) ]); } this._charAtlas = atlas; diff --git a/demo/client.ts b/demo/client.ts index 67ad0284..3a438c00 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -279,6 +279,7 @@ function createTerminal(): void { setTextureAtlas(addons.webgl.instance.textureAtlas); addons.webgl.instance.onChangeTextureAtlas(e => setTextureAtlas(e)); addons.webgl.instance.onAddTextureAtlasCanvas(e => appendTextureAtlas(e)); + addons.webgl.instance.onRemoveTextureAtlasCanvas(e => removeTextureAtlas(e)); } }, 0); @@ -662,6 +663,9 @@ function appendTextureAtlas(e: HTMLCanvasElement): void { styleAtlasPage(e); document.querySelector('#texture-atlas').appendChild(e); } +function removeTextureAtlas(e: HTMLCanvasElement): void { + e.remove(); +} function styleAtlasPage(e: HTMLCanvasElement): void { e.style.width = `${e.width / window.devicePixelRatio}px`; e.style.height = `${e.height / window.devicePixelRatio}px`; diff --git a/src/browser/renderer/shared/TextureAtlas.ts b/src/browser/renderer/shared/TextureAtlas.ts index ffa3cb40..62f36ad3 100644 --- a/src/browser/renderer/shared/TextureAtlas.ts +++ b/src/browser/renderer/shared/TextureAtlas.ts @@ -38,7 +38,8 @@ const enum Constants { ROW_PIXEL_THRESHOLD = 2, /** * The maximum texture size regardless of what the actual hardware maximum turns out to be. This - * is enforced to ensure uploading the texture still finishes in a reasonable amount of time. + * is enforced to ensure uploading the texture still finishes in a reasonable amount of time. A + * 4096 squared image takes up 16MB of GPU memory. */ FORCED_MAX_TEXTURE_SIZE = 4096 } @@ -81,6 +82,8 @@ export class TextureAtlas implements ITextureAtlas { public readonly onRequestRedrawViewport = this._onRequestRedrawViewport.event; private readonly _onAddTextureAtlasCanvas = new EventEmitter(); public readonly onAddTextureAtlasCanvas = this._onAddTextureAtlasCanvas.event; + private readonly _onRemoveTextureAtlasCanvas = new EventEmitter(); + public readonly onRemoveTextureAtlasCanvas = this._onRemoveTextureAtlasCanvas.event; constructor( private readonly _document: Document, @@ -145,17 +148,14 @@ export class TextureAtlas implements ITextureAtlas { } private _createNewPage(): AtlasPage { - // Try merge the set of the 4 most used pages of the largest size. This is is deferred to a // microtask to ensure it does not interrupt textures that will be rendered in the current // animation frame which would result in blank rendered areas. This is actually not that // expensive relative to drawing the glyphs, so there is no need to wait for an idle callback. if (TextureAtlas.maxAtlasPages && this._pages.length >= Math.max(4, TextureAtlas.maxAtlasPages / 2)) { - // TODO: If the viewport has enough glyphs to fill the new page, there will be a webgl error queueMicrotask(() => { - // Migrate over 1 page at a time due to the time it takes to iterate over glyphs - - // Find the set of the largest 4 images below the maximum size with the highest percentages used the 4 most used pages + // Find the set of the largest 4 images, below the maximum size, with the highest + // percentages used const pagesBySize = this._pages.filter(e => { return e.canvas.width * 2 <= (TextureAtlas.maxTextureSize || Constants.FORCED_MAX_TEXTURE_SIZE); }).sort((a, b) => { @@ -175,30 +175,25 @@ export class TextureAtlas implements ITextureAtlas { } } - // TODO: This is slow, need to sort after slice so _pages doesn't get sorted - - const mergingPages = pagesBySize.slice(sameSizeI, sameSizeI + 4); // .sort((a, b) => a.percentageUsed < b.percentageUsed ? 1 : -1); + // Gather details of the merge + const mergingPages = pagesBySize.slice(sameSizeI, sameSizeI + 4); const sortedMergingPagesIndexes = mergingPages.map(e => e.glyphs[0].texturePage).sort((a, b) => a > b ? 1 : -1); - // TODO: Pull texture page index in a nicer way const mergedPageIndex = sortedMergingPagesIndexes[0]; + // Merge into the new page const mergedPage = this._mergePages(mergingPages, mergedPageIndex); - - // (console as any).image(mergedPage.canvas); - mergedPage.hasCanvasChanged = true; - // this._pages[0] = mergedPage; - // Replace an old merging page with the merged + + // Replace the first _merging_ page with the _merged_ page this._pages[mergedPageIndex] = mergedPage; - // TODO: Splice other 3 pages, shifting all other texture page props + // Delete the other 3 pages, shifting glyph texture pages as needed for (let i = sortedMergingPagesIndexes.length - 1; i >= 1; i--) { this._deletePage(sortedMergingPagesIndexes[i]); } // Request the model to be cleared to refresh all texture pages. this._requestClearModel = true; - this._onAddTextureAtlasCanvas.fire(mergedPage.canvas); }); } @@ -228,8 +223,7 @@ export class TextureAtlas implements ITextureAtlas { g.texturePositionClipSpace.y = g.texturePosition.y / mergedSize; } - p.ctx.fillStyle = 'green'; - p.ctx.fillRect(0, 0, p.canvas.width, p.canvas.height); + this._onRemoveTextureAtlasCanvas.fire(p.canvas); // Remove the merging page from active pages if it was there const index = this._activePages.indexOf(p); diff --git a/src/browser/renderer/shared/Types.d.ts b/src/browser/renderer/shared/Types.d.ts index 5f4a53ff..cbebcad4 100644 --- a/src/browser/renderer/shared/Types.d.ts +++ b/src/browser/renderer/shared/Types.d.ts @@ -91,6 +91,7 @@ export interface ITextureAtlas extends IDisposable { onRequestRedrawViewport: IEvent; onAddTextureAtlasCanvas: IEvent; + onRemoveTextureAtlasCanvas: IEvent; /** * Warm up the texture atlas, adding common glyphs to avoid slowing early frame. From 97a0df260b125ba98c647962e300b0379a9745b4 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 3 Nov 2022 05:44:50 -0700 Subject: [PATCH 9/9] Remove unused event --- addons/xterm-addon-webgl/src/WebglRenderer.ts | 1 - src/browser/renderer/shared/TextureAtlas.ts | 3 --- src/browser/renderer/shared/Types.d.ts | 1 - 3 files changed, 5 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index 7941b2a5..97e8dd7d 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -271,7 +271,6 @@ export class WebglRenderer extends Disposable implements IRenderer { this._charAtlasDisposable?.dispose(); this._onChangeTextureAtlas.fire(atlas.pages[0].canvas); this._charAtlasDisposable = getDisposeArrayDisposable([ - atlas.onRequestRedrawViewport(() => this._requestRedrawViewport()), forwardEvent(atlas.onAddTextureAtlasCanvas, this._onAddTextureAtlasCanvas), forwardEvent(atlas.onRemoveTextureAtlasCanvas, this._onRemoveTextureAtlasCanvas) ]); diff --git a/src/browser/renderer/shared/TextureAtlas.ts b/src/browser/renderer/shared/TextureAtlas.ts index 62f36ad3..654f3680 100644 --- a/src/browser/renderer/shared/TextureAtlas.ts +++ b/src/browser/renderer/shared/TextureAtlas.ts @@ -78,8 +78,6 @@ export class TextureAtlas implements ITextureAtlas { public static maxAtlasPages: number | undefined; public static maxTextureSize: number | undefined; - private readonly _onRequestRedrawViewport = new EventEmitter(); - public readonly onRequestRedrawViewport = this._onRequestRedrawViewport.event; private readonly _onAddTextureAtlasCanvas = new EventEmitter(); public readonly onAddTextureAtlasCanvas = this._onAddTextureAtlasCanvas.event; private readonly _onRemoveTextureAtlasCanvas = new EventEmitter(); @@ -106,7 +104,6 @@ export class TextureAtlas implements ITextureAtlas { for (const page of this.pages) { page.canvas.remove(); } - this._onRequestRedrawViewport.dispose(); this._onAddTextureAtlasCanvas.dispose(); } diff --git a/src/browser/renderer/shared/Types.d.ts b/src/browser/renderer/shared/Types.d.ts index cbebcad4..78a6b6e5 100644 --- a/src/browser/renderer/shared/Types.d.ts +++ b/src/browser/renderer/shared/Types.d.ts @@ -89,7 +89,6 @@ export interface IRenderer extends IDisposable { export interface ITextureAtlas extends IDisposable { readonly pages: { canvas: HTMLCanvasElement, hasCanvasChanged: boolean }[]; - onRequestRedrawViewport: IEvent; onAddTextureAtlasCanvas: IEvent; onRemoveTextureAtlasCanvas: IEvent;