Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple texture atlas pages #4244

Merged
merged 29 commits into from Oct 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
54335ef
Create texture page attribute
Tyriar Oct 29, 2022
4ebc75a
Merge remote-tracking branch 'upstream/master' into multi_page_atlas
Tyriar Oct 29, 2022
84ab6a4
Bring texturePage partially to atlas
Tyriar Oct 29, 2022
6b37187
Create AtlasPage
Tyriar Oct 29, 2022
975d52f
Remove deprecated prop
Tyriar Oct 29, 2022
67ef455
Get a second page kind of working
Tyriar Oct 29, 2022
efba2c9
Get pages working, add to demo
Tyriar Oct 29, 2022
713baeb
Base atlas page size on device pixel ratio
Tyriar Oct 29, 2022
c6e3cc0
Stop atlas flickering on demo
Tyriar Oct 29, 2022
0a49a5d
Make texture atlas presentation nicer for multiple pages
Tyriar Oct 29, 2022
c257a72
Only upload textures that change
Tyriar Oct 29, 2022
86ccd70
Avoid setting uniforms every frame
Tyriar Oct 29, 2022
04f79aa
Share page texture binding code
Tyriar Oct 29, 2022
bfa9dd5
Clean up
Tyriar Oct 30, 2022
57a65e0
Continute filling atlas page after new pages are added
Tyriar Oct 30, 2022
5e95475
Use current row when filling in old atlas pages
Tyriar Oct 30, 2022
2a3c2d9
Make better use of atlas space
Tyriar Oct 30, 2022
3f2ed42
Fix glyphs getting clipped on bottom row
Tyriar Oct 30, 2022
0f70055
Add CJK test button
Tyriar Oct 30, 2022
846573b
Support up to maximum texture units (eg. 16 on my machine)
Tyriar Oct 30, 2022
c9ef4a8
Increase texture size as it nears the maximum texture unit
Tyriar Oct 30, 2022
fc03a16
Share page creation code
Tyriar Oct 30, 2022
0592837
Fill pages to capacity
Tyriar Oct 30, 2022
e092ca7
Simplify page reuse/creation
Tyriar Oct 30, 2022
0aa9fc5
Add border around atlas pages
Tyriar Oct 30, 2022
095ceda
Show canvas atlas pages in demo
Tyriar Oct 30, 2022
04041d0
Generate bitmaps for all atlas pages
Tyriar Oct 30, 2022
dda3f5f
Properly dispose of atlas event
Tyriar Oct 30, 2022
4d05905
Polish
Tyriar Oct 31, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 20 additions & 8 deletions addons/xterm-addon-canvas/src/BaseRenderLayer.ts
Expand Up @@ -15,12 +15,13 @@ import { ReadonlyColorSet } from 'browser/Types';
import { CellData } from 'common/buffer/CellData';
import { WHITESPACE_CELL_CODE } from 'common/buffer/Constants';
import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services';
import { ICellData } from 'common/Types';
import { ICellData, IDisposable } from 'common/Types';
import { Terminal } from 'xterm';
import { IRenderLayer } from './Types';
import { CellColorResolver } from 'browser/renderer/shared/CellColorResolver';
import { Disposable, toDisposable } from 'common/Lifecycle';
import { isSafari } from 'common/Platform';
import { EventEmitter, forwardEvent } from 'common/EventEmitter';

export abstract class BaseRenderLayer extends Disposable implements IRenderLayer {
private _canvas: HTMLCanvasElement;
Expand All @@ -34,12 +35,16 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer

protected _selectionModel: ISelectionRenderModel = createSelectionRenderModel();
private _cellColorResolver: CellColorResolver;
private _bitmapGenerator?: BitmapGenerator;
private _bitmapGenerator: (BitmapGenerator | undefined)[] = [];

protected _charAtlas!: ITextureAtlas;
private _charAtlasDisposable?: IDisposable;

public get canvas(): HTMLCanvasElement { return this._canvas; }
public get cacheCanvas(): HTMLCanvasElement { return this._charAtlas?.cacheCanvas!; }
public get cacheCanvas(): HTMLCanvasElement { return this._charAtlas?.pages[0].canvas!; }

private readonly _onAddTextureAtlasCanvas = this.register(new EventEmitter<HTMLCanvasElement>());
public readonly onAddTextureAtlasCanvas = this._onAddTextureAtlasCanvas.event;

constructor(
private readonly _terminal: Terminal,
Expand Down Expand Up @@ -116,9 +121,13 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer
if (this._deviceCharWidth <= 0 && this._deviceCharHeight <= 0) {
return;
}
this._charAtlasDisposable?.dispose();
this._charAtlas = acquireTextureAtlas(this._terminal, colorSet, this._deviceCellWidth, this._deviceCellHeight, this._deviceCharWidth, this._deviceCharHeight, this._coreBrowserService.dpr);
this._charAtlasDisposable = forwardEvent(this._charAtlas.onAddTextureAtlasCanvas, this._onAddTextureAtlasCanvas);
this._charAtlas.warmUp();
this._bitmapGenerator = new BitmapGenerator(this._charAtlas.cacheCanvas);
for (let i = 0; i < this._charAtlas.pages.length; i++) {
this._bitmapGenerator[i] = new BitmapGenerator(this._charAtlas.pages[i].canvas);
}
}

public resize(dim: IRenderDimensions): void {
Expand Down Expand Up @@ -367,12 +376,15 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer
this._ctx.save();
this._clipRow(y);
// Draw the image, use the bitmap if it's available
if (this._charAtlas.hasCanvasChanged) {
this._bitmapGenerator?.refresh();
this._charAtlas.hasCanvasChanged = false;
if (this._charAtlas.pages[glyph.texturePage].hasCanvasChanged) {
if (!this._bitmapGenerator[glyph.texturePage]) {
this._bitmapGenerator[glyph.texturePage] = new BitmapGenerator(this._charAtlas.pages[glyph.texturePage].canvas);
}
this._bitmapGenerator[glyph.texturePage]?.refresh();
this._charAtlas.pages[glyph.texturePage].hasCanvasChanged = false;
}
this._ctx.drawImage(
this._bitmapGenerator?.bitmap || this._charAtlas!.cacheCanvas,
this._bitmapGenerator[glyph.texturePage]?.bitmap || this._charAtlas!.pages[glyph.texturePage].canvas,
glyph.texturePosition.x,
glyph.texturePosition.y,
glyph.size.x,
Expand Down
3 changes: 3 additions & 0 deletions addons/xterm-addon-canvas/src/CanvasAddon.ts
Expand Up @@ -17,6 +17,8 @@ export class CanvasAddon extends Disposable implements ITerminalAddon {

private readonly _onChangeTextureAtlas = this.register(new EventEmitter<HTMLCanvasElement>());
public readonly onChangeTextureAtlas = this._onChangeTextureAtlas.event;
private readonly _onAddTextureAtlasCanvas = this.register(new EventEmitter<HTMLCanvasElement>());
public readonly onAddTextureAtlasCanvas = this._onAddTextureAtlasCanvas.event;

public get textureAtlas(): HTMLCanvasElement | undefined {
return this._renderer?.textureAtlas;
Expand Down Expand Up @@ -46,6 +48,7 @@ export class CanvasAddon extends Disposable implements ITerminalAddon {

this._renderer = new CanvasRenderer(terminal, screenElement, linkifier, bufferService, charSizeService, optionsService, characterJoinerService, coreService, coreBrowserService, decorationService, themeService);
this.register(forwardEvent(this._renderer.onChangeTextureAtlas, this._onChangeTextureAtlas));
this.register(forwardEvent(this._renderer.onAddTextureAtlasCanvas, this._onAddTextureAtlasCanvas));
renderService.setRenderer(this._renderer);
renderService.handleResize(bufferService.cols, bufferService.rows);

Expand Down
7 changes: 6 additions & 1 deletion addons/xterm-addon-canvas/src/CanvasRenderer.ts
Expand Up @@ -9,7 +9,7 @@ import { createRenderDimensions } from 'browser/renderer/shared/RendererUtils';
import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from 'browser/renderer/shared/Types';
import { ICharacterJoinerService, ICharSizeService, ICoreBrowserService, IThemeService } from 'browser/services/Services';
import { ILinkifier2 } from 'browser/Types';
import { EventEmitter } from 'common/EventEmitter';
import { EventEmitter, forwardEvent } from 'common/EventEmitter';
import { Disposable, toDisposable } from 'common/Lifecycle';
import { IBufferService, ICoreService, IDecorationService, IOptionsService } from 'common/services/Services';
import { Terminal } from 'xterm';
Expand All @@ -29,6 +29,8 @@ export class CanvasRenderer extends Disposable implements IRenderer {
public readonly onRequestRedraw = this._onRequestRedraw.event;
private readonly _onChangeTextureAtlas = this.register(new EventEmitter<HTMLCanvasElement>());
public readonly onChangeTextureAtlas = this._onChangeTextureAtlas.event;
private readonly _onAddTextureAtlasCanvas = this.register(new EventEmitter<HTMLCanvasElement>());
public readonly onAddTextureAtlasCanvas = this._onAddTextureAtlasCanvas.event;

constructor(
private readonly _terminal: Terminal,
Expand All @@ -51,6 +53,9 @@ export class CanvasRenderer extends Disposable implements IRenderer {
new LinkRenderLayer(this._terminal, this._screenElement, 2, linkifier2, this._bufferService, this._optionsService, decorationService, this._coreBrowserService, _themeService),
new CursorRenderLayer(this._terminal, this._screenElement, 3, this._onRequestRedraw, this._bufferService, this._optionsService, coreService, this._coreBrowserService, decorationService, _themeService)
];
for (const layer of this._renderLayers) {
forwardEvent(layer.onAddTextureAtlasCanvas, this._onAddTextureAtlasCanvas);
}
this.dimensions = createRenderDimensions();
this._devicePixelRatio = this._coreBrowserService.dpr;
this._updateDimensions();
Expand Down
1 change: 1 addition & 0 deletions addons/xterm-addon-canvas/src/Types.d.ts
Expand Up @@ -42,6 +42,7 @@ export interface IRenderLayer extends IDisposable {
readonly canvas: HTMLCanvasElement;
readonly cacheCanvas: HTMLCanvasElement;

readonly onAddTextureAtlasCanvas: IEvent<HTMLCanvasElement>;
/**
* Called when the terminal loses focus.
*/
Expand Down
5 changes: 5 additions & 0 deletions addons/xterm-addon-canvas/typings/xterm-addon-canvas.d.ts
Expand Up @@ -17,6 +17,11 @@ declare module 'xterm-addon-canvas' {
*/
public readonly onChangeTextureAtlas: IEvent<HTMLCanvasElement>;

/**
* An event that is fired when the a new page is added to the texture atlas.
*/
public readonly onAddTextureAtlasCanvas: IEvent<HTMLCanvasElement>;

constructor();

/**
Expand Down