Partially implement benchmarking for SVG.
This commit is contained in:
parent
f5a7032ca5
commit
30893fb9ad
|
@ -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,8 +23,23 @@
|
||||||
</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">
|
||||||
|
<a class="nav-link active" id="pf-benchmark-text-tab"
|
||||||
|
data-toggle="tab" href="#pf-benchmark-text" role="tab"
|
||||||
|
aria-controls="pf-benchmark-text" aria-selected="true">Text</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" id="pf-benchmark-svg-tab" data-toggle="tab"
|
||||||
|
href="#pf-benchmark-svg" role="tab"
|
||||||
|
aria-controls="pf-benchmark-svg" aria-selected="false">SVG</a>
|
||||||
|
</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"
|
<label for="pf-aa-level-select"
|
||||||
class="col-form-label mr-sm-2">Antialiasing</label>
|
class="col-form-label mr-sm-2">Antialiasing</label>
|
||||||
<select id="pf-aa-level-select"
|
<select id="pf-aa-level-select"
|
||||||
|
@ -37,6 +54,13 @@
|
||||||
{{>partials/switch.html id="pf-subpixel-aa" title="Subpixel AA"}}
|
{{>partials/switch.html id="pf-subpixel-aa" title="Subpixel AA"}}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane pt-3" id="pf-benchmark-svg"
|
||||||
|
role="tabpanel" aria-labelledby="pf-benchmark-svg-tab">
|
||||||
|
<form class="form" id="pf-benchmark-svg-form">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
if (this.renderer instanceof BenchmarkTextRenderer) {
|
||||||
this.renderer.pixelsPerEm = newPPEM;
|
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() {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue