Bring back ImageBitmap optimization in canvas renderer

It's more simple than it used to be, it will clear and debounce all
glyphs when any change is made.
This commit is contained in:
Daniel Imms
2022-10-04 15:24:10 -07:00
parent 3b260a2193
commit e0324e32a8
2 changed files with 58 additions and 2 deletions
@@ -32,6 +32,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
protected _selectionModel: ISelectionRenderModel = createSelectionRenderModel();
private _cellColorResolver: CellColorResolver;
private _bitmapGenerator?: BitmapGenerator;
protected _charAtlas!: ITextureAtlas;
@@ -115,6 +116,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
}
this._charAtlas = acquireTextureAtlas(this._terminal, colorSet, this._scaledCellWidth, this._scaledCellHeight, this._scaledCharWidth, this._scaledCharHeight, this._coreBrowserService.dpr);
this._charAtlas.warmUp();
this._bitmapGenerator = new BitmapGenerator(this._charAtlas.cacheCanvas);
}
public resize(dim: IRenderDimensions): void {
@@ -353,6 +355,10 @@ export abstract class BaseRenderLayer implements IRenderLayer {
* the character atlas to reduce draw time.
*/
protected _drawChars(cell: ICellData, x: number, y: number): void {
if (this._charAtlas.hasCanvasChanged) {
this._bitmapGenerator?.refresh();
this._charAtlas.hasCanvasChanged = false;
}
const chars = cell.getChars();
this._cellColorResolver.resolve(cell, x, y);
let glyph: IRasterizedGlyph;
@@ -363,8 +369,9 @@ export abstract class BaseRenderLayer implements IRenderLayer {
}
this._ctx.save();
this._clipRow(y);
// Draw the image, use the bitmap if it's available
this._ctx.drawImage(
this._charAtlas!.cacheCanvas,
this._bitmapGenerator?.bitmap || this._charAtlas!.cacheCanvas,
glyph.texturePosition.x,
glyph.texturePosition.y,
glyph.size.x,
@@ -403,3 +410,53 @@ export abstract class BaseRenderLayer implements IRenderLayer {
}
}
/**
* The number of milliseconds to wait before generating the ImageBitmap, this is to debounce/batch
* the operation as window.createImageBitmap is asynchronous.
*/
const GLYPH_BITMAP_COMMIT_DELAY = 100;
const enum BitmapGeneratorState {
IDLE = 0,
GENERATING = 1,
GENERATING_INVALID = 2
}
class BitmapGenerator {
private _state: BitmapGeneratorState = BitmapGeneratorState.IDLE;
private _commitTimeout: number | undefined = undefined;
private _bitmap: ImageBitmap | undefined = undefined;
public get bitmap(): ImageBitmap | undefined { return this._bitmap; }
constructor(private readonly _canvas: HTMLCanvasElement) {
}
public refresh(): void {
// Clear the bitmap immediately as it's stale
this._bitmap = undefined;
if (this._commitTimeout === undefined) {
this._commitTimeout = window.setTimeout(() => this._generate(), GLYPH_BITMAP_COMMIT_DELAY);
}
if (this._state === BitmapGeneratorState.GENERATING) {
this._state = BitmapGeneratorState.GENERATING_INVALID;
}
}
private _generate(): void {
if (this._state === BitmapGeneratorState.IDLE) {
this._bitmap = undefined;
this._state = BitmapGeneratorState.GENERATING;
window.createImageBitmap(this._canvas).then(bitmap => {
if (this._state === BitmapGeneratorState.GENERATING_INVALID) {
this.refresh();
} else {
this._bitmap = bitmap;
}
this._state = BitmapGeneratorState.IDLE;
});
if (this._commitTimeout) {
this._commitTimeout = undefined;
}
}
}
}
-1
View File
@@ -77,7 +77,6 @@ export interface IRenderer extends IDisposable {
export interface ITextureAtlas extends IDisposable {
readonly cacheCanvas: HTMLCanvasElement;
// TODO: Add endFrame and make this readonly
hasCanvasChanged: boolean;
/**