Skip to content

Commit

Permalink
Merge pull request #233769 from microsoft/tyriar/233768
Browse files Browse the repository at this point in the history
Get DOM-based selections working on gpu lines
  • Loading branch information
Tyriar authored Nov 13, 2024
2 parents 2206a8f + 601f45a commit cd0bd66
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 29 deletions.
31 changes: 17 additions & 14 deletions src/vs/editor/browser/gpu/rectangleRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ 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';
import type { ViewCursorStateChangedEvent, ViewScrollChangedEvent } from '../../common/viewEvents.js';
import type { ViewportData } from '../../common/viewLayout/viewLinesViewportData.js';
import type { ViewContext } from '../../common/viewModel/viewContext.js';
import { GPULifecycle } from './gpuDisposable.js';
Expand Down Expand Up @@ -42,7 +42,6 @@ export class RectangleRenderer extends ViewEventHandler {
private _scrollOffsetValueBuffer!: Float32Array;

private _initialized: boolean = false;
private _scrollChanged: boolean = true;

private readonly _shapeCollection: IObjectCollectionBuffer<RectangleRendererEntrySpec> = this._register(createObjectCollectionBuffer([
{ name: 'x' },
Expand Down Expand Up @@ -242,29 +241,33 @@ export class RectangleRenderer extends ViewEventHandler {
return this._shapeCollection.createEntry({ x, y, width, height, red, green, blue, alpha });
}

// --- begin event handlers
// #region Event handlers

public override onScrollChanged(e: ViewScrollChangedEvent): boolean {
this._scrollChanged = true;
return super.onScrollChanged(e);
return true;
}

// --- end event handlers
public override onCursorStateChanged(e: ViewCursorStateChangedEvent): boolean {
if (this._device) {
const dpr = getActiveWindow().devicePixelRatio;
this._scrollOffsetValueBuffer[0] = this._context.viewLayout.getCurrentScrollLeft() * dpr;
this._scrollOffsetValueBuffer[1] = this._context.viewLayout.getCurrentScrollTop() * dpr;
this._device.queue.writeBuffer(this._scrollOffsetBindBuffer, 0, this._scrollOffsetValueBuffer);
}
return true;
}

// #endregion

private _update() {
if (!this._device) {
return;
}
const shapes = this._shapeCollection;
if (shapes.dirtyTracker.isDirty) {
this._device.queue.writeBuffer(this._shapeBindBuffer.value!.object, 0, shapes.buffer, shapes.dirtyTracker.dataOffset, shapes.dirtyTracker.dirtySize! * shapes.view.BYTES_PER_ELEMENT);
shapes.dirtyTracker.clear();
}

// Update scroll offset
if (this._scrollChanged) {
const dpr = getActiveWindow().devicePixelRatio;
this._scrollOffsetValueBuffer[0] = this._context.viewLayout.getCurrentScrollLeft() * dpr;
this._scrollOffsetValueBuffer[1] = this._context.viewLayout.getCurrentScrollTop() * dpr;
this._device.queue.writeBuffer(this._scrollOffsetBindBuffer, 0, this._scrollOffsetValueBuffer);
}
}

draw(viewportData: ViewportData) {
Expand Down
17 changes: 16 additions & 1 deletion src/vs/editor/browser/view/renderingContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,22 @@ export class RenderingContext extends RestrictedRenderingContext {
}

public linesVisibleRangesForRange(range: Range, includeNewLines: boolean): LineVisibleRanges[] | null {
return this._viewLines.linesVisibleRangesForRange(range, includeNewLines) ?? this._viewLinesGpu?.linesVisibleRangesForRange(range, includeNewLines) ?? null;
const domRanges = this._viewLines.linesVisibleRangesForRange(range, includeNewLines);
if (!this._viewLinesGpu) {
return domRanges ?? null;
}
const gpuRanges = this._viewLinesGpu.linesVisibleRangesForRange(range, includeNewLines);
if (!domRanges && !gpuRanges) {
return null;
}
const ranges = [];
if (domRanges) {
ranges.push(...domRanges);
}
if (gpuRanges) {
ranges.push(...gpuRanges);
}
return ranges;
}

public visibleRangeForPosition(position: Position): HorizontalPosition | null {
Expand Down
98 changes: 84 additions & 14 deletions src/vs/editor/browser/viewParts/viewLinesGpu/viewLinesGpu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import { autorun } from '../../../../base/common/observable.js';
import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';
import { ILogService } from '../../../../platform/log/common/log.js';
import { EditorOption } from '../../../common/config/editorOptions.js';
import type { Position } from '../../../common/core/position.js';
import type { Range } from '../../../common/core/range.js';
import type { ViewLinesChangedEvent, ViewLinesDeletedEvent, ViewScrollChangedEvent } from '../../../common/viewEvents.js';
import { Position } from '../../../common/core/position.js';
import { Range } from '../../../common/core/range.js';
import type { ViewConfigurationChangedEvent, ViewCursorStateChangedEvent, ViewLinesChangedEvent, ViewLinesDeletedEvent, ViewScrollChangedEvent } from '../../../common/viewEvents.js';
import type { ViewportData } from '../../../common/viewLayout/viewLinesViewportData.js';
import type { ViewContext } from '../../../common/viewModel/viewContext.js';
import { TextureAtlasPage } from '../../gpu/atlas/textureAtlasPage.js';
Expand All @@ -20,7 +20,7 @@ import { BindingId, type IGpuRenderStrategy } from '../../gpu/gpu.js';
import { GPULifecycle } from '../../gpu/gpuDisposable.js';
import { observeDevicePixelDimensions, quadVertices } from '../../gpu/gpuUtils.js';
import { ViewGpuContext } from '../../gpu/viewGpuContext.js';
import { FloatHorizontalRange, HorizontalPosition, IViewLines, LineVisibleRanges, RenderingContext, RestrictedRenderingContext, VisibleRanges } from '../../view/renderingContext.js';
import { FloatHorizontalRange, HorizontalPosition, HorizontalRange, IViewLines, LineVisibleRanges, RenderingContext, RestrictedRenderingContext, VisibleRanges } from '../../view/renderingContext.js';
import { ViewPart } from '../../view/viewPart.js';
import { ViewLineOptions } from '../viewLines/viewLineOptions.js';

Expand Down Expand Up @@ -368,6 +368,16 @@ export class ViewLinesGpu extends ViewPart implements IViewLines {
throw new BugIndicatingError('Should not be called');
}

// #region Event handlers

// Since ViewLinesGpu currently coordinates rendering to the canvas, it must listen to all
// changed events that any GPU part listens to. This is because any drawing to the canvas will
// clear it for that frame, so all parts must be rendered every time.

override onConfigurationChanged(e: ViewConfigurationChangedEvent): boolean {
return true;
}

override onLinesChanged(e: ViewLinesChangedEvent): boolean {
return true;
}
Expand All @@ -381,7 +391,11 @@ export class ViewLinesGpu extends ViewPart implements IViewLines {
return true;
}

// subscribe to more events
override onCursorStateChanged(e: ViewCursorStateChangedEvent): boolean {
return true;
}

// #endregion

public renderText(viewportData: ViewportData): void {
if (this._initialized) {
Expand Down Expand Up @@ -427,8 +441,65 @@ export class ViewLinesGpu extends ViewPart implements IViewLines {
this._lastViewLineOptions = options;
}

linesVisibleRangesForRange(range: Range, includeNewLines: boolean): LineVisibleRanges[] | null {
return null;
linesVisibleRangesForRange(_range: Range, includeNewLines: boolean): LineVisibleRanges[] | null {
if (!this._lastViewportData) {
return null;
}
const originalEndLineNumber = _range.endLineNumber;
const range = Range.intersectRanges(_range, this._lastViewportData.visibleRange);
if (!range) {
return null;
}

const rendStartLineNumber = this._lastViewportData.startLineNumber;
const rendEndLineNumber = this._lastViewportData.endLineNumber;

const viewportData = this._lastViewportData;
const viewLineOptions = this._lastViewLineOptions;

if (!viewportData || !viewLineOptions) {
return null;
}

const visibleRanges: LineVisibleRanges[] = [];

let nextLineModelLineNumber: number = 0;
if (includeNewLines) {
nextLineModelLineNumber = this._context.viewModel.coordinatesConverter.convertViewPositionToModelPosition(new Position(range.startLineNumber, 1)).lineNumber;
}

for (let lineNumber = range.startLineNumber; lineNumber <= range.endLineNumber; lineNumber++) {

if (lineNumber < rendStartLineNumber || lineNumber > rendEndLineNumber) {
continue;
}
const startColumn = lineNumber === range.startLineNumber ? range.startColumn : 1;
const continuesInNextLine = lineNumber !== range.endLineNumber;
const endColumn = continuesInNextLine ? this._context.viewModel.getLineMaxColumn(lineNumber) : range.endColumn;

const visibleRangesForLine = this._visibleRangesForLineRange(lineNumber, startColumn, endColumn);

if (!visibleRangesForLine) {
continue;
}

if (includeNewLines && lineNumber < originalEndLineNumber) {
const currentLineModelLineNumber = nextLineModelLineNumber;
nextLineModelLineNumber = this._context.viewModel.coordinatesConverter.convertViewPositionToModelPosition(new Position(lineNumber + 1, 1)).lineNumber;

if (currentLineModelLineNumber !== nextLineModelLineNumber) {
visibleRangesForLine.ranges[visibleRangesForLine.ranges.length - 1].width += viewLineOptions.spaceWidth;
}
}

visibleRanges.push(new LineVisibleRanges(visibleRangesForLine.outsideRenderedLine, lineNumber, HorizontalRange.from(visibleRangesForLine.ranges), continuesInNextLine));
}

if (visibleRanges.length === 0) {
return null;
}

return visibleRanges;
}

private _visibleRangesForLineRange(lineNumber: number, startColumn: number, endColumn: number): VisibleRanges | null {
Expand All @@ -448,20 +519,19 @@ export class ViewLinesGpu extends ViewPart implements IViewLines {
// Resolve tab widths for this line
const lineData = viewportData.getViewLineRenderingData(lineNumber);
const content = lineData.content;
let startColumnResolvedTabWidth = 0;
let endColumnResolvedTabWidth = 0;
let resolvedStartColumnLeft = 0;
for (let x = 0; x < startColumn - 1; x++) {
startColumnResolvedTabWidth += content[x] === '\t' ? lineData.tabSize : 1;
resolvedStartColumnLeft += content[x] === '\t' ? lineData.tabSize : 1;
}
endColumnResolvedTabWidth = startColumnResolvedTabWidth;
let resolvedRangeWidth = 0;
for (let x = startColumn - 1; x < endColumn - 1; x++) {
endColumnResolvedTabWidth += content[x] === '\t' ? lineData.tabSize : 1;
resolvedRangeWidth += content[x] === '\t' ? lineData.tabSize : 1;
}

// Visible horizontal range in _scaled_ pixels
const result = new VisibleRanges(false, [new FloatHorizontalRange(
startColumnResolvedTabWidth * viewLineOptions.spaceWidth,
endColumnResolvedTabWidth * viewLineOptions.spaceWidth)
resolvedStartColumnLeft * viewLineOptions.spaceWidth,
resolvedRangeWidth * viewLineOptions.spaceWidth)
]);

return result;
Expand Down

0 comments on commit cd0bd66

Please sign in to comment.