mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Increase texture size as it nears the maximum texture unit
#4243 would be a better, but more complicated, solution to this
This commit is contained in:
@@ -122,6 +122,7 @@ export class GlyphRenderer extends Disposable {
|
||||
if (GlyphRenderer._maxAtlasPages === undefined) {
|
||||
GlyphRenderer._maxAtlasPages = throwIfFalsy(gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS) as number | null);
|
||||
}
|
||||
|
||||
this._program = throwIfFalsy(createProgram(gl, vertexShaderSource, createFragmentShaderSource(GlyphRenderer._maxAtlasPages)));
|
||||
this.register(toDisposable(() => gl.deleteProgram(this._program)));
|
||||
|
||||
@@ -285,7 +286,8 @@ export class GlyphRenderer extends Disposable {
|
||||
} else {
|
||||
this._vertices.attributes.fill(0);
|
||||
}
|
||||
for (let i = 0; i < this._vertices.attributesBuffers.length; i++) {
|
||||
let i = 0;
|
||||
for (; i < this._vertices.attributesBuffers.length; i++) {
|
||||
if (this._vertices.count !== newCount) {
|
||||
this._vertices.attributesBuffers[i] = new Float32Array(newCount);
|
||||
} else {
|
||||
@@ -293,7 +295,7 @@ export class GlyphRenderer extends Disposable {
|
||||
}
|
||||
}
|
||||
this._vertices.count = newCount;
|
||||
let i = 0;
|
||||
i = 0;
|
||||
for (let y = 0; y < terminal.rows; y++) {
|
||||
for (let x = 0; x < terminal.cols; x++) {
|
||||
this._vertices.attributes[i + 9] = x / terminal.cols;
|
||||
|
||||
@@ -7,7 +7,8 @@ import { addDisposableDomListener } from 'browser/Lifecycle';
|
||||
import { CellColorResolver } from 'browser/renderer/shared/CellColorResolver';
|
||||
import { acquireTextureAtlas, removeTerminalFromCache } from 'browser/renderer/shared/CharAtlasCache';
|
||||
import { observeDevicePixelDimensions } from 'browser/renderer/shared/DevicePixelObserver';
|
||||
import { createRenderDimensions } from 'browser/renderer/shared/RendererUtils';
|
||||
import { createRenderDimensions, throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
||||
import { TextureAtlas } from 'browser/renderer/shared/TextureAtlas';
|
||||
import { IRenderDimensions, IRenderer, IRequestRedrawEvent, ITextureAtlas } from 'browser/renderer/shared/Types';
|
||||
import { ICharacterJoinerService, ICharSizeService, ICoreBrowserService, IThemeService } from 'browser/services/Services';
|
||||
import { ITerminal } from 'browser/Types';
|
||||
|
||||
@@ -67,6 +67,19 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
private _workBoundingBox: IBoundingBox = { top: 0, left: 0, bottom: 0, right: 0 };
|
||||
private _workAttributeData: AttributeData = new AttributeData();
|
||||
|
||||
private _textureSize: number = 512;
|
||||
|
||||
/**
|
||||
* Doubles the texture size of new atlas pages if allowed.
|
||||
*/
|
||||
private _increaseTextureSize(): void {
|
||||
// 4096 is the minimum texture size in WebGL, but we still want the texture to be reasonably fast
|
||||
// to upload. We could loosen this limit if it ever becomes a problem.
|
||||
if (this._textureSize < 2048) {
|
||||
this._textureSize *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly _onAddTextureAtlasCanvas = new EventEmitter<HTMLCanvasElement>();
|
||||
public readonly onAddTextureAtlasCanvas = this._onAddTextureAtlasCanvas.event;
|
||||
|
||||
@@ -75,7 +88,7 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
private readonly _config: ICharAtlasConfig,
|
||||
private readonly _unicodeService: IUnicodeService
|
||||
) {
|
||||
const page = new AtlasPage(_document, _config.devicePixelRatio);
|
||||
const page = new AtlasPage(_document, this._textureSize);
|
||||
this._pages.push(page);
|
||||
this._activePages.push(page);
|
||||
this._tmpCanvas = createCanvas(
|
||||
@@ -121,8 +134,11 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
// TODO: Revisit when a new page gets added, this is only really needed now when there is no
|
||||
// room for a new row
|
||||
if (page.currentRow.y > Math.floor(page.canvas.height * 0.8)) {
|
||||
if (this._pages.length === 4 || this._pages.length === 7) {
|
||||
this._increaseTextureSize();
|
||||
}
|
||||
// TODO: Clear all pages and restart if the maximum page count is reached
|
||||
const newPage = new AtlasPage(this._document, this._config.devicePixelRatio);
|
||||
const newPage = new AtlasPage(this._document, this._textureSize);
|
||||
this._pages.push(newPage);
|
||||
this._activePages.push(newPage);
|
||||
this._onAddTextureAtlasCanvas.fire(newPage.canvas);
|
||||
@@ -597,7 +613,7 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
}
|
||||
|
||||
// TODO: Ideally this wouldn't pull dimensions off the first canvas
|
||||
const rasterizedGlyph = this._findGlyphBoundingBox(imageData, this._workBoundingBox, allowedWidth, restrictedPowerlineGlyph, customGlyph, padding, this._pages[0].canvas.width, this._pages[0].canvas.height);
|
||||
const rasterizedGlyph = this._findGlyphBoundingBox(imageData, this._workBoundingBox, allowedWidth, restrictedPowerlineGlyph, customGlyph, padding);
|
||||
|
||||
// Find the best atlas row to use
|
||||
let activePage: AtlasPage;
|
||||
@@ -646,7 +662,10 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
if (candidatePage === undefined) {
|
||||
// Creating a new page if there is no room
|
||||
// TODO: Share atlas page creation code
|
||||
const newPage = new AtlasPage(this._document, this._config.devicePixelRatio);
|
||||
if (this._pages.length === 4 || this._pages.length === 7) {
|
||||
this._increaseTextureSize();
|
||||
}
|
||||
const newPage = new AtlasPage(this._document, this._textureSize);
|
||||
this._pages.push(newPage);
|
||||
this._activePages.push(newPage);
|
||||
this._onAddTextureAtlasCanvas.fire(newPage.canvas);
|
||||
@@ -720,6 +739,10 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
rasterizedGlyph.texturePositionClipSpace.x = activeRow.x / activePage.canvas.width;
|
||||
rasterizedGlyph.texturePositionClipSpace.y = activeRow.y / activePage.canvas.height;
|
||||
|
||||
// Fix the clipspace position as pages may be of differing size
|
||||
rasterizedGlyph.sizeClipSpace.x /= activePage.canvas.width;
|
||||
rasterizedGlyph.sizeClipSpace.y /= activePage.canvas.height;
|
||||
|
||||
// Update atlas current row, for fixed rows the glyph height will never be larger than the row
|
||||
// height
|
||||
activeRow.height = Math.max(activeRow.height, rasterizedGlyph.size.y);
|
||||
@@ -747,7 +770,7 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
* @param imageData The image data to read.
|
||||
* @param boundingBox An IBoundingBox to put the clipped bounding box values.
|
||||
*/
|
||||
private _findGlyphBoundingBox(imageData: ImageData, boundingBox: IBoundingBox, allowedWidth: number, restrictedGlyph: boolean, customGlyph: boolean, padding: number, pageWidth: number, pageHeight: number): IRasterizedGlyph {
|
||||
private _findGlyphBoundingBox(imageData: ImageData, boundingBox: IBoundingBox, allowedWidth: number, restrictedGlyph: boolean, customGlyph: boolean, padding: number): IRasterizedGlyph {
|
||||
boundingBox.top = 0;
|
||||
const height = restrictedGlyph ? this._config.deviceCellHeight : this._tmpCanvas.height;
|
||||
const width = restrictedGlyph ? this._config.deviceCellWidth : allowedWidth;
|
||||
@@ -819,8 +842,8 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
y: boundingBox.bottom - boundingBox.top + 1
|
||||
},
|
||||
sizeClipSpace: {
|
||||
x: (boundingBox.right - boundingBox.left + 1) / pageWidth,
|
||||
y: (boundingBox.bottom - boundingBox.top + 1) / pageHeight
|
||||
x: (boundingBox.right - boundingBox.left + 1),
|
||||
y: (boundingBox.bottom - boundingBox.top + 1)
|
||||
},
|
||||
offset: {
|
||||
x: -boundingBox.left + padding + ((restrictedGlyph || customGlyph) ? Math.floor((this._config.deviceCellWidth - this._config.deviceCharWidth) / 2) : 0),
|
||||
@@ -859,10 +882,8 @@ class AtlasPage {
|
||||
|
||||
constructor(
|
||||
document: Document,
|
||||
dpr: number
|
||||
size: number
|
||||
) {
|
||||
// TODO: Enforce a maximum texture size
|
||||
const size = Math.pow(2, 8 + Math.max(1, dpr));
|
||||
this.canvas = createCanvas(document, size, size);
|
||||
// The canvas needs alpha because we use clearColor to convert the background color to alpha.
|
||||
// It might also contain some characters with transparent backgrounds if allowTransparency is
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
export const DEFAULT_COLOR = 256;
|
||||
export const DEFAULT_COLOR = 0;
|
||||
export const DEFAULT_ATTR = (0 << 18) | (DEFAULT_COLOR << 9) | (256 << 0);
|
||||
export const DEFAULT_EXT = 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user