diff --git a/src/vs/editor/browser/gpu/objectCollectionBuffer.ts b/src/vs/editor/browser/gpu/objectCollectionBuffer.ts index afad65089954b9..8a8bf6bfb52c16 100644 --- a/src/vs/editor/browser/gpu/objectCollectionBuffer.ts +++ b/src/vs/editor/browser/gpu/objectCollectionBuffer.ts @@ -42,6 +42,11 @@ export interface IObjectCollectionBuffer; + /** + * Fires when the buffer is recreated. + */ + readonly onDidChangeBuffer: Event; + /** * Creates an entry in the collection. This will return a managed object that can be modified * which will update the underlying buffer. @@ -87,6 +92,8 @@ class ObjectCollectionBuffer ext private readonly _onDidChange = this._register(new Emitter()); readonly onDidChange = this._onDidChange.event; + private readonly _onDidChangeBuffer = this._register(new Emitter()); + readonly onDidChangeBuffer = this._onDidChangeBuffer.event; constructor( public propertySpecs: T, @@ -109,7 +116,8 @@ class ObjectCollectionBuffer ext createEntry(data: ObjectCollectionPropertyValues): IObjectCollectionBufferEntry { 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); @@ -133,6 +141,15 @@ class ObjectCollectionBuffer 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 extends Disposable implements IObjectCollectionBufferEntry { diff --git a/src/vs/editor/browser/gpu/rectangleRenderer.ts b/src/vs/editor/browser/gpu/rectangleRenderer.ts index 9670802425f6ba..38c751c38b3092 100644 --- a/src/vs/editor/browser/gpu/rectangleRenderer.ts +++ b/src/vs/editor/browser/gpu/rectangleRenderer.ts @@ -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'; @@ -34,7 +36,7 @@ export class RectangleRenderer extends ViewEventHandler { private _pipeline!: GPURenderPipeline; private _vertexBuffer!: GPUBuffer; - private _shapeBindBuffer!: GPUBuffer; + private readonly _shapeBindBuffer: MutableDisposable> = this._register(new MutableDisposable()); private _scrollOffsetBindBuffer!: GPUBuffer; private _scrollOffsetValueBuffer!: Float32Array; @@ -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 @@ -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 { - // TODO: Expand buffer if needed return this._shapeCollection.createEntry({ x, y, width, height, red, green, blue, alpha }); } @@ -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) {