Partially implement benchmarking for SVG.

This commit is contained in:
Patrick Walton 2017-12-05 19:04:55 -08:00
parent f5a7032ca5
commit 30893fb9ad
10 changed files with 267 additions and 51 deletions

View File

@ -8,7 +8,9 @@
</head> </head>
<body class="pf-unscrollable"> <body class="pf-unscrollable">
{{>partials/navbar.html isTool=true}} {{>partials/navbar.html isTool=true}}
<canvas id="pf-canvas" class="pf-draggable" width="400" height="300"></canvas> <canvas id="pf-canvas" class="pf-maximized-canvas pf-draggable" width="400"
height="300"></canvas>
<svg id="pf-svg" xmlns="http://www.w3.org/2000/svg" width="400" height="300"></svg>
<div class="modal fade" id="pf-benchmark-modal" tabindex="-1" role="dialog" <div class="modal fade" id="pf-benchmark-modal" tabindex="-1" role="dialog"
aria-labelledby="pf-benchmark-label" aria-hidden="false"> aria-labelledby="pf-benchmark-label" aria-hidden="false">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
@ -21,22 +23,44 @@
</button> </button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form class="form"> <ul class="nav nav-tabs" role="tablist">
<div class="form-group"> <li class="nav-item">
<label for="pf-aa-level-select" <a class="nav-link active" id="pf-benchmark-text-tab"
class="col-form-label mr-sm-2">Antialiasing</label> data-toggle="tab" href="#pf-benchmark-text" role="tab"
<select id="pf-aa-level-select" aria-controls="pf-benchmark-text" aria-selected="true">Text</a>
class="form-control custom-select mr-sm-3"> </li>
<option value="none" selected>None</option> <li class="nav-item">
<option value="ssaa-2">2&times;SSAA</option> <a class="nav-link" id="pf-benchmark-svg-tab" data-toggle="tab"
<option value="ssaa-4">4&times;SSAA</option> href="#pf-benchmark-svg" role="tab"
<option value="xcaa">XCAA</option> aria-controls="pf-benchmark-svg" aria-selected="false">SVG</a>
</select> </li>
</ul>
<div class="tab-content">
<div class="tab-pane show active pt-3" id="pf-benchmark-text"
role="tabpanel" aria-labelledby="pf-benchmark-text-tab">
<form class="form" id="pf-benchmark-text-form">
<div class="form-group" id="pf-aa-level-form-group">
<label for="pf-aa-level-select"
class="col-form-label mr-sm-2">Antialiasing</label>
<select id="pf-aa-level-select"
class="form-control custom-select mr-sm-3">
<option value="none" selected>None</option>
<option value="ssaa-2">2&times;SSAA</option>
<option value="ssaa-4">4&times;SSAA</option>
<option value="xcaa">XCAA</option>
</select>
</div>
<div class="form-group row justify-content-between">
{{>partials/switch.html id="pf-subpixel-aa" title="Subpixel AA"}}
</div>
</form>
</div> </div>
<div class="form-group row justify-content-between"> <div class="tab-pane pt-3" id="pf-benchmark-svg"
{{>partials/switch.html id="pf-subpixel-aa" title="Subpixel AA"}} role="tabpanel" aria-labelledby="pf-benchmark-svg-tab">
<form class="form" id="pf-benchmark-svg-form">
</form>
</div> </div>
</form> </div>
<div class="d-flex justify-content-end"> <div class="d-flex justify-content-end">
<button id="pf-run-benchmark-button" type="button" <button id="pf-run-benchmark-button" type="button"
class="btn btn-primary"> class="btn btn-primary">
@ -67,7 +91,7 @@
<span id="pf-benchmark-results-partitioning-time">0</span> µs/glyph <span id="pf-benchmark-results-partitioning-time">0</span> µs/glyph
</div> </div>
<table class="table table-striped"> <table class="table table-striped">
<thead class="thead-default"> <thead class="thead-default" id="pf-benchmark-results-table-header">
<tr><th>Font size (px)</th><th>GPU time per glyph (µs)</th></tr> <tr><th>Font size (px)</th><th>GPU time per glyph (µs)</th></tr>
</thead> </thead>
<tbody id="pf-benchmark-results-table-body"></tbody> <tbody id="pf-benchmark-results-table-body"></tbody>

View File

@ -21,7 +21,7 @@ import PathfinderBufferTexture from "./buffer-texture";
import {CameraView, PerspectiveCamera} from "./camera"; import {CameraView, PerspectiveCamera} from "./camera";
import {UniformMap} from './gl-utils'; import {UniformMap} from './gl-utils';
import {PathfinderMeshData} from "./meshes"; import {PathfinderMeshData} from "./meshes";
import {PathTransformBuffers, Renderer} from './renderer'; import {BaseRenderer, PathTransformBuffers} from './renderer';
import {ShaderMap, ShaderProgramSource} from "./shader-loader"; import {ShaderMap, ShaderProgramSource} from "./shader-loader";
import SSAAStrategy from "./ssaa-strategy"; import SSAAStrategy from "./ssaa-strategy";
import {BUILTIN_FONT_URI, ExpandedMeshData} from "./text"; import {BUILTIN_FONT_URI, ExpandedMeshData} from "./text";
@ -359,7 +359,7 @@ class ThreeDView extends DemoView implements TextRenderContext {
newTimingsReceived(timings: Timings): void {} newTimingsReceived(timings: Timings): void {}
} }
class ThreeDRenderer extends Renderer { class ThreeDRenderer extends BaseRenderer {
renderContext: ThreeDView; renderContext: ThreeDView;
camera: PerspectiveCamera; camera: PerspectiveCamera;

View File

@ -19,9 +19,11 @@ import PathfinderBufferTexture from './buffer-texture';
import {OrthographicCamera} from './camera'; import {OrthographicCamera} from './camera';
import {UniformMap} from './gl-utils'; import {UniformMap} from './gl-utils';
import {PathfinderMeshData} from "./meshes"; import {PathfinderMeshData} from "./meshes";
import {PathTransformBuffers, Renderer} from './renderer'; import {BaseRenderer, PathTransformBuffers} from './renderer';
import {ShaderMap, ShaderProgramSource} from "./shader-loader"; import {ShaderMap, ShaderProgramSource} from "./shader-loader";
import SSAAStrategy from './ssaa-strategy'; import SSAAStrategy from './ssaa-strategy';
import {BUILTIN_SVG_URI, SVGLoader} from './svg-loader';
import {SVGRenderer} from './svg-renderer';
import {BUILTIN_FONT_URI, ExpandedMeshData, GlyphStore, PathfinderFont, TextFrame} from "./text"; import {BUILTIN_FONT_URI, ExpandedMeshData, GlyphStore, PathfinderFont, TextFrame} from "./text";
import {computeStemDarkeningAmount, TextRun} from "./text"; import {computeStemDarkeningAmount, TextRun} from "./text";
import {assert, lerp, PathfinderError, unwrapNull, unwrapUndef} from "./utils"; import {assert, lerp, PathfinderError, unwrapNull, unwrapUndef} from "./utils";
@ -30,7 +32,8 @@ import {AdaptiveMonochromeXCAAStrategy} from './xcaa-strategy';
const STRING: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; const STRING: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
const FONT: string = 'nimbus-sans'; const DEFAULT_FONT: string = 'nimbus-sans';
const DEFAULT_SVG_FILE: string = 'tiger';
const TEXT_COLOR: number[] = [0, 0, 0, 255]; const TEXT_COLOR: number[] = [0, 0, 0, 255];
@ -47,22 +50,48 @@ const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
xcaa: AdaptiveMonochromeXCAAStrategy, xcaa: AdaptiveMonochromeXCAAStrategy,
}; };
interface BenchmarkModeMap<T> {
text: T;
svg: T;
}
type BenchmarkMode = 'text' | 'svg';
interface AntialiasingStrategyTable { interface AntialiasingStrategyTable {
none: typeof NoAAStrategy; none: typeof NoAAStrategy;
ssaa: typeof SSAAStrategy; ssaa: typeof SSAAStrategy;
xcaa: typeof AdaptiveMonochromeXCAAStrategy; xcaa: typeof AdaptiveMonochromeXCAAStrategy;
} }
const DISPLAY_HEADER_LABELS: BenchmarkModeMap<string[]> = {
svg: ["Size (px)", "GPU time (ms)"],
text: ["Font size (px)", "GPU time per glyph (µs)"],
};
class BenchmarkAppController extends DemoAppController<BenchmarkTestView> { class BenchmarkAppController extends DemoAppController<BenchmarkTestView> {
font: PathfinderFont | null; font: PathfinderFont | null;
textRun: TextRun | null; textRun: TextRun | null;
protected readonly defaultFile: string = FONT; svgLoader: SVGLoader;
protected readonly builtinFileURI: string = BUILTIN_FONT_URI;
mode: BenchmarkMode;
protected get defaultFile(): string {
if (this.mode === 'text')
return DEFAULT_FONT;
return DEFAULT_SVG_FILE;
}
protected get builtinFileURI(): string {
if (this.mode === 'text')
return BUILTIN_FONT_URI;
return BUILTIN_SVG_URI;
}
private optionsModal: HTMLDivElement; private optionsModal: HTMLDivElement;
private resultsModal: HTMLDivElement; private resultsModal: HTMLDivElement;
private resultsTableHeader: HTMLTableSectionElement;
private resultsTableBody: HTMLTableSectionElement; private resultsTableBody: HTMLTableSectionElement;
private resultsPartitioningTimeLabel: HTMLSpanElement; private resultsPartitioningTimeLabel: HTMLSpanElement;
@ -79,11 +108,16 @@ class BenchmarkAppController extends DemoAppController<BenchmarkTestView> {
start(): void { start(): void {
super.start(); super.start();
this.mode = 'text';
this.optionsModal = unwrapNull(document.getElementById('pf-benchmark-modal')) as this.optionsModal = unwrapNull(document.getElementById('pf-benchmark-modal')) as
HTMLDivElement; HTMLDivElement;
this.resultsModal = unwrapNull(document.getElementById('pf-benchmark-results-modal')) as this.resultsModal = unwrapNull(document.getElementById('pf-benchmark-results-modal')) as
HTMLDivElement; HTMLDivElement;
this.resultsTableHeader =
unwrapNull(document.getElementById('pf-benchmark-results-table-header')) as
HTMLTableSectionElement;
this.resultsTableBody = this.resultsTableBody =
unwrapNull(document.getElementById('pf-benchmark-results-table-body')) as unwrapNull(document.getElementById('pf-benchmark-results-table-body')) as
HTMLTableSectionElement; HTMLTableSectionElement;
@ -104,12 +138,56 @@ class BenchmarkAppController extends DemoAppController<BenchmarkTestView> {
const runBenchmarkButton = unwrapNull(document.getElementById('pf-run-benchmark-button')); const runBenchmarkButton = unwrapNull(document.getElementById('pf-run-benchmark-button'));
runBenchmarkButton.addEventListener('click', () => this.runBenchmark(), false); runBenchmarkButton.addEventListener('click', () => this.runBenchmark(), false);
const aaLevelFormGroup = unwrapNull(document.getElementById('pf-aa-level-form-group')) as
HTMLDivElement;
const benchmarkTextForm = unwrapNull(document.getElementById('pf-benchmark-text-form')) as
HTMLFormElement;
const benchmarkSVGForm = unwrapNull(document.getElementById('pf-benchmark-svg-form')) as
HTMLFormElement;
window.jQuery(this.optionsModal).modal(); window.jQuery(this.optionsModal).modal();
const benchmarkTextTab = document.getElementById('pf-benchmark-text-tab') as
HTMLAnchorElement;
const benchmarkSVGTab = document.getElementById('pf-benchmark-svg-tab') as
HTMLAnchorElement;
window.jQuery(benchmarkTextTab).on('shown.bs.tab', event => {
this.mode = 'text';
if (aaLevelFormGroup.parentElement != null)
aaLevelFormGroup.parentElement.removeChild(aaLevelFormGroup);
benchmarkTextForm.insertBefore(aaLevelFormGroup, benchmarkTextForm.firstChild);
this.loadInitialFile(this.builtinFileURI);
});
window.jQuery(benchmarkSVGTab).on('shown.bs.tab', event => {
this.mode = 'svg';
if (aaLevelFormGroup.parentElement != null)
aaLevelFormGroup.parentElement.removeChild(aaLevelFormGroup);
benchmarkSVGForm.insertBefore(aaLevelFormGroup, benchmarkSVGForm.firstChild);
this.loadInitialFile(this.builtinFileURI);
});
this.loadInitialFile(this.builtinFileURI); this.loadInitialFile(this.builtinFileURI);
} }
protected fileLoaded(fileData: ArrayBuffer, builtinName: string | null): void { protected fileLoaded(fileData: ArrayBuffer, builtinName: string | null): void {
switch (this.mode) {
case 'text':
this.textFileLoaded(fileData, builtinName);
return;
case 'svg':
this.svgFileLoaded(fileData, builtinName);
return;
}
}
protected createView(gammaLUT: HTMLImageElement,
commonShaderSource: string,
shaderSources: ShaderMap<ShaderProgramSource>):
BenchmarkTestView {
return new BenchmarkTestView(this, gammaLUT, commonShaderSource, shaderSources);
}
private textFileLoaded(fileData: ArrayBuffer, builtinName: string | null): void {
const font = new PathfinderFont(fileData, builtinName); const font = new PathfinderFont(fileData, builtinName);
this.font = font; this.font = font;
@ -135,16 +213,22 @@ class BenchmarkAppController extends DemoAppController<BenchmarkTestView> {
this.expandedMeshes = expandedMeshes; this.expandedMeshes = expandedMeshes;
this.view.then(view => { this.view.then(view => {
view.recreateRenderer();
view.attachMeshes([expandedMeshes.meshes]); view.attachMeshes([expandedMeshes.meshes]);
}); });
}); });
} }
protected createView(gammaLUT: HTMLImageElement, private svgFileLoaded(fileData: ArrayBuffer, builtinName: string | null): void {
commonShaderSource: string, this.svgLoader = new SVGLoader;
shaderSources: ShaderMap<ShaderProgramSource>): this.svgLoader.loadFile(fileData);
BenchmarkTestView { this.svgLoader.partition().then(meshes => {
return new BenchmarkTestView(this, gammaLUT, commonShaderSource, shaderSources); this.view.then(view => {
view.recreateRenderer();
view.attachMeshes([meshes]);
view.initCameraBounds(this.svgLoader.svgBounds);
});
});
} }
private reset(): void { private reset(): void {
@ -206,15 +290,26 @@ class BenchmarkAppController extends DemoAppController<BenchmarkTestView> {
} }
private showResults(): void { private showResults(): void {
while (this.resultsTableHeader.lastChild != null)
this.resultsTableHeader.removeChild(this.resultsTableHeader.lastChild);
while (this.resultsTableBody.lastChild != null) while (this.resultsTableBody.lastChild != null)
this.resultsTableBody.removeChild(this.resultsTableBody.lastChild); this.resultsTableBody.removeChild(this.resultsTableBody.lastChild);
const tr = document.createElement('tr');
for (const headerLabel of DISPLAY_HEADER_LABELS[this.mode]) {
const th = document.createElement('th');
th.appendChild(document.createTextNode(headerLabel));
tr.appendChild(th);
}
this.resultsTableHeader.appendChild(tr);
for (const elapsedTime of this.elapsedTimes) { for (const elapsedTime of this.elapsedTimes) {
const tr = document.createElement('tr'); const tr = document.createElement('tr');
const sizeTH = document.createElement('th'); const sizeTH = document.createElement('th');
const timeTD = document.createElement('td'); const timeTD = document.createElement('td');
sizeTH.appendChild(document.createTextNode("" + elapsedTime.size)); sizeTH.appendChild(document.createTextNode("" + elapsedTime.size));
timeTD.appendChild(document.createTextNode("" + elapsedTime.time)); const time = this.mode === 'svg' ? elapsedTime.timeInMS : elapsedTime.time;
timeTD.appendChild(document.createTextNode("" + time));
sizeTH.scope = 'row'; sizeTH.scope = 'row';
tr.appendChild(sizeTH); tr.appendChild(sizeTH);
tr.appendChild(timeTD); tr.appendChild(timeTD);
@ -246,7 +341,8 @@ class BenchmarkAppController extends DemoAppController<BenchmarkTestView> {
} }
class BenchmarkTestView extends DemoView { class BenchmarkTestView extends DemoView {
readonly renderer: BenchmarkRenderer; renderer: BenchmarkTextRenderer | BenchmarkSVGRenderer;
readonly appController: BenchmarkAppController; readonly appController: BenchmarkAppController;
renderingPromiseCallback: ((time: number) => void) | null; renderingPromiseCallback: ((time: number) => void) | null;
@ -256,7 +352,14 @@ class BenchmarkTestView extends DemoView {
} }
set pixelsPerEm(newPPEM: number) { set pixelsPerEm(newPPEM: number) {
this.renderer.pixelsPerEm = newPPEM; if (this.renderer instanceof BenchmarkTextRenderer) {
this.renderer.pixelsPerEm = newPPEM;
} else if (this.renderer instanceof BenchmarkSVGRenderer) {
const camera = this.renderer.camera;
camera.reset();
camera.zoom(newPPEM / 100.0);
camera.center();
}
} }
constructor(appController: BenchmarkAppController, constructor(appController: BenchmarkAppController,
@ -264,24 +367,40 @@ class BenchmarkTestView extends DemoView {
commonShaderSource: string, commonShaderSource: string,
shaderSources: ShaderMap<ShaderProgramSource>) { shaderSources: ShaderMap<ShaderProgramSource>) {
super(gammaLUT, commonShaderSource, shaderSources); super(gammaLUT, commonShaderSource, shaderSources);
this.appController = appController; this.appController = appController;
this.renderer = new BenchmarkRenderer(this); this.recreateRenderer();
this.resizeToFit(true); this.resizeToFit(true);
} }
recreateRenderer(): void {
switch (this.appController.mode) {
case 'svg':
this.renderer = new BenchmarkSVGRenderer(this);
break;
case 'text':
this.renderer = new BenchmarkTextRenderer(this);
break;
}
}
initCameraBounds(bounds: glmatrix.vec4): void {
if (this.renderer instanceof BenchmarkSVGRenderer)
this.renderer.initCameraBounds(bounds);
}
protected renderingFinished(): void { protected renderingFinished(): void {
if (this.renderingPromiseCallback == null) if (this.renderingPromiseCallback == null)
return; return;
const glyphCount = unwrapNull(this.appController.textRun).glyphIDs.length; const appController = this.appController;
const usPerGlyph = this.renderer.lastTimings.rendering * 1000.0 / glyphCount; let time = this.renderer.lastTimings.rendering * 1000.0;
this.renderingPromiseCallback(usPerGlyph); if (appController.mode === 'text')
time /= unwrapNull(appController.textRun).glyphIDs.length;
this.renderingPromiseCallback(time);
} }
} }
class BenchmarkRenderer extends Renderer { class BenchmarkTextRenderer extends BaseRenderer {
renderContext: BenchmarkTestView; renderContext: BenchmarkTestView;
camera: OrthographicCamera; camera: OrthographicCamera;
@ -459,6 +578,22 @@ class BenchmarkRenderer extends Renderer {
} }
} }
class BenchmarkSVGRenderer extends SVGRenderer {
renderContext: BenchmarkTestView;
protected get loader(): SVGLoader {
return this.renderContext.appController.svgLoader;
}
protected get canvas(): HTMLCanvasElement {
return this.renderContext.canvas;
}
constructor(renderContext: BenchmarkTestView) {
super(renderContext);
}
}
function computeMedian(values: number[]): number | null { function computeMedian(values: number[]): number | null {
if (values.length === 0) if (values.length === 0)
return null; return null;
@ -481,6 +616,10 @@ class ElapsedTime {
const median = computeMedian(this.times); const median = computeMedian(this.times);
return median == null ? 0.0 : median; return median == null ? 0.0 : median;
} }
get timeInMS(): number {
return this.time / 1000.0;
}
} }
function main() { function main() {

View File

@ -123,9 +123,7 @@ export class OrthographicCamera extends Camera {
this.scaleBounds = !!options.scaleBounds; this.scaleBounds = !!options.scaleBounds;
this.ignoreBounds = !!options.ignoreBounds; this.ignoreBounds = !!options.ignoreBounds;
this.translation = glmatrix.vec2.create(); this.reset();
this.scale = 1.0;
this.rotationAngle = 0.0;
this._bounds = glmatrix.vec4.create(); this._bounds = glmatrix.vec4.create();
@ -139,6 +137,12 @@ export class OrthographicCamera extends Camera {
this.onRotate = null; this.onRotate = null;
} }
reset(): void {
this.translation = glmatrix.vec2.create();
this.scale = 1.0;
this.rotationAngle = 0.0;
}
onWheel(event: MouseWheelEvent): void { onWheel(event: MouseWheelEvent): void {
if (this.canvas == null) if (this.canvas == null)
throw new Error("onWheel() with no canvas?!"); throw new Error("onWheel() with no canvas?!");
@ -174,6 +178,13 @@ export class OrthographicCamera extends Camera {
this.scale = Math.min(this.canvas.width / width, this.canvas.height / height); this.scale = Math.min(this.canvas.width / width, this.canvas.height / height);
// Center. // Center.
this.center();
}
center(): void {
const upperLeft = glmatrix.vec2.clone([this._bounds[0], this._bounds[1]]);
const lowerRight = glmatrix.vec2.clone([this._bounds[2], this._bounds[3]]);
this.translation = glmatrix.vec2.create(); this.translation = glmatrix.vec2.create();
glmatrix.vec2.lerp(this.translation, upperLeft, lowerRight, 0.5); glmatrix.vec2.lerp(this.translation, upperLeft, lowerRight, 0.5);
glmatrix.vec2.scale(this.translation, this.translation, -this.scale); glmatrix.vec2.scale(this.translation, this.translation, -this.scale);
@ -269,7 +280,7 @@ export class OrthographicCamera extends Camera {
} }
private get centerPoint(): glmatrix.vec2 { private get centerPoint(): glmatrix.vec2 {
return glmatrix.vec2.fromValues(this.canvas.width * 0.5, this.canvas.height * 0.5); return glmatrix.vec2.clone([this.canvas.width * 0.5, this.canvas.height * 0.5]);
} }
get bounds(): glmatrix.vec4 { get bounds(): glmatrix.vec4 {

View File

@ -20,7 +20,7 @@ import {SUBPIXEL_GRANULARITY} from './atlas';
import {OrthographicCamera} from './camera'; import {OrthographicCamera} from './camera';
import {UniformMap} from './gl-utils'; import {UniformMap} from './gl-utils';
import {PathfinderMeshData} from './meshes'; import {PathfinderMeshData} from './meshes';
import {PathTransformBuffers, Renderer} from "./renderer"; import {BaseRenderer, PathTransformBuffers} from "./renderer";
import {ShaderMap, ShaderProgramSource} from "./shader-loader"; import {ShaderMap, ShaderProgramSource} from "./shader-loader";
import SSAAStrategy from './ssaa-strategy'; import SSAAStrategy from './ssaa-strategy';
import {BUILTIN_FONT_URI, computeStemDarkeningAmount, ExpandedMeshData, GlyphStore} from "./text"; import {BUILTIN_FONT_URI, computeStemDarkeningAmount, ExpandedMeshData, GlyphStore} from "./text";
@ -465,7 +465,7 @@ class ReferenceTestView extends DemoView {
} }
} }
class ReferenceTestRenderer extends Renderer { class ReferenceTestRenderer extends BaseRenderer {
renderContext: ReferenceTestView; renderContext: ReferenceTestView;
camera: OrthographicCamera; camera: OrthographicCamera;

View File

@ -36,7 +36,43 @@ export interface PathTransformBuffers<T> {
ext: T; ext: T;
} }
export abstract class Renderer { export interface Renderer {
readonly renderContext: RenderContext;
readonly pathTransformBufferTextures: Array<PathTransformBuffers<PathfinderBufferTexture>>;
readonly meshes: PathfinderMeshBuffers[] | null;
readonly meshData: PathfinderMeshData[] | null;
readonly usesSTTransform: boolean;
readonly emboldenAmount: glmatrix.vec2;
readonly bgColor: glmatrix.vec4;
readonly fgColor: glmatrix.vec4 | null;
readonly backgroundColor: glmatrix.vec4;
readonly meshesAttached: boolean;
readonly usesIntermediateRenderTargets: boolean;
readonly destFramebuffer: WebGLFramebuffer | null;
readonly destAllocatedSize: glmatrix.vec2;
readonly destUsedSize: glmatrix.vec2;
attachMeshes(meshes: PathfinderMeshData[]): void;
pathBoundingRects(objectIndex: number): Float32Array;
setHintsUniform(uniforms: UniformMap): void;
setPathColorsUniform(objectIndex: number, uniforms: UniformMap, textureUnit: number): void;
setEmboldenAmountUniform(objectIndex: number, uniforms: UniformMap): void;
setAntialiasingOptions(aaType: AntialiasingStrategyName,
aaLevel: number,
aaOptions: AAOptions):
void;
redraw(): void;
canvasResized(): void;
meshIndexForObject(objectIndex: number): number;
pathRangeForObject(objectIndex: number): Range;
renderTaskTypeForObject(objectIndex: number): RenderTaskType;
compositingOperationForObject(objectIndex: number): CompositingOperation | null;
setTransformAndTexScaleUniformsForDest(uniforms: UniformMap): void;
setTransformSTAndTexScaleUniformsForDest(uniforms: UniformMap): void;
setTransformUniform(uniforms: UniformMap, objectIndex: number): void;
setTransformSTUniform(uniforms: UniformMap, objectIndex: number): void;
}
export abstract class BaseRenderer implements Renderer {
readonly renderContext: RenderContext; readonly renderContext: RenderContext;
readonly pathTransformBufferTextures: Array<PathTransformBuffers<PathfinderBufferTexture>>; readonly pathTransformBufferTextures: Array<PathTransformBuffers<PathfinderBufferTexture>>;
@ -240,7 +276,7 @@ export abstract class Renderer {
gl.uniform2f(uniforms.uTexScale, usedSize[0], usedSize[1]); gl.uniform2f(uniforms.uTexScale, usedSize[0], usedSize[1]);
} }
setTransformUniform(uniforms: UniformMap, objectIndex: number) { setTransformUniform(uniforms: UniformMap, objectIndex: number): void {
const transform = glmatrix.mat4.clone(this.worldTransform); const transform = glmatrix.mat4.clone(this.worldTransform);
glmatrix.mat4.mul(transform, transform, this.getModelviewTransform(objectIndex)); glmatrix.mat4.mul(transform, transform, this.getModelviewTransform(objectIndex));
this.renderContext.gl.uniformMatrix4fv(uniforms.uTransform, false, transform); this.renderContext.gl.uniformMatrix4fv(uniforms.uTransform, false, transform);

View File

@ -16,7 +16,7 @@ import {OrthographicCamera} from "./camera";
import {UniformMap} from './gl-utils'; import {UniformMap} from './gl-utils';
import {PathfinderMeshData} from './meshes'; import {PathfinderMeshData} from './meshes';
import {CompositingOperation, RenderTaskType} from './render-task'; import {CompositingOperation, RenderTaskType} from './render-task';
import {PathTransformBuffers, Renderer} from "./renderer"; import {BaseRenderer, PathTransformBuffers} from "./renderer";
import {ShaderMap} from './shader-loader'; import {ShaderMap} from './shader-loader';
import SSAAStrategy from './ssaa-strategy'; import SSAAStrategy from './ssaa-strategy';
import {SVGLoader} from './svg-loader'; import {SVGLoader} from './svg-loader';
@ -36,7 +36,7 @@ const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
xcaa: ECAAMulticolorStrategy, xcaa: ECAAMulticolorStrategy,
}; };
export abstract class SVGRenderer extends Renderer { export abstract class SVGRenderer extends BaseRenderer {
renderContext: RenderContext; renderContext: RenderContext;
camera: OrthographicCamera; camera: OrthographicCamera;

View File

@ -24,7 +24,6 @@ import {createFramebuffer, createFramebufferColorTexture} from './gl-utils';
import {createFramebufferDepthTexture, QUAD_ELEMENTS, setTextureParameters} from './gl-utils'; import {createFramebufferDepthTexture, QUAD_ELEMENTS, setTextureParameters} from './gl-utils';
import {UniformMap} from './gl-utils'; import {UniformMap} from './gl-utils';
import {PathfinderMeshBuffers, PathfinderMeshData} from './meshes'; import {PathfinderMeshBuffers, PathfinderMeshData} from './meshes';
import {Renderer} from './renderer';
import {PathfinderShaderProgram, ShaderMap, ShaderProgramSource} from './shader-loader'; import {PathfinderShaderProgram, ShaderMap, ShaderProgramSource} from './shader-loader';
import SSAAStrategy from './ssaa-strategy'; import SSAAStrategy from './ssaa-strategy';
import {calculatePixelRectForGlyph, PathfinderFont} from "./text"; import {calculatePixelRectForGlyph, PathfinderFont} from "./text";
@ -86,8 +85,14 @@ declare global {
} }
} }
interface TabShownEvent {
target: EventTarget;
relatedTarget: EventTarget;
}
interface JQuerySubset { interface JQuerySubset {
modal(options?: any): void; modal(options?: any): void;
on(name: 'shown.bs.tab', handler: (event: TabShownEvent) => void): void;
} }
type Matrix4D = Float32Array; type Matrix4D = Float32Array;

View File

@ -17,7 +17,7 @@ import {Atlas, ATLAS_SIZE, AtlasGlyph, GlyphKey, SUBPIXEL_GRANULARITY} from './a
import {CameraView, OrthographicCamera} from './camera'; import {CameraView, OrthographicCamera} from './camera';
import {createFramebuffer, createFramebufferDepthTexture, QUAD_ELEMENTS} from './gl-utils'; import {createFramebuffer, createFramebufferDepthTexture, QUAD_ELEMENTS} from './gl-utils';
import {UniformMap} from './gl-utils'; import {UniformMap} from './gl-utils';
import {PathTransformBuffers, Renderer} from './renderer'; import {BaseRenderer, PathTransformBuffers} from './renderer';
import {ShaderMap} from './shader-loader'; import {ShaderMap} from './shader-loader';
import SSAAStrategy from './ssaa-strategy'; import SSAAStrategy from './ssaa-strategy';
import {calculatePixelRectForGlyph, computeStemDarkeningAmount, GlyphStore, Hint} from "./text"; import {calculatePixelRectForGlyph, computeStemDarkeningAmount, GlyphStore, Hint} from "./text";
@ -56,7 +56,7 @@ export interface TextRenderContext extends RenderContext {
newTimingsReceived(timings: Timings): void; newTimingsReceived(timings: Timings): void;
} }
export abstract class TextRenderer extends Renderer { export abstract class TextRenderer extends BaseRenderer {
renderContext: TextRenderContext; renderContext: TextRenderContext;
camera: OrthographicCamera; camera: OrthographicCamera;

View File

@ -787,7 +787,8 @@ export abstract class ECAAStrategy extends XCAAStrategy {
this.curveShaderProgramNames[1]); this.curveShaderProgramNames[1]);
} }
protected setAAUniforms(renderer: Renderer, uniforms: UniformMap, objectIndex: number): void { protected setAAUniforms(renderer: Renderer, uniforms: UniformMap, objectIndex: number):
void {
super.setAAUniforms(renderer, uniforms, objectIndex); super.setAAUniforms(renderer, uniforms, objectIndex);
renderer.setEmboldenAmountUniform(objectIndex, uniforms); renderer.setEmboldenAmountUniform(objectIndex, uniforms);
} }