Merge pull request #4141 from Tyriar/idle_task_queue

Do char atlas warmup via new IdleTaskQueue
This commit is contained in:
Daniel Imms
2022-09-24 11:44:10 -07:00
committed by GitHub
2 changed files with 62 additions and 8 deletions
@@ -16,6 +16,7 @@ import { tryDrawCustomChar } from 'browser/renderer/CustomGlyphs';
import { excludeFromContrastRatioDemands, isPowerlineGlyph, isRestrictedPowerlineGlyph } from 'browser/renderer/RendererUtils';
import { IUnicodeService } from 'common/services/Services';
import { FourKeyMap } from 'common/MultiKeyMap';
import { IdleTaskQueue } from 'common/IdleTaskQueue';
// For debugging purposes, it can be useful to set this to a really tiny value,
// to verify that LRU eviction works.
@@ -124,20 +125,21 @@ export class WebglCharAtlas implements IDisposable {
public warmUp(): void {
if (!this._didWarmUp) {
(typeof requestIdleCallback !== 'function' ? requestIdleCallback : setTimeout)(() => {
this._doWarmUp();
});
this._doWarmUp();
this._didWarmUp = true;
}
}
private _doWarmUp(): void {
// Pre-fill with ASCII 33-126
// Pre-fill with ASCII 33-126, this is not urgent and done in idle callbacks
const queue = new IdleTaskQueue();
for (let i = 33; i < 126; i++) {
if (!this._cacheMap.get(i, DEFAULT_COLOR, DEFAULT_COLOR, DEFAULT_EXT)) {
const rasterizedGlyph = this._drawToCache(i, DEFAULT_COLOR, DEFAULT_COLOR, DEFAULT_EXT);
this._cacheMap.set(i, DEFAULT_COLOR, DEFAULT_COLOR, DEFAULT_EXT, rasterizedGlyph);
}
queue.enqueue(() => {
if (!this._cacheMap.get(i, DEFAULT_COLOR, DEFAULT_COLOR, DEFAULT_EXT)) {
const rasterizedGlyph = this._drawToCache(i, DEFAULT_COLOR, DEFAULT_COLOR, DEFAULT_EXT);
this._cacheMap.set(i, DEFAULT_COLOR, DEFAULT_COLOR, DEFAULT_EXT, rasterizedGlyph);
}
});
}
}
+52
View File
@@ -0,0 +1,52 @@
/**
* Copyright (c) 2022 The xterm.js authors. All rights reserved.
* @license MIT
*/
/**
* A queue of that runs tasks over several idle callbacks, trying to maintain the specified
* frame rate. The tasks will run in the order they are enqueued, but they will run some time later,
* and care should be taken to ensure they're non-urgent and will not introduce race conditions.
*/
export class IdleTaskQueue {
private _tasks: Function[] = [];
private _idleCallback?: number;
private _maxTaskDuration: number;
private _i = 0;
/**
* @param targetFps The target frame rate.
*/
constructor(targetFps: number = 240) {
this._maxTaskDuration = 1000 / targetFps;
}
/**
* Adds a task to the queue which will run in a future idle callback.
*/
public enqueue(task: Function): void {
this._tasks.push(task);
this._start();
}
private _start(): void {
if (!this._idleCallback) {
this._idleCallback = requestIdleCallback(() => this._process());
}
}
private _process(): void {
const start = performance.now();
this._idleCallback = undefined;
while (this._i < this._tasks.length) {
this._tasks[this._i++]();
if (performance.now() - start > this._maxTaskDuration) {
this._start();
return;
}
}
// Clear the queue
this._i = 0;
this._tasks.length = 0;
}
}