Skip to content

Commit 9c85622

Browse files
committed
Faster minimap character rendering
1 parent 8c92d30 commit 9c85622

File tree

3 files changed

+94
-118
lines changed

3 files changed

+94
-118
lines changed

scripts/code.bat

+4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ set ELECTRON_ENABLE_LOGGING=1
3434
set ELECTRON_ENABLE_STACK_DUMPING=1
3535

3636
:: Launch Code
37+
38+
:: Use the following to get v8 tracing:
39+
:: %CODE% --js-flags="--trace-hydrogen --trace-phase=Z --trace-deopt --code-comments --hydrogen-track-positions --redirect-code-traces" . %*
40+
3741
%CODE% . %*
3842
popd
3943

src/vs/editor/browser/viewParts/minimap/minimap.ts

+22-21
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ import { ViewContext } from 'vs/editor/common/view/viewContext';
1414
import { IRenderingContext, IRestrictedRenderingContext } from 'vs/editor/common/view/renderingContext';
1515
import { /*createMinimapCharRenderer,*/ createMinimapCharRenderer2 } from 'vs/editor/common/view/runtimeMinimapCharRenderer';
1616
import * as browser from 'vs/base/browser/browser';
17-
import { MinimapColors, MinimapTokensColorTracker, Constants } from 'vs/editor/common/view/minimapCharRenderer';
17+
import { ParsedColor, MinimapColors, MinimapTokensColorTracker, Constants } from 'vs/editor/common/view/minimapCharRenderer';
1818
import * as editorCommon from 'vs/editor/common/editorCommon';
1919
import { CharCode } from 'vs/base/common/charCode';
2020
import { MinimapLineRenderingData } from 'vs/editor/common/viewModel/viewModel';
21+
import { ColorId } from 'vs/editor/common/modes';
2122

2223
// let charRenderer = createMinimapCharRenderer();
23-
let charRenderer2 = createMinimapCharRenderer2();
24+
let charRenderer2 = createMinimapCharRenderer2(); // TODO@minimap
2425

2526
// interface IWidgetData {
2627
// widget: IOverlayWidget;
@@ -177,7 +178,7 @@ export class Minimap extends ViewPart {
177178

178179
public render(ctx: IRestrictedRenderingContext): void {
179180
let pixelRatio = browser.getPixelRatio();
180-
console.log(pixelRatio);
181+
// console.log(pixelRatio);
181182
const WIDTH = pixelRatio * this._minimapWidth;
182183
const HEIGHT = pixelRatio * this._minimapHeight;
183184
this.domNode.width = WIDTH;
@@ -195,7 +196,7 @@ export class Minimap extends ViewPart {
195196
// 8 * 4 * lineLen
196197
// );
197198

198-
let start = performance.now();
199+
// let start = performance.now();
199200
// console.profile();
200201

201202
let ctx2 = this.domNode.getContext('2d');
@@ -206,7 +207,8 @@ export class Minimap extends ViewPart {
206207
let colorTracker = MinimapTokensColorTracker.getInstance();
207208
let colors = colorTracker.getColorMaps();
208209

209-
let background = colors.getBackgroundColor();
210+
let background = colors.getColor(ColorId.DefaultBackground);
211+
// getBackgroundColor();
210212
let backgroundR = background.r;
211213
let backgroundG = background.g;
212214
let backgroundB = background.b;
@@ -222,17 +224,18 @@ export class Minimap extends ViewPart {
222224
}
223225
}
224226

227+
let data: MinimapLineRenderingData[] = [];
225228
for (let lineIndex = 0; lineIndex < lineCount; lineIndex++) {
226-
let data = this._context.model.getMinimapLineRenderingData(lineIndex + 1);
227-
// let length = Math.min(data.content.length, lineLen);
229+
data[lineIndex] = this._context.model.getMinimapLineRenderingData(lineIndex + 1);
230+
}
228231

232+
let start2 = performance.now();
233+
for (let lineIndex = 0; lineIndex < lineCount; lineIndex++) {
229234
let dy = lineIndex * Constants.x2_CHAR_HEIGHT;
230-
231-
Minimap._render2xLine(imageData, colors, dy, this._viewportColumn, data);
232-
233-
234-
// break;
235+
Minimap._x2RenderLine(imageData, background, colors, dy, data[lineIndex]);
235236
}
237+
let end2 = performance.now();
238+
console.log(`INNER LOOP TOOK ${end2 - start2} ms.`);
236239

237240
// console.log(imageData.data);
238241
// ctx2.strokeStyle = '#000';
@@ -242,10 +245,8 @@ export class Minimap extends ViewPart {
242245

243246
// console.profileEnd();
244247

245-
let end = performance.now();
246-
247-
248-
console.log('TOOK ' + (end - start) + 'ms.');
248+
// let end = performance.now();
249+
// console.log('TOOK ' + (end - start) + 'ms.');
249250

250251
// let data = this._context.model.getViewLineRenderingData(null, 1);
251252

@@ -260,11 +261,11 @@ export class Minimap extends ViewPart {
260261
// }
261262
}
262263

263-
private static _render2xLine(target: ImageData, colors: MinimapColors, dy: number, maxColumn: number, lineData: MinimapLineRenderingData) {
264+
private static _x2RenderLine(target: ImageData, backgroundColor: ParsedColor, colors: MinimapColors, dy: number, lineData: MinimapLineRenderingData) {
264265
const content = lineData.content;
265266
const tokens = lineData.tokens;
266267
const tabSize = lineData.tabSize;
267-
const charIndexStop = Math.min(content.length, maxColumn - 1);
268+
const maxDx = target.width - Constants.x2_CHAR_WIDTH;
268269

269270
let dx = 0;
270271
let charIndex = 0;
@@ -274,10 +275,10 @@ export class Minimap extends ViewPart {
274275
const token = tokens[tokenIndex];
275276
const tokenEndIndex = token.endIndex;
276277
const tokenColorId = token.getForeground();
277-
const tokenColor = colors.getMinimapColor(tokenColorId);
278+
const tokenColor = colors.getColor(tokenColorId);
278279

279280
for (; charIndex < tokenEndIndex; charIndex++) {
280-
if (charIndex >= charIndexStop) {
281+
if (dx > maxDx) {
281282
// hit edge of minimap
282283
return;
283284
}
@@ -292,7 +293,7 @@ export class Minimap extends ViewPart {
292293
// No need to render anything since space is invisible
293294
dx += Constants.x2_CHAR_WIDTH;
294295
} else {
295-
charRenderer2.x2RenderChar(target, dx, dy, charCode, tokenColor);
296+
charRenderer2.x2RenderChar(target, dx, dy, charCode, tokenColor, backgroundColor);
296297
dx += Constants.x2_CHAR_WIDTH;
297298
}
298299
}

src/vs/editor/common/view/minimapCharRenderer.ts

+68-97
Original file line numberDiff line numberDiff line change
@@ -20,65 +20,18 @@ export class ParsedColor {
2020
}
2121
}
2222

23-
/**
24-
* Represents a color rendered on top of the background at all possible alpha values.
25-
*/
26-
export class MinimapColor {
27-
28-
/**
29-
* For each 0 <= i <= 255:
30-
* data[3*i + 0] = r
31-
* data[3*i + 1] = g;
32-
* data[3*i + 2] = b;
33-
*/
34-
public readonly data: Uint8ClampedArray;
35-
36-
constructor(data: Uint8ClampedArray) {
37-
this.data = data;
38-
}
39-
}
40-
4123
export class MinimapColors {
4224

43-
private readonly _backgroundColor: ParsedColor;
44-
private readonly _colors: MinimapColor[];
25+
private readonly _colors: ParsedColor[];
4526

4627
constructor(colorMap: string[]) {
47-
this._backgroundColor = MinimapColors._parseColor(colorMap[ColorId.DefaultBackground]);
48-
let backgroundR = this._backgroundColor.r;
49-
let backgroundG = this._backgroundColor.g;
50-
let backgroundB = this._backgroundColor.b;
51-
5228
this._colors = [null];
5329
for (let colorId = 1; colorId < colorMap.length; colorId++) {
54-
let color = MinimapColors._parseColor(colorMap[colorId]);
55-
let colorR = color.r;
56-
let colorG = color.g;
57-
let colorB = color.b;
58-
59-
let result = new Uint8ClampedArray(256 * 3), resultOffset = 0;
60-
for (let alpha = 0; alpha <= 255; alpha++) {
61-
let fAlpha = alpha / 255;
62-
let fAlphaInverse = (255 - alpha) / 255;
63-
64-
let r = (colorR * fAlpha) + (backgroundR * fAlphaInverse);
65-
let g = (colorG * fAlpha) + (backgroundG * fAlphaInverse);
66-
let b = (colorB * fAlpha) + (backgroundB * fAlphaInverse);
67-
68-
result[resultOffset++] = r;
69-
result[resultOffset++] = g;
70-
result[resultOffset++] = b;
71-
}
72-
73-
this._colors[colorId] = new MinimapColor(result);
30+
this._colors[colorId] = MinimapColors._parseColor(colorMap[colorId]);
7431
}
7532
}
7633

77-
public getBackgroundColor(): ParsedColor {
78-
return this._backgroundColor;
79-
}
80-
81-
public getMinimapColor(colorId: ColorId): MinimapColor {
34+
public getColor(colorId: ColorId): ParsedColor {
8235
if (colorId < 1 || colorId >= this._colors.length) {
8336
// background color (basically invisible)
8437
colorId = 2;
@@ -243,59 +196,77 @@ export class MinimapCharRenderer2 {
243196
return chCode - Constants.START_CH_CODE;
244197
}
245198

246-
public x2RenderChar(target: ImageData, dx: number, dy: number, chCode: number, _color: MinimapColor): void {
199+
public x2RenderChar(target: ImageData, dx: number, dy: number, chCode: number, color: ParsedColor, backgroundColor: ParsedColor): void {
247200
const x2CharData = this.x2charData;
248201
const chIndex = MinimapCharRenderer2._getChIndex(chCode);
249-
const sourceOffset = chIndex * Constants.x2_CHAR_HEIGHT * Constants.x2_CHAR_WIDTH;
250-
const c1 = x2CharData[sourceOffset];
251-
const c2 = x2CharData[sourceOffset + 1];
252-
const c3 = x2CharData[sourceOffset + 2];
253-
const c4 = x2CharData[sourceOffset + 3];
254-
const c5 = x2CharData[sourceOffset + 4];
255-
const c6 = x2CharData[sourceOffset + 5];
256-
const c7 = x2CharData[sourceOffset + 6];
257-
const c8 = x2CharData[sourceOffset + 7];
258202

259203
const outWidth = target.width * Constants.RGBA_CHANNELS_CNT;
260-
let resultOffset = dy * outWidth + dx * Constants.RGBA_CHANNELS_CNT;
204+
205+
const backgroundR = backgroundColor.r;
206+
const backgroundG = backgroundColor.g;
207+
const backgroundB = backgroundColor.b;
208+
209+
const deltaR = color.r - backgroundR;
210+
const deltaG = color.g - backgroundG;
211+
const deltaB = color.b - backgroundB;
261212

262213
const dest = target.data;
263-
const color = _color.data;
264-
dest[resultOffset + 0] = color[3 * c1 + 0];
265-
dest[resultOffset + 1] = color[3 * c1 + 1];
266-
dest[resultOffset + 2] = color[3 * c1 + 2];
267-
dest[resultOffset + 3] = 255;
268-
dest[resultOffset + 4] = color[3 * c2 + 0];
269-
dest[resultOffset + 5] = color[3 * c2 + 1];
270-
dest[resultOffset + 6] = color[3 * c2 + 2];
271-
dest[resultOffset + 7] = 255;
272-
resultOffset += outWidth;
273-
dest[resultOffset + 0] = color[3 * c3 + 0];
274-
dest[resultOffset + 1] = color[3 * c3 + 1];
275-
dest[resultOffset + 2] = color[3 * c3 + 2];
276-
dest[resultOffset + 3] = 255;
277-
dest[resultOffset + 4] = color[3 * c4 + 0];
278-
dest[resultOffset + 5] = color[3 * c4 + 1];
279-
dest[resultOffset + 6] = color[3 * c4 + 2];
280-
dest[resultOffset + 7] = 255;
281-
resultOffset += outWidth;
282-
dest[resultOffset + 0] = color[3 * c5 + 0];
283-
dest[resultOffset + 1] = color[3 * c5 + 1];
284-
dest[resultOffset + 2] = color[3 * c5 + 2];
285-
dest[resultOffset + 3] = 255;
286-
dest[resultOffset + 4] = color[3 * c6 + 0];
287-
dest[resultOffset + 5] = color[3 * c6 + 1];
288-
dest[resultOffset + 6] = color[3 * c6 + 2];
289-
dest[resultOffset + 7] = 255;
290-
resultOffset += outWidth;
291-
dest[resultOffset + 0] = color[3 * c7 + 0];
292-
dest[resultOffset + 1] = color[3 * c7 + 1];
293-
dest[resultOffset + 2] = color[3 * c7 + 2];
294-
dest[resultOffset + 3] = 255;
295-
dest[resultOffset + 4] = color[3 * c8 + 0];
296-
dest[resultOffset + 5] = color[3 * c8 + 1];
297-
dest[resultOffset + 6] = color[3 * c8 + 2];
298-
dest[resultOffset + 7] = 255;
214+
const sourceOffset = chIndex * Constants.x2_CHAR_HEIGHT * Constants.x2_CHAR_WIDTH;
215+
let destOffset = dy * outWidth + dx * Constants.RGBA_CHANNELS_CNT;
216+
{
217+
const c = x2CharData[sourceOffset] / 255;
218+
dest[destOffset + 0] = backgroundR + deltaR * c;
219+
dest[destOffset + 1] = backgroundG + deltaG * c;
220+
dest[destOffset + 2] = backgroundB + deltaB * c;
221+
}
222+
{
223+
const c = x2CharData[sourceOffset + 1] / 255;
224+
dest[destOffset + 4] = backgroundR + deltaR * c;
225+
dest[destOffset + 5] = backgroundG + deltaG * c;
226+
dest[destOffset + 6] = backgroundB + deltaB * c;
227+
}
228+
229+
destOffset += outWidth;
230+
{
231+
const c = x2CharData[sourceOffset + 2] / 255;
232+
dest[destOffset + 0] = backgroundR + deltaR * c;
233+
dest[destOffset + 1] = backgroundG + deltaG * c;
234+
dest[destOffset + 2] = backgroundB + deltaB * c;
235+
}
236+
{
237+
const c = x2CharData[sourceOffset + 3] / 255;
238+
dest[destOffset + 4] = backgroundR + deltaR * c;
239+
dest[destOffset + 5] = backgroundG + deltaG * c;
240+
dest[destOffset + 6] = backgroundB + deltaB * c;
241+
}
242+
243+
destOffset += outWidth;
244+
{
245+
const c = x2CharData[sourceOffset + 4] / 255;
246+
dest[destOffset + 0] = backgroundR + deltaR * c;
247+
dest[destOffset + 1] = backgroundG + deltaG * c;
248+
dest[destOffset + 2] = backgroundB + deltaB * c;
249+
}
250+
{
251+
const c = x2CharData[sourceOffset + 5] / 255;
252+
dest[destOffset + 4] = backgroundR + deltaR * c;
253+
dest[destOffset + 5] = backgroundG + deltaG * c;
254+
dest[destOffset + 6] = backgroundB + deltaB * c;
255+
}
256+
257+
destOffset += outWidth;
258+
{
259+
const c = x2CharData[sourceOffset + 6] / 255;
260+
dest[destOffset + 0] = backgroundR + deltaR * c;
261+
dest[destOffset + 1] = backgroundG + deltaG * c;
262+
dest[destOffset + 2] = backgroundB + deltaB * c;
263+
}
264+
{
265+
const c = x2CharData[sourceOffset + 7] / 255;
266+
dest[destOffset + 4] = backgroundR + deltaR * c;
267+
dest[destOffset + 5] = backgroundG + deltaG * c;
268+
dest[destOffset + 6] = backgroundB + deltaB * c;
269+
}
299270
}
300271

301272
public x1RenderChar(target: ImageData, dx: number, dy: number, chCode: number): void {

0 commit comments

Comments
 (0)