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

Dynamic atlas: Reduce unnecessary objects generated and draw from ImageBitmap #1692

Merged
merged 18 commits into from Sep 23, 2018
Merged
Changes from 1 commit
Commits
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
55 changes: 52 additions & 3 deletions src/renderer/atlas/DynamicCharAtlas.ts
Expand Up @@ -29,9 +29,14 @@ const TRANSPARENT_COLOR = {
// cache.
const FRAME_CACHE_DRAW_LIMIT = 100;

const GLYPH_BITMAP_COMMIT_DELAY = 100;

const GLYPH_BITMAP_COMMIT_LIMIT = 100;

interface IGlyphCacheValue {
index: number;
isEmpty: boolean;
inBitmap: boolean;
}

function getGlyphCacheKey(code: number, fg: number, bg: number, bold: boolean, dim: boolean, italic: boolean): number {
Expand Down Expand Up @@ -65,6 +70,11 @@ export default class DynamicCharAtlas extends BaseCharAtlas {

private _drawToCacheCount: number = 0;

private _glyphsWaitingOnBitmap: Uint32Array = new Uint32Array(GLYPH_BITMAP_COMMIT_LIMIT);
private _glyphsWaitingOnBitmapCount: number = 0;
Tyriar marked this conversation as resolved.
Show resolved Hide resolved
private _bitmapCommitTimeout: number | null = null;
private _bitmap: ImageBitmap | null = null;

constructor(document: Document, private _config: ICharAtlasConfig) {
super();
this._cacheCanvas = document.createElement('canvas');
Expand Down Expand Up @@ -124,7 +134,7 @@ export default class DynamicCharAtlas extends BaseCharAtlas {
// we're out of space, so our call to set will delete this item
index = this._cacheMap.peek().index;
}
const cacheValue = this._drawToCache(chars, bg, fg, bold, dim, italic, index);
const cacheValue = this._drawToCache(chars, code, bg, fg, bold, dim, italic, index);
this._cacheMap.set(glyphKey, cacheValue);
this._drawFromCache(ctx, cacheValue, x, y);
return true;
Expand Down Expand Up @@ -164,7 +174,7 @@ export default class DynamicCharAtlas extends BaseCharAtlas {
const cacheX = this._toCoordinateX(cacheValue.index);
const cacheY = this._toCoordinateY(cacheValue.index);
ctx.drawImage(
this._cacheCanvas,
cacheValue.inBitmap ? this._bitmap : this._cacheCanvas,
cacheX,
cacheY,
this._config.scaledCharWidth,
Expand Down Expand Up @@ -211,6 +221,7 @@ export default class DynamicCharAtlas extends BaseCharAtlas {
// into a shared function.
private _drawToCache(
chars: string,
code: number,
bg: number,
fg: number,
bold: boolean,
Expand Down Expand Up @@ -264,9 +275,47 @@ export default class DynamicCharAtlas extends BaseCharAtlas {
// putImageData doesn't do any blending, so it will overwrite any existing cache entry for us
this._cacheCtx.putImageData(imageData, x, y);

this._glyphsWaitingOnBitmap[this._glyphsWaitingOnBitmapCount++] = getGlyphCacheKey(code, fg, bg, bold, dim, italic);
this._queueGenerateBitmap();

return {
index,
isEmpty
isEmpty,
inBitmap: false
};
}

private _queueGenerateBitmap(): void {
// Check if it's already queued
if (this._bitmapCommitTimeout !== null) {
return;
}

this._bitmapCommitTimeout = window.setTimeout(() => this._generateBitmap(), GLYPH_BITMAP_COMMIT_DELAY);
Tyriar marked this conversation as resolved.
Show resolved Hide resolved
}

private _generateBitmap(): void {
const countAtGeneration = this._glyphsWaitingOnBitmapCount;
// TODO: Fallback when createImageBitmap not supported
window.createImageBitmap(this._cacheCanvas).then(bitmap => {
// Set bitmap
this._bitmap = bitmap;

// Mark all new glyphs as in bitmap
for (let i = 0; i < countAtGeneration; i++) {
const key = this._glyphsWaitingOnBitmap[i];
this._cacheMap.get(key).inBitmap = true;
Tyriar marked this conversation as resolved.
Show resolved Hide resolved
this._glyphsWaitingOnBitmap[i] = 0;
}

// Fix up any glyphs that were added since image bitmap was created
if (countAtGeneration > this._glyphsWaitingOnBitmapCount) {
// TODO: Verify this
// TODO: Use 2 arrays to speed up set?
this._glyphsWaitingOnBitmap.set(this._glyphsWaitingOnBitmap.subarray(countAtGeneration, this._glyphsWaitingOnBitmapCount - countAtGeneration), 0);
}
Tyriar marked this conversation as resolved.
Show resolved Hide resolved
this._glyphsWaitingOnBitmapCount -= countAtGeneration;
});
this._bitmapCommitTimeout = null;
}
}