diff --git a/addons/xterm-addon-webgl/src/GlyphRenderer.ts b/addons/xterm-addon-webgl/src/GlyphRenderer.ts index b19c8cb1..c198c9ba 100644 --- a/addons/xterm-addon-webgl/src/GlyphRenderer.ts +++ b/addons/xterm-addon-webgl/src/GlyphRenderer.ts @@ -4,13 +4,12 @@ */ import { createProgram, PROJECTION_MATRIX, throwIfFalsy } from './WebglUtils'; -import { WebglCharAtlas } from './atlas/WebglCharAtlas'; import { IWebGL2RenderingContext, IWebGLVertexArrayObject, IRenderModel, IRasterizedGlyph } from './Types'; import { fill } from 'common/TypedArrayUtils'; import { NULL_CELL_CODE } from 'common/buffer/Constants'; import { Terminal } from 'xterm'; import { IColorSet } from 'browser/Types'; -import { IRenderDimensions } from 'browser/renderer/shared/Types'; +import { IRenderDimensions, ITextureAtlas } from 'browser/renderer/shared/Types'; import { Disposable, toDisposable } from 'common/Lifecycle'; interface IVertices { @@ -77,7 +76,7 @@ let $leftCellPadding = 0; let $clippedPixels = 0; export class GlyphRenderer extends Disposable { - private _atlas: WebglCharAtlas | undefined; + private _atlas: ITextureAtlas | undefined; private _program: WebGLProgram; private _vertexArrayObject: IWebGLVertexArrayObject; @@ -321,7 +320,7 @@ export class GlyphRenderer extends Disposable { gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, bufferLength / INDICES_PER_CELL); } - public setAtlas(atlas: WebglCharAtlas): void { + public setAtlas(atlas: ITextureAtlas): void { const gl = this._gl; this._atlas = atlas; diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index 34f247eb..b3a3ed02 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -7,7 +7,6 @@ import { GlyphRenderer } from './GlyphRenderer'; import { LinkRenderLayer } from './renderLayer/LinkRenderLayer'; import { CursorRenderLayer } from './renderLayer/CursorRenderLayer'; import { acquireCharAtlas, removeTerminalFromCache } from './atlas/CharAtlasCache'; -import { WebglCharAtlas } from './atlas/WebglCharAtlas'; import { RectangleRenderer } from './RectangleRenderer'; import { IWebGL2RenderingContext } from './Types'; import { RenderModel, COMBINED_CHAR_BIT_MASK, RENDER_MODEL_BG_OFFSET, RENDER_MODEL_FG_OFFSET, RENDER_MODEL_EXT_OFFSET, RENDER_MODEL_INDICIES_PER_CELL } from './RenderModel'; @@ -15,7 +14,7 @@ import { Disposable } from 'common/Lifecycle'; import { Attributes, BgFlags, Content, FgFlags, NULL_CELL_CHAR, NULL_CELL_CODE } from 'common/buffer/Constants'; import { Terminal, IEvent } from 'xterm'; import { IRenderLayer } from './renderLayer/Types'; -import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from 'browser/renderer/shared/Types'; +import { IRenderDimensions, IRenderer, IRequestRedrawEvent, ITextureAtlas } from 'browser/renderer/shared/Types'; import { observeDevicePixelDimensions } from 'browser/renderer/shared/DevicePixelObserver'; import { ITerminal, IColorSet } from 'browser/Types'; import { EventEmitter } from 'common/EventEmitter'; @@ -35,7 +34,7 @@ let $isSelected = false; export class WebglRenderer extends Disposable implements IRenderer { private _renderLayers: IRenderLayer[]; - private _charAtlas: WebglCharAtlas | undefined; + private _charAtlas: ITextureAtlas | undefined; private _devicePixelRatio: number; private _model: RenderModel = new RenderModel(); diff --git a/addons/xterm-addon-webgl/src/atlas/CharAtlasCache.ts b/addons/xterm-addon-webgl/src/atlas/CharAtlasCache.ts index e70a4995..741de255 100644 --- a/addons/xterm-addon-webgl/src/atlas/CharAtlasCache.ts +++ b/addons/xterm-addon-webgl/src/atlas/CharAtlasCache.ts @@ -6,11 +6,11 @@ import { WebglCharAtlas } from './WebglCharAtlas'; import { Terminal } from 'xterm'; import { IColorSet, ITerminal } from 'browser/Types'; -import { ICharAtlasConfig } from 'browser/renderer/shared/Types'; +import { ICharAtlasConfig, ITextureAtlas } from 'browser/renderer/shared/Types'; import { generateConfig, configEquals } from 'browser/renderer/shared/CharAtlasUtils'; interface ICharAtlasCacheEntry { - atlas: WebglCharAtlas; + atlas: ITextureAtlas; config: ICharAtlasConfig; // N.B. This implementation potentially holds onto copies of the terminal forever, so // this may cause memory leaks. @@ -33,7 +33,7 @@ export function acquireCharAtlas( scaledCharWidth: number, scaledCharHeight: number, devicePixelRatio: number -): WebglCharAtlas { +): ITextureAtlas { const newConfig = generateConfig(scaledCellWidth, scaledCellHeight, scaledCharWidth, scaledCharHeight, terminal, colors, devicePixelRatio); // Check to see if the terminal already owns this config diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index b9a4088d..8782e123 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -16,7 +16,7 @@ import { excludeFromContrastRatioDemands, isPowerlineGlyph, isRestrictedPowerlin import { IUnicodeService } from 'common/services/Services'; import { FourKeyMap } from 'common/MultiKeyMap'; import { IdleTaskQueue } from 'common/TaskQueue'; -import { ICharAtlasConfig } from 'browser/renderer/shared/Types'; +import { ICharAtlasConfig, ITextureAtlas } from 'browser/renderer/shared/Types'; // For debugging purposes, it can be useful to set this to a really tiny value, // to verify that LRU eviction works. @@ -51,7 +51,7 @@ interface ICharAtlasActiveRow { // Work variables to avoid garbage collection let $glyph = undefined; -export class WebglCharAtlas implements IDisposable { +export class WebglCharAtlas implements ITextureAtlas { private _didWarmUp: boolean = false; private _cacheMap: FourKeyMap = new FourKeyMap(); diff --git a/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts index 2cba49dd..1321c246 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts @@ -9,9 +9,8 @@ import { Terminal } from 'xterm'; import { IColorSet } from 'browser/Types'; import { TEXT_BASELINE } from 'browser/renderer/shared/Constants'; import { ICoreBrowserService } from 'browser/services/Services'; -import { IRenderDimensions } from 'browser/renderer/shared/Types'; +import { IRenderDimensions, ITextureAtlas } from 'browser/renderer/shared/Types'; import { CellData } from 'common/buffer/CellData'; -import { WebglCharAtlas } from 'atlas/WebglCharAtlas'; import { throwIfFalsy } from '../WebglUtils'; export abstract class BaseRenderLayer implements IRenderLayer { @@ -24,7 +23,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { private _scaledCharLeft: number = 0; private _scaledCharTop: number = 0; - protected _charAtlas: WebglCharAtlas | undefined; + protected _charAtlas: ITextureAtlas | undefined; constructor( private _container: HTMLElement, diff --git a/src/browser/renderer/shared/Types.d.ts b/src/browser/renderer/shared/Types.d.ts index ccfcae43..8fde3ae8 100644 --- a/src/browser/renderer/shared/Types.d.ts +++ b/src/browser/renderer/shared/Types.d.ts @@ -74,3 +74,61 @@ export interface IRenderer extends IDisposable { renderRows(start: number, end: number): void; clearTextureAtlas?(): void; } + +export interface ITextureAtlas extends IDisposable { + readonly cacheCanvas: HTMLCanvasElement; + // TODO: Add endFrame and make this readonly + hasCanvasChanged: boolean; + + /** + * Warm up the texture atlas, adding common glyphs to avoid slowing early frame. + */ + warmUp(): void; + + /** + * Call when a frame is being drawn, this will return true if the atlas was cleared to make room + * for a new set of glyphs. + */ + beginFrame(): boolean; + + /** + * Clear all glyphs from the texture atlas. + */ + clearTexture(): void; + getRasterizedGlyph(code: number, bg: number, fg: number, ext: number): IRasterizedGlyph; + getRasterizedGlyphCombinedChar(chars: string, bg: number, fg: number, ext: number): IRasterizedGlyph; +} + +/** + * Represents a rasterized glyph within a texture atlas. Some numbers are + * tracked in CSS pixels as well in order to reduce calculations during the + * render loop. + */ +export interface IRasterizedGlyph { + /** + * The x and y offset between the glyph's top/left and the top/left of a cell + * in pixels. + */ + offset: IVector; + /** + * the x and y position of the glyph in the texture in pixels. + */ + texturePosition: IVector; + /** + * the x and y position of the glyph in the texture in clip space coordinates. + */ + texturePositionClipSpace: IVector; + /** + * The width and height of the glyph in the texture in pixels. + */ + size: IVector; + /** + * The width and height of the glyph in the texture in clip space coordinates. + */ + sizeClipSpace: IVector; +} + +export interface IVector { + x: number; + y: number; +}