Skip to content

Commit

Permalink
Expand object collection buffer when capacity hit
Browse files Browse the repository at this point in the history
Fixes #228834
  • Loading branch information
Tyriar committed Sep 17, 2024
1 parent 1740abb commit 173878d
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 15 deletions.
19 changes: 18 additions & 1 deletion src/vs/editor/browser/gpu/objectCollectionBuffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ export interface IObjectCollectionBuffer<T extends ObjectCollectionBufferPropert
*/
readonly onDidChange: Event<void>;

/**
* Fires when the buffer is recreated.
*/
readonly onDidChangeBuffer: Event<void>;

/**
* Creates an entry in the collection. This will return a managed object that can be modified
* which will update the underlying buffer.
Expand Down Expand Up @@ -87,6 +92,8 @@ class ObjectCollectionBuffer<T extends ObjectCollectionBufferPropertySpec[]> ext

private readonly _onDidChange = this._register(new Emitter<void>());
readonly onDidChange = this._onDidChange.event;
private readonly _onDidChangeBuffer = this._register(new Emitter<void>());
readonly onDidChangeBuffer = this._onDidChangeBuffer.event;

constructor(
public propertySpecs: T,
Expand All @@ -109,7 +116,8 @@ class ObjectCollectionBuffer<T extends ObjectCollectionBufferPropertySpec[]> ext

createEntry(data: ObjectCollectionPropertyValues<T>): IObjectCollectionBufferEntry<T> {
if (this._entries.size === this.capacity) {
throw new Error(`Cannot create more entries ObjectCollectionBuffer entries (capacity=${this.capacity})`);
this._expandBuffer();
this._onDidChangeBuffer.fire();
}

const value = new ObjectCollectionBufferEntry(this.view, this._propertySpecsMap, this._entries.size, data);
Expand All @@ -133,6 +141,15 @@ class ObjectCollectionBuffer<T extends ObjectCollectionBufferPropertySpec[]> ext
}));
return value;
}

private _expandBuffer() {
console.log('expand', this.capacity, this.capacity * 2);
this.capacity *= 2;
const newView = new Float32Array(this.capacity * this._entrySize);
newView.set(this.view);
this.view = newView;
this.buffer = this.view.buffer;
}
}

class ObjectCollectionBufferEntry<T extends ObjectCollectionBufferPropertySpec[]> extends Disposable implements IObjectCollectionBufferEntry<T> {
Expand Down
42 changes: 28 additions & 14 deletions src/vs/editor/browser/gpu/rectangleRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
*--------------------------------------------------------------------------------------------*/

import { getActiveWindow } from '../../../base/browser/dom.js';
import { Event } from '../../../base/common/event.js';
import { IReference, MutableDisposable } from '../../../base/common/lifecycle.js';
import { EditorOption } from '../../common/config/editorOptions.js';
import { ViewEventHandler } from '../../common/viewEventHandler.js';
import type { ViewScrollChangedEvent } from '../../common/viewEvents.js';
Expand Down Expand Up @@ -34,7 +36,7 @@ export class RectangleRenderer extends ViewEventHandler {
private _pipeline!: GPURenderPipeline;

private _vertexBuffer!: GPUBuffer;
private _shapeBindBuffer!: GPUBuffer;
private readonly _shapeBindBuffer: MutableDisposable<IReference<GPUBuffer>> = this._register(new MutableDisposable());

private _scrollOffsetBindBuffer!: GPUBuffer;
private _scrollOffsetValueBuffer!: Float32Array;
Expand Down Expand Up @@ -141,11 +143,20 @@ export class RectangleRenderer extends ViewEventHandler {

// #region Storage buffers

this._shapeBindBuffer = this._register(GPULifecycle.createBuffer(this._device, {
label: 'Monaco rectangle renderer shape buffer',
size: this._shapeCollection.buffer.byteLength,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
})).object;
const createShapeBindBuffer = () => {
return GPULifecycle.createBuffer(this._device, {
label: 'Monaco rectangle renderer shape buffer',
size: this._shapeCollection.buffer.byteLength,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
});
};
this._shapeBindBuffer.value = createShapeBindBuffer();
this._register(Event.runAndSubscribe(this._shapeCollection.onDidChangeBuffer, () => {
this._shapeBindBuffer.value = createShapeBindBuffer();
if (this._pipeline) {
this._updateBindGroup(this._pipeline, layoutInfoUniformBuffer);
}
}));

// #endregion Storage buffers

Expand Down Expand Up @@ -208,23 +219,26 @@ export class RectangleRenderer extends ViewEventHandler {

// #region Bind group

this._updateBindGroup(this._pipeline, layoutInfoUniformBuffer);

// endregion Bind group

this._initialized = true;
}

private _updateBindGroup(pipeline: GPURenderPipeline, layoutInfoUniformBuffer: GPUBuffer) {
this._bindGroup = this._device.createBindGroup({
label: 'Monaco rectangle renderer bind group',
layout: this._pipeline.getBindGroupLayout(0),
layout: pipeline.getBindGroupLayout(0),
entries: [
{ binding: RectangleRendererBindingId.Shapes, resource: { buffer: this._shapeBindBuffer } },
{ binding: RectangleRendererBindingId.Shapes, resource: { buffer: this._shapeBindBuffer.value!.object } },
{ binding: RectangleRendererBindingId.LayoutInfoUniform, resource: { buffer: layoutInfoUniformBuffer } },
{ binding: RectangleRendererBindingId.ScrollOffset, resource: { buffer: this._scrollOffsetBindBuffer } },
],
});

// endregion Bind group

this._initialized = true;
}

register(x: number, y: number, width: number, height: number, red: number, green: number, blue: number, alpha: number): IObjectCollectionBufferEntry<RectangleRendererEntrySpec> {
// TODO: Expand buffer if needed
return this._shapeCollection.createEntry({ x, y, width, height, red, green, blue, alpha });
}

Expand All @@ -239,7 +253,7 @@ export class RectangleRenderer extends ViewEventHandler {

private _update() {
// TODO: Only write dirty range
this._device.queue.writeBuffer(this._shapeBindBuffer, 0, this._shapeCollection.buffer);
this._device.queue.writeBuffer(this._shapeBindBuffer.value!.object, 0, this._shapeCollection.buffer);

// Update scroll offset
if (this._scrollChanged) {
Expand Down

0 comments on commit 173878d

Please sign in to comment.