Clear texture atlas on zoom change and rasterizer on config change

Fixes #234213
This commit is contained in:
Daniel Imms 2024-11-20 04:46:05 -08:00
Родитель 1dd8c77ac7
Коммит f154193b01
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E5CF412B63651C69
3 изменённых файлов: 36 добавлений и 12 удалений

Просмотреть файл

@ -5,6 +5,7 @@
import { getActiveWindow } from '../../../base/browser/dom.js';
import { BugIndicatingError } from '../../../base/common/errors.js';
import { MandatoryMutableDisposable } from '../../../base/common/lifecycle.js';
import { EditorOption } from '../../common/config/editorOptions.js';
import { CursorColumns } from '../../common/core/cursorColumns.js';
import type { IViewLineTokens } from '../../common/tokens/lineTokens.js';
@ -38,13 +39,17 @@ const enum CellBufferInfo {
TextureIndex = 5,
}
type QueuedBufferEvent = ViewLinesDeletedEvent | ViewZonesChangedEvent;
type QueuedBufferEvent = (
ViewConfigurationChangedEvent |
ViewLinesDeletedEvent |
ViewZonesChangedEvent
);
export class FullFileRenderStrategy extends ViewEventHandler implements IGpuRenderStrategy {
readonly wgsl: string = fullFileRenderStrategyWgsl;
private readonly _glyphRasterizer: GlyphRasterizer;
private readonly _glyphRasterizer: MandatoryMutableDisposable<GlyphRasterizer>;
private _cellBindBuffer!: GPUBuffer;
@ -81,11 +86,10 @@ export class FullFileRenderStrategy extends ViewEventHandler implements IGpuRend
this._context.addEventHandler(this);
// TODO: Detect when lines have been tokenized and clear _upToDateLines
const fontFamily = this._context.configuration.options.get(EditorOption.fontFamily);
const fontSize = this._context.configuration.options.get(EditorOption.fontSize);
this._glyphRasterizer = this._register(new GlyphRasterizer(fontSize, fontFamily));
this._glyphRasterizer = this._register(new MandatoryMutableDisposable(new GlyphRasterizer(fontSize, fontFamily)));
const bufferSize = this._viewGpuContext.maxGpuLines * this._viewGpuContext.maxGpuCols * Constants.IndicesPerCell * Float32Array.BYTES_PER_ELEMENT;
this._cellBindBuffer = this._register(GPULifecycle.createBuffer(this._device, {
@ -112,6 +116,17 @@ export class FullFileRenderStrategy extends ViewEventHandler implements IGpuRend
public override onConfigurationChanged(e: ViewConfigurationChangedEvent): boolean {
this._upToDateLines[0].clear();
this._upToDateLines[1].clear();
this._queueBufferUpdate(e);
const fontFamily = this._context.configuration.options.get(EditorOption.fontFamily);
const fontSize = this._context.configuration.options.get(EditorOption.fontSize);
if (
this._glyphRasterizer.value.fontFamily !== fontFamily ||
this._glyphRasterizer.value.fontSize !== fontSize
) {
this._glyphRasterizer.value = new GlyphRasterizer(fontSize, fontFamily);
}
return true;
}
@ -245,6 +260,15 @@ export class FullFileRenderStrategy extends ViewEventHandler implements IGpuRend
const e = queuedBufferUpdates.shift()!;
switch (e.type) {
case ViewEventType.ViewConfigurationChanged: {
// TODO: Refine the cases for when we throw away all the data
cellBuffer.fill(0);
dirtyLineStart = 1;
dirtyLineEnd = this._finalRenderedLine;
this._finalRenderedLine = 0;
break;
}
case ViewEventType.ViewLinesDeleted: {
// Shift content below deleted line up
const deletedLineContentStartIndex = (e.fromLineNumber - 1) * this._viewGpuContext.maxGpuCols * Constants.IndicesPerCell;
@ -324,7 +348,7 @@ export class FullFileRenderStrategy extends ViewEventHandler implements IGpuRend
continue;
}
glyph = this._viewGpuContext.atlas.getGlyph(this._glyphRasterizer, chars, tokenMetadata);
glyph = this._viewGpuContext.atlas.getGlyph(this._glyphRasterizer.value, chars, tokenMetadata);
// TODO: Support non-standard character widths
absoluteOffsetX = Math.round((x + xOffset) * viewLineOptions.spaceWidth * dpr);

Просмотреть файл

@ -18,7 +18,7 @@ export class GlyphRasterizer extends Disposable implements IGlyphRasterizer {
@memoize
public get cacheKey(): string {
return `${this._fontFamily}_${this._fontSize}px`;
return `${this.fontFamily}_${this.fontSize}px`;
}
private _canvas: OffscreenCanvas;
@ -40,12 +40,12 @@ export class GlyphRasterizer extends Disposable implements IGlyphRasterizer {
private _workGlyphConfig: { chars: string | undefined; metadata: number } = { chars: undefined, metadata: 0 };
constructor(
private readonly _fontSize: number,
private readonly _fontFamily: string,
readonly fontSize: number,
readonly fontFamily: string,
) {
super();
const devicePixelFontSize = Math.ceil(this._fontSize * getActiveWindow().devicePixelRatio);
const devicePixelFontSize = Math.ceil(this.fontSize * getActiveWindow().devicePixelRatio);
this._canvas = new OffscreenCanvas(devicePixelFontSize * 3, devicePixelFontSize * 3);
this._ctx = ensureNonNullable(this._canvas.getContext('2d', {
willReadFrequently: true
@ -87,7 +87,7 @@ export class GlyphRasterizer extends Disposable implements IGlyphRasterizer {
metadata: number,
colorMap: string[],
): Readonly<IRasterizedGlyph> {
const devicePixelFontSize = Math.ceil(this._fontSize * getActiveWindow().devicePixelRatio);
const devicePixelFontSize = Math.ceil(this.fontSize * getActiveWindow().devicePixelRatio);
const canvasDim = devicePixelFontSize * 3;
if (this._canvas.width !== canvasDim) {
this._canvas.width = canvasDim;
@ -105,7 +105,7 @@ export class GlyphRasterizer extends Disposable implements IGlyphRasterizer {
if (fontStyle & FontStyle.Bold) {
fontSb.appendString('bold ');
}
fontSb.appendString(`${devicePixelFontSize}px ${this._fontFamily}`);
fontSb.appendString(`${devicePixelFontSize}px ${this.fontFamily}`);
this._ctx.font = fontSb.build();
// TODO: Support FontStyle.Strikethrough and FontStyle.Underline text decorations, these

Просмотреть файл

@ -106,7 +106,6 @@ export class ViewGpuContext extends Disposable {
this.device.then(device => {
if (!ViewGpuContext._atlas) {
ViewGpuContext._atlas = this._instantiationService.createInstance(TextureAtlas, device.limits.maxTextureDimension2D, undefined);
runOnChange(this.devicePixelRatio, () => ViewGpuContext.atlas.clear());
}
});
@ -117,6 +116,7 @@ export class ViewGpuContext extends Disposable {
dprObs.set(getActiveWindow().devicePixelRatio, undefined);
}));
this.devicePixelRatio = dprObs;
this._register(runOnChange(this.devicePixelRatio, () => ViewGpuContext.atlas?.clear()));
const canvasDevicePixelDimensions = observableValue(this, { width: this.canvas.domNode.width, height: this.canvas.domNode.height });
this._register(observeDevicePixelDimensions(