From 9c856228a9030ab8273e1e703e8134435cdcbde1 Mon Sep 17 00:00:00 2001 From: Alex Dima Date: Mon, 13 Feb 2017 17:51:53 +0100 Subject: [PATCH] Faster minimap character rendering --- scripts/code.bat | 4 + .../browser/viewParts/minimap/minimap.ts | 47 ++--- .../editor/common/view/minimapCharRenderer.ts | 165 ++++++++---------- 3 files changed, 96 insertions(+), 120 deletions(-) diff --git a/scripts/code.bat b/scripts/code.bat index 5e7d9660aa1..b35c50b3533 100644 --- a/scripts/code.bat +++ b/scripts/code.bat @@ -34,6 +34,10 @@ set ELECTRON_ENABLE_LOGGING=1 set ELECTRON_ENABLE_STACK_DUMPING=1 :: Launch Code + +:: Use the following to get v8 tracing: +:: %CODE% --js-flags="--trace-hydrogen --trace-phase=Z --trace-deopt --code-comments --hydrogen-track-positions --redirect-code-traces" . %* + %CODE% . %* popd diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index 42c675bc765..700e4c117b0 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -14,13 +14,14 @@ import { ViewContext } from 'vs/editor/common/view/viewContext'; import { IRenderingContext, IRestrictedRenderingContext } from 'vs/editor/common/view/renderingContext'; import { /*createMinimapCharRenderer,*/ createMinimapCharRenderer2 } from 'vs/editor/common/view/runtimeMinimapCharRenderer'; import * as browser from 'vs/base/browser/browser'; -import { MinimapColors, MinimapTokensColorTracker, Constants } from 'vs/editor/common/view/minimapCharRenderer'; +import { ParsedColor, MinimapColors, MinimapTokensColorTracker, Constants } from 'vs/editor/common/view/minimapCharRenderer'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { CharCode } from 'vs/base/common/charCode'; import { MinimapLineRenderingData } from 'vs/editor/common/viewModel/viewModel'; +import { ColorId } from 'vs/editor/common/modes'; // let charRenderer = createMinimapCharRenderer(); -let charRenderer2 = createMinimapCharRenderer2(); +let charRenderer2 = createMinimapCharRenderer2(); // TODO@minimap // interface IWidgetData { // widget: IOverlayWidget; @@ -177,7 +178,7 @@ export class Minimap extends ViewPart { public render(ctx: IRestrictedRenderingContext): void { let pixelRatio = browser.getPixelRatio(); - console.log(pixelRatio); + // console.log(pixelRatio); const WIDTH = pixelRatio * this._minimapWidth; const HEIGHT = pixelRatio * this._minimapHeight; this.domNode.width = WIDTH; @@ -195,7 +196,7 @@ export class Minimap extends ViewPart { // 8 * 4 * lineLen // ); - let start = performance.now(); + // let start = performance.now(); // console.profile(); let ctx2 = this.domNode.getContext('2d'); @@ -206,7 +207,8 @@ export class Minimap extends ViewPart { let colorTracker = MinimapTokensColorTracker.getInstance(); let colors = colorTracker.getColorMaps(); - let background = colors.getBackgroundColor(); + let background = colors.getColor(ColorId.DefaultBackground); + // getBackgroundColor(); let backgroundR = background.r; let backgroundG = background.g; let backgroundB = background.b; @@ -222,18 +224,19 @@ export class Minimap extends ViewPart { } } + let data: MinimapLineRenderingData[] = []; for (let lineIndex = 0; lineIndex < lineCount; lineIndex++) { - let data = this._context.model.getMinimapLineRenderingData(lineIndex + 1); - // let length = Math.min(data.content.length, lineLen); - - let dy = lineIndex * Constants.x2_CHAR_HEIGHT; - - Minimap._render2xLine(imageData, colors, dy, this._viewportColumn, data); - - - // break; + data[lineIndex] = this._context.model.getMinimapLineRenderingData(lineIndex + 1); } + let start2 = performance.now(); + for (let lineIndex = 0; lineIndex < lineCount; lineIndex++) { + let dy = lineIndex * Constants.x2_CHAR_HEIGHT; + Minimap._x2RenderLine(imageData, background, colors, dy, data[lineIndex]); + } + let end2 = performance.now(); + console.log(`INNER LOOP TOOK ${end2 - start2} ms.`); + // console.log(imageData.data); // ctx2.strokeStyle = '#000'; // for (i = 0; i <) @@ -242,10 +245,8 @@ export class Minimap extends ViewPart { // console.profileEnd(); - let end = performance.now(); - - - console.log('TOOK ' + (end - start) + 'ms.'); + // let end = performance.now(); + // console.log('TOOK ' + (end - start) + 'ms.'); // let data = this._context.model.getViewLineRenderingData(null, 1); @@ -260,11 +261,11 @@ export class Minimap extends ViewPart { // } } - private static _render2xLine(target: ImageData, colors: MinimapColors, dy: number, maxColumn: number, lineData: MinimapLineRenderingData) { + private static _x2RenderLine(target: ImageData, backgroundColor: ParsedColor, colors: MinimapColors, dy: number, lineData: MinimapLineRenderingData) { const content = lineData.content; const tokens = lineData.tokens; const tabSize = lineData.tabSize; - const charIndexStop = Math.min(content.length, maxColumn - 1); + const maxDx = target.width - Constants.x2_CHAR_WIDTH; let dx = 0; let charIndex = 0; @@ -274,10 +275,10 @@ export class Minimap extends ViewPart { const token = tokens[tokenIndex]; const tokenEndIndex = token.endIndex; const tokenColorId = token.getForeground(); - const tokenColor = colors.getMinimapColor(tokenColorId); + const tokenColor = colors.getColor(tokenColorId); for (; charIndex < tokenEndIndex; charIndex++) { - if (charIndex >= charIndexStop) { + if (dx > maxDx) { // hit edge of minimap return; } @@ -292,7 +293,7 @@ export class Minimap extends ViewPart { // No need to render anything since space is invisible dx += Constants.x2_CHAR_WIDTH; } else { - charRenderer2.x2RenderChar(target, dx, dy, charCode, tokenColor); + charRenderer2.x2RenderChar(target, dx, dy, charCode, tokenColor, backgroundColor); dx += Constants.x2_CHAR_WIDTH; } } diff --git a/src/vs/editor/common/view/minimapCharRenderer.ts b/src/vs/editor/common/view/minimapCharRenderer.ts index 3b1bd4f0c86..801e5d0b17d 100644 --- a/src/vs/editor/common/view/minimapCharRenderer.ts +++ b/src/vs/editor/common/view/minimapCharRenderer.ts @@ -20,65 +20,18 @@ export class ParsedColor { } } -/** - * Represents a color rendered on top of the background at all possible alpha values. - */ -export class MinimapColor { - - /** - * For each 0 <= i <= 255: - * data[3*i + 0] = r - * data[3*i + 1] = g; - * data[3*i + 2] = b; - */ - public readonly data: Uint8ClampedArray; - - constructor(data: Uint8ClampedArray) { - this.data = data; - } -} - export class MinimapColors { - private readonly _backgroundColor: ParsedColor; - private readonly _colors: MinimapColor[]; + private readonly _colors: ParsedColor[]; constructor(colorMap: string[]) { - this._backgroundColor = MinimapColors._parseColor(colorMap[ColorId.DefaultBackground]); - let backgroundR = this._backgroundColor.r; - let backgroundG = this._backgroundColor.g; - let backgroundB = this._backgroundColor.b; - this._colors = [null]; for (let colorId = 1; colorId < colorMap.length; colorId++) { - let color = MinimapColors._parseColor(colorMap[colorId]); - let colorR = color.r; - let colorG = color.g; - let colorB = color.b; - - let result = new Uint8ClampedArray(256 * 3), resultOffset = 0; - for (let alpha = 0; alpha <= 255; alpha++) { - let fAlpha = alpha / 255; - let fAlphaInverse = (255 - alpha) / 255; - - let r = (colorR * fAlpha) + (backgroundR * fAlphaInverse); - let g = (colorG * fAlpha) + (backgroundG * fAlphaInverse); - let b = (colorB * fAlpha) + (backgroundB * fAlphaInverse); - - result[resultOffset++] = r; - result[resultOffset++] = g; - result[resultOffset++] = b; - } - - this._colors[colorId] = new MinimapColor(result); + this._colors[colorId] = MinimapColors._parseColor(colorMap[colorId]); } } - public getBackgroundColor(): ParsedColor { - return this._backgroundColor; - } - - public getMinimapColor(colorId: ColorId): MinimapColor { + public getColor(colorId: ColorId): ParsedColor { if (colorId < 1 || colorId >= this._colors.length) { // background color (basically invisible) colorId = 2; @@ -243,59 +196,77 @@ export class MinimapCharRenderer2 { return chCode - Constants.START_CH_CODE; } - public x2RenderChar(target: ImageData, dx: number, dy: number, chCode: number, _color: MinimapColor): void { + public x2RenderChar(target: ImageData, dx: number, dy: number, chCode: number, color: ParsedColor, backgroundColor: ParsedColor): void { const x2CharData = this.x2charData; const chIndex = MinimapCharRenderer2._getChIndex(chCode); - const sourceOffset = chIndex * Constants.x2_CHAR_HEIGHT * Constants.x2_CHAR_WIDTH; - const c1 = x2CharData[sourceOffset]; - const c2 = x2CharData[sourceOffset + 1]; - const c3 = x2CharData[sourceOffset + 2]; - const c4 = x2CharData[sourceOffset + 3]; - const c5 = x2CharData[sourceOffset + 4]; - const c6 = x2CharData[sourceOffset + 5]; - const c7 = x2CharData[sourceOffset + 6]; - const c8 = x2CharData[sourceOffset + 7]; const outWidth = target.width * Constants.RGBA_CHANNELS_CNT; - let resultOffset = dy * outWidth + dx * Constants.RGBA_CHANNELS_CNT; + + const backgroundR = backgroundColor.r; + const backgroundG = backgroundColor.g; + const backgroundB = backgroundColor.b; + + const deltaR = color.r - backgroundR; + const deltaG = color.g - backgroundG; + const deltaB = color.b - backgroundB; const dest = target.data; - const color = _color.data; - dest[resultOffset + 0] = color[3 * c1 + 0]; - dest[resultOffset + 1] = color[3 * c1 + 1]; - dest[resultOffset + 2] = color[3 * c1 + 2]; - dest[resultOffset + 3] = 255; - dest[resultOffset + 4] = color[3 * c2 + 0]; - dest[resultOffset + 5] = color[3 * c2 + 1]; - dest[resultOffset + 6] = color[3 * c2 + 2]; - dest[resultOffset + 7] = 255; - resultOffset += outWidth; - dest[resultOffset + 0] = color[3 * c3 + 0]; - dest[resultOffset + 1] = color[3 * c3 + 1]; - dest[resultOffset + 2] = color[3 * c3 + 2]; - dest[resultOffset + 3] = 255; - dest[resultOffset + 4] = color[3 * c4 + 0]; - dest[resultOffset + 5] = color[3 * c4 + 1]; - dest[resultOffset + 6] = color[3 * c4 + 2]; - dest[resultOffset + 7] = 255; - resultOffset += outWidth; - dest[resultOffset + 0] = color[3 * c5 + 0]; - dest[resultOffset + 1] = color[3 * c5 + 1]; - dest[resultOffset + 2] = color[3 * c5 + 2]; - dest[resultOffset + 3] = 255; - dest[resultOffset + 4] = color[3 * c6 + 0]; - dest[resultOffset + 5] = color[3 * c6 + 1]; - dest[resultOffset + 6] = color[3 * c6 + 2]; - dest[resultOffset + 7] = 255; - resultOffset += outWidth; - dest[resultOffset + 0] = color[3 * c7 + 0]; - dest[resultOffset + 1] = color[3 * c7 + 1]; - dest[resultOffset + 2] = color[3 * c7 + 2]; - dest[resultOffset + 3] = 255; - dest[resultOffset + 4] = color[3 * c8 + 0]; - dest[resultOffset + 5] = color[3 * c8 + 1]; - dest[resultOffset + 6] = color[3 * c8 + 2]; - dest[resultOffset + 7] = 255; + const sourceOffset = chIndex * Constants.x2_CHAR_HEIGHT * Constants.x2_CHAR_WIDTH; + let destOffset = dy * outWidth + dx * Constants.RGBA_CHANNELS_CNT; + { + const c = x2CharData[sourceOffset] / 255; + dest[destOffset + 0] = backgroundR + deltaR * c; + dest[destOffset + 1] = backgroundG + deltaG * c; + dest[destOffset + 2] = backgroundB + deltaB * c; + } + { + const c = x2CharData[sourceOffset + 1] / 255; + dest[destOffset + 4] = backgroundR + deltaR * c; + dest[destOffset + 5] = backgroundG + deltaG * c; + dest[destOffset + 6] = backgroundB + deltaB * c; + } + + destOffset += outWidth; + { + const c = x2CharData[sourceOffset + 2] / 255; + dest[destOffset + 0] = backgroundR + deltaR * c; + dest[destOffset + 1] = backgroundG + deltaG * c; + dest[destOffset + 2] = backgroundB + deltaB * c; + } + { + const c = x2CharData[sourceOffset + 3] / 255; + dest[destOffset + 4] = backgroundR + deltaR * c; + dest[destOffset + 5] = backgroundG + deltaG * c; + dest[destOffset + 6] = backgroundB + deltaB * c; + } + + destOffset += outWidth; + { + const c = x2CharData[sourceOffset + 4] / 255; + dest[destOffset + 0] = backgroundR + deltaR * c; + dest[destOffset + 1] = backgroundG + deltaG * c; + dest[destOffset + 2] = backgroundB + deltaB * c; + } + { + const c = x2CharData[sourceOffset + 5] / 255; + dest[destOffset + 4] = backgroundR + deltaR * c; + dest[destOffset + 5] = backgroundG + deltaG * c; + dest[destOffset + 6] = backgroundB + deltaB * c; + } + + destOffset += outWidth; + { + const c = x2CharData[sourceOffset + 6] / 255; + dest[destOffset + 0] = backgroundR + deltaR * c; + dest[destOffset + 1] = backgroundG + deltaG * c; + dest[destOffset + 2] = backgroundB + deltaB * c; + } + { + const c = x2CharData[sourceOffset + 7] / 255; + dest[destOffset + 4] = backgroundR + deltaR * c; + dest[destOffset + 5] = backgroundG + deltaG * c; + dest[destOffset + 6] = backgroundB + deltaB * c; + } } public x1RenderChar(target: ImageData, dx: number, dy: number, chCode: number): void {