Get a bare-minimum benchmark up and running

This commit is contained in:
Patrick Walton 2017-09-12 12:40:14 -07:00
parent a7d75f913c
commit 2c8c11b303
7 changed files with 347 additions and 111 deletions

View File

@ -8,6 +8,7 @@
</head>
<body>
{{>partials/navbar.html isTool=true}}
<canvas id="pf-canvas" class="pf-draggable" width="400" height="300"></canvas>
<div class="fixed-bottom mb-3 d-flex justify-content-end align-items-end pf-pointer-events-none">
<div id="pf-toolbar">
<button id="pf-run-benchmark-button" type="button"

View File

@ -168,7 +168,8 @@ class ThreeDController extends DemoAppController<ThreeDView> {
this.baseMeshes = baseMeshes;
this.expandedMeshes = this.glyphStorage.expandMeshes(baseMeshes);
this.view.then(view => {
view.uploadPathMetadata();
view.uploadPathColors(this.expandedMeshes.length);
view.uploadPathTransforms(this.expandedMeshes.length);
view.attachMeshes(this.expandedMeshes.map(meshes => meshes.meshes));
});
});
@ -216,41 +217,34 @@ class ThreeDView extends PathfinderDemoView {
this.gl.bufferData(this.gl.ELEMENT_ARRAY_BUFFER, CUBE_INDICES, this.gl.STATIC_DRAW);
}
uploadPathMetadata() {
this.pathColorsBufferTextures = [];
this.pathTransformBufferTextures = [];
protected pathColorsForObject(textFrameIndex: number): Uint8Array {
const textFrame = this.appController.glyphStorage.textFrames[textFrameIndex];
const textGlyphs = textFrame.allGlyphs;
const pathCount = textGlyphs.length;
const textFrameCount = this.appController.glyphStorage.textFrames.length;
for (let textFrameIndex = 0;
textFrameIndex < textFrameCount;
textFrameIndex++) {
const textFrame = this.appController.glyphStorage.textFrames[textFrameIndex];
const textGlyphs = textFrame.allGlyphs;
const pathCount = textGlyphs.length;
const pathColors = new Uint8Array(4 * (pathCount + 1));
for (let pathIndex = 0; pathIndex < pathCount; pathIndex++)
pathColors.set(TEXT_COLOR, (pathIndex + 1) * 4);
const hint = new Hint(this.appController.glyphStorage.font, PIXELS_PER_UNIT, false);
return pathColors;
}
const pathColors = new Uint8Array(4 * (pathCount + 1));
const pathTransforms = new Float32Array(4 * (pathCount + 1));
protected pathTransformsForObject(textFrameIndex: number): Float32Array {
const textFrame = this.appController.glyphStorage.textFrames[textFrameIndex];
const textGlyphs = textFrame.allGlyphs;
const pathCount = textGlyphs.length;
for (let pathIndex = 0; pathIndex < pathCount; pathIndex++) {
const startOffset = (pathIndex + 1) * 4;
const hint = new Hint(this.appController.glyphStorage.font, PIXELS_PER_UNIT, false);
pathColors.set(TEXT_COLOR, startOffset);
const pathTransforms = new Float32Array(4 * (pathCount + 1));
const textGlyph = textGlyphs[pathIndex];
const glyphOrigin = textGlyph.calculatePixelOrigin(hint, PIXELS_PER_UNIT);
pathTransforms.set([1, 1, glyphOrigin[0], glyphOrigin[1]], startOffset);
}
const pathColorsBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathColors');
const pathTransformBufferTexture = new PathfinderBufferTexture(this.gl,
'uPathTransform');
pathColorsBufferTexture.upload(this.gl, pathColors);
pathTransformBufferTexture.upload(this.gl, pathTransforms);
this.pathColorsBufferTextures.push(pathColorsBufferTexture);
this.pathTransformBufferTextures.push(pathTransformBufferTexture);
for (let pathIndex = 0; pathIndex < pathCount; pathIndex++) {
const textGlyph = textGlyphs[pathIndex];
const glyphOrigin = textGlyph.calculatePixelOrigin(hint, PIXELS_PER_UNIT);
pathTransforms.set([1, 1, glyphOrigin[0], glyphOrigin[1]], (pathIndex + 1) * 4);
}
return pathTransforms;
}
protected createAAStrategy(aaType: AntialiasingStrategyName,
@ -304,17 +298,13 @@ class ThreeDView extends PathfinderDemoView {
return glmatrix.vec2.fromValues(this.canvas.width, this.canvas.height);
}
get destFramebuffer(): WebGLFramebuffer | null {
return null;
}
destFramebuffer: WebGLFramebuffer | null = null;
get destUsedSize(): glmatrix.vec2 {
return this.destAllocatedSize;
}
protected get usedSizeFactor(): glmatrix.vec2 {
return glmatrix.vec2.fromValues(1.0, 1.0);
}
protected usedSizeFactor: glmatrix.vec2 = glmatrix.vec2.clone([1.0, 1.0]);
private calculateWorldTransform(modelviewTranslation: glmatrix.vec3,
modelviewScale: glmatrix.vec3):
@ -355,13 +345,8 @@ class ThreeDView extends PathfinderDemoView {
return transform;
}
protected get directCurveProgramName(): keyof ShaderMap<void> {
return 'direct3DCurve';
}
protected get directInteriorProgramName(): keyof ShaderMap<void> {
return 'direct3DInterior';
}
protected directCurveProgramName: keyof ShaderMap<void> = 'direct3DCurve';
protected directInteriorProgramName: keyof ShaderMap<void> = 'direct3DInterior';
protected depthFunction: number = this.gl.LESS;

View File

@ -58,22 +58,29 @@ export abstract class DemoAppController<View extends PathfinderDemoView> extends
start() {
super.start();
this.settingsCard = document.getElementById('pf-settings') as HTMLElement;
this.settingsButton = document.getElementById('pf-settings-button') as HTMLButtonElement;
this.settingsCloseButton = document.getElementById('pf-settings-close-button') as
HTMLButtonElement;
const settingsCard = document.getElementById('pf-settings') as (HTMLElement | null);
const settingsButton = document.getElementById('pf-settings-button') as
(HTMLButtonElement | null);
const settingsCloseButton = document.getElementById('pf-settings-close-button') as
(HTMLButtonElement | null);
this.settingsButton.addEventListener('click', event => {
event.stopPropagation();
this.settingsCard.classList.toggle('pf-invisible');
}, false);
this.settingsCloseButton.addEventListener('click', () => {
this.settingsCard.classList.add('pf-invisible');
}, false);
document.body.addEventListener('click', () => {
this.settingsCard.classList.add('pf-invisible');
}, false);
this.settingsCard.addEventListener('click', event => event.stopPropagation(), false);
if (settingsButton != null) {
settingsButton.addEventListener('click', event => {
event.stopPropagation();
unwrapNull(settingsCard).classList.toggle('pf-invisible');
}, false);
}
if (settingsCloseButton != null) {
settingsCloseButton.addEventListener('click', () => {
unwrapNull(settingsCard).classList.add('pf-invisible');
}, false);
}
if (settingsCard != null) {
document.body.addEventListener('click', () => {
settingsCard.classList.add('pf-invisible');
}, false);
settingsCard.addEventListener('click', event => event.stopPropagation(), false);
}
const screenshotButton = document.getElementById('pf-screenshot-button') as
HTMLButtonElement | null;
@ -124,20 +131,31 @@ export abstract class DemoAppController<View extends PathfinderDemoView> extends
return this.createView();
});
this.aaLevelSelect = document.getElementById('pf-aa-level-select') as HTMLSelectElement;
this.aaLevelSelect = document.getElementById('pf-aa-level-select') as
(HTMLSelectElement | null);
if (this.aaLevelSelect != null)
this.aaLevelSelect.addEventListener('change', () => this.updateAALevel(), false);
this.subpixelAASwitch =
document.getElementById('pf-subpixel-aa') as HTMLInputElement | null;
this.aaLevelSelect.addEventListener('change', () => this.updateAALevel(), false);
if (this.subpixelAASwitch != null)
this.subpixelAASwitch.addEventListener('change', () => this.updateAALevel(), false);
this.updateAALevel();
}
private updateAALevel() {
const selectedOption = this.aaLevelSelect.selectedOptions[0];
const aaValues = unwrapNull(/^([a-z-]+)(?:-([0-9]+))?$/.exec(selectedOption.value));
const aaType = aaValues[1] as AntialiasingStrategyName;
const aaLevel = aaValues[2] === "" ? 1 : parseInt(aaValues[2]);
let aaType: AntialiasingStrategyName, aaLevel: number;
if (this.aaLevelSelect != null) {
const selectedOption = this.aaLevelSelect.selectedOptions[0];
const aaValues = unwrapNull(/^([a-z-]+)(?:-([0-9]+))?$/.exec(selectedOption.value));
aaType = aaValues[1] as AntialiasingStrategyName;
aaLevel = aaValues[2] === "" ? 1 : parseInt(aaValues[2]);
} else {
aaType = 'none';
aaLevel = 0;
}
const subpixelAA = this.subpixelAASwitch == null ? false : this.subpixelAASwitch.checked;
this.view.then(view => view.setAntialiasingOptions(aaType, aaLevel, subpixelAA));
}
@ -187,10 +205,6 @@ export abstract class DemoAppController<View extends PathfinderDemoView> extends
protected commonShaderSource: string | null;
protected shaderSources: ShaderMap<ShaderProgramSource> | null;
private aaLevelSelect: HTMLSelectElement;
private aaLevelSelect: HTMLSelectElement | null;
private subpixelAASwitch: HTMLInputElement | null;
private settingsCard: HTMLElement;
private settingsButton: HTMLButtonElement;
private settingsCloseButton: HTMLButtonElement;
}

View File

@ -8,18 +8,44 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
import * as glmatrix from 'gl-matrix';
import * as opentype from "opentype.js";
import {AppController} from "./app-controller";
import { AppController, DemoAppController } from "./app-controller";
import {PathfinderMeshData} from "./meshes";
import {BUILTIN_FONT_URI, GlyphStorage, PathfinderGlyph, TextFrame, TextRun} from "./text";
import {assert, unwrapNull} from "./utils";
import { BUILTIN_FONT_URI, GlyphStorage, PathfinderGlyph, TextFrame, TextRun, ExpandedMeshData } from "./text";
import { assert, unwrapNull, PathfinderError } from "./utils";
import { PathfinderDemoView, Timings } from "./view";
import { ShaderMap, ShaderProgramSource } from "./shader-loader";
import { AntialiasingStrategy, AntialiasingStrategyName, NoAAStrategy } from "./aa-strategy";
import SSAAStrategy from './ssaa-strategy';
import { OrthographicCamera } from './camera';
const STRING: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
const FONT: string = 'nimbus-sans';
class BenchmarkAppController extends AppController {
const TEXT_COLOR: number[] = [0, 0, 0, 255];
const MIN_FONT_SIZE: number = 6;
const MAX_FONT_SIZE: number = 200;
const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
none: NoAAStrategy,
ssaa: SSAAStrategy,
};
interface ElapsedTime {
size: number;
time: number;
}
interface AntialiasingStrategyTable {
none: typeof NoAAStrategy;
ssaa: typeof SSAAStrategy;
}
class BenchmarkAppController extends DemoAppController<BenchmarkTestView> {
start() {
super.start();
@ -31,29 +57,176 @@ class BenchmarkAppController extends AppController {
protected fileLoaded(): void {
const font = opentype.parse(this.fileData);
assert(font.isSupported(), "The font type is unsupported!");
this.font = font;
assert(this.font.isSupported(), "The font type is unsupported!");
const createGlyph = (glyph: opentype.Glyph) => new BenchmarkGlyph(glyph);
const textRun = new TextRun<BenchmarkGlyph>(STRING, [0, 0], font, createGlyph);
this.textRun = textRun;
const textFrame = new TextFrame([textRun], font);
this.glyphStorage = new GlyphStorage(this.fileData, [textFrame], createGlyph, font);
this.glyphStorage.partition().then(meshes => {
this.meshes = meshes;
// TODO(pcwalton)
// this.renderer.attachMeshes();
this.glyphStorage.partition().then(baseMeshes => {
this.baseMeshes = baseMeshes;
const expandedMeshes = this.glyphStorage.expandMeshes(baseMeshes)[0];
this.expandedMeshes = expandedMeshes;
this.view.then(view => {
view.uploadPathColors(1);
view.uploadPathTransforms(1);
view.attachMeshes([expandedMeshes.meshes]);
})
})
}
protected createView(): BenchmarkTestView {
return new BenchmarkTestView(this,
unwrapNull(this.commonShaderSource),
unwrapNull(this.shaderSources));
}
private runBenchmark(): void {
// TODO(pcwalton)
this.pixelsPerEm = MIN_FONT_SIZE;
this.elapsedTimes = [];
this.view.then(view => this.runOneBenchmarkTest(view));
}
private runOneBenchmarkTest(view: BenchmarkTestView): void {
const renderedPromise = new Promise<number>((resolve, reject) => {
view.renderingPromiseCallback = resolve;
view.pixelsPerEm = this.pixelsPerEm;
});
renderedPromise.then(elapsedTime => {
this.elapsedTimes.push({ size: this.pixelsPerEm, time: elapsedTime });
if (this.pixelsPerEm == MAX_FONT_SIZE) {
console.info(this.elapsedTimes);
return;
}
this.pixelsPerEm++;
this.runOneBenchmarkTest(view);
});
}
protected readonly defaultFile: string = FONT;
protected readonly builtinFileURI: string = BUILTIN_FONT_URI;
private glyphStorage: GlyphStorage<BenchmarkGlyph>;
private meshes: PathfinderMeshData;
private baseMeshes: PathfinderMeshData;
private expandedMeshes: ExpandedMeshData;
private pixelsPerEm: number;
private elapsedTimes: ElapsedTime[];
font: opentype.Font | null;
textRun: TextRun<BenchmarkGlyph> | null;
}
class BenchmarkTestView extends PathfinderDemoView {
constructor(appController: BenchmarkAppController,
commonShaderSource: string,
shaderSources: ShaderMap<ShaderProgramSource>) {
super(commonShaderSource, shaderSources);
this.appController = appController;
this.camera = new OrthographicCamera(this.canvas);
this.camera.onPan = () => this.setDirty();
this.camera.onZoom = () => this.setDirty();
}
protected createAAStrategy(aaType: AntialiasingStrategyName,
aaLevel: number,
subpixelAA: boolean):
AntialiasingStrategy {
if (aaType !== 'ecaa')
return new (ANTIALIASING_STRATEGIES[aaType])(aaLevel, subpixelAA);
throw new PathfinderError("Unsupported antialiasing type!");
}
protected compositeIfNecessary(): void {}
protected updateTimings(timings: Timings): void {
// TODO(pcwalton)
}
protected pathColorsForObject(objectIndex: number): Uint8Array {
const pathColors = new Uint8Array(4 * (STRING.length + 1));
for (let pathIndex = 0; pathIndex < STRING.length; pathIndex++)
pathColors.set(TEXT_COLOR, (pathIndex + 1) * 4);
return pathColors;
}
protected pathTransformsForObject(objectIndex: number): Float32Array {
const pathTransforms = new Float32Array(4 * (STRING.length + 1));
let currentX = 0;
for (let glyphIndex = 0; glyphIndex < STRING.length; glyphIndex++) {
const glyph = unwrapNull(this.appController.textRun).glyphs[glyphIndex];
pathTransforms.set([1, 1, currentX, 0], (glyphIndex + 1) * 4);
currentX += glyph.advanceWidth;
}
return pathTransforms;
}
protected renderingFinished(): void {
if (this.renderingPromiseCallback != null)
this.renderingPromiseCallback(this.lastTimings.atlasRendering);
}
destFramebuffer: WebGLFramebuffer | null = null;
get destAllocatedSize(): glmatrix.vec2 {
return glmatrix.vec2.clone([this.canvas.width, this.canvas.height]);
}
get destUsedSize(): glmatrix.vec2 {
return this.destAllocatedSize;
}
private readonly appController: BenchmarkAppController;
protected usedSizeFactor: glmatrix.vec2 = glmatrix.vec2.clone([1.0, 1.0]);
protected get worldTransform() {
const transform = glmatrix.mat4.create();
const translation = this.camera.translation;
glmatrix.mat4.fromTranslation(transform, [translation[0], translation[1], 0]);
glmatrix.mat4.scale(transform, transform, [this.camera.scale, this.camera.scale, 1.0]);
const pixelsPerUnit = this._pixelsPerEm / unwrapNull(this.appController.font).unitsPerEm;
glmatrix.mat4.scale(transform, transform, [pixelsPerUnit, pixelsPerUnit, 1.0]);
return transform;
}
get pixelsPerEm(): number {
return this._pixelsPerEm;
}
set pixelsPerEm(newPixelsPerEm: number) {
this._pixelsPerEm = newPixelsPerEm;
this.setDirty();
}
renderingPromiseCallback: ((time: number) => void) | null;
private _pixelsPerEm: number = 32.0;
protected directCurveProgramName: keyof ShaderMap<void> = 'directCurve';
protected directInteriorProgramName: keyof ShaderMap<void> = 'directInterior';
protected depthFunction: number = this.gl.GREATER;
protected camera: OrthographicCamera;
}
class BenchmarkGlyph extends PathfinderGlyph {}
function main() {
const controller = new BenchmarkAppController;
window.addEventListener('load', () => controller.start(), false);
}
main();

View File

@ -190,7 +190,8 @@ class SVGDemoController extends DemoAppController<SVGDemoView> {
private meshesReceived(bounds: glmatrix.vec4): void {
this.view.then(view => {
view.uploadPathMetadata(this.pathInstances);
view.uploadPathColors(1);
view.uploadPathTransforms(1);
view.attachMeshes([this.meshes]);
view.camera.bounds = bounds;
@ -198,8 +199,9 @@ class SVGDemoController extends DemoAppController<SVGDemoView> {
})
}
pathInstances: PathInstance[];
private svg: SVGSVGElement;
private pathInstances: PathInstance[];
private meshes: PathfinderMeshData;
}
@ -228,9 +230,10 @@ class SVGDemoView extends PathfinderDemoView {
return this.destAllocatedSize;
}
uploadPathMetadata(instances: PathInstance[]) {
protected pathColorsForObject(objectIndex: number): Uint8Array {
const instances = this.appController.pathInstances;
const pathColors = new Uint8Array(4 * (instances.length + 1));
const pathTransforms = new Float32Array(4 * (instances.length + 1));
for (let pathIndex = 0; pathIndex < instances.length; pathIndex++) {
const startOffset = (pathIndex + 1) * 4;
@ -241,17 +244,22 @@ class SVGDemoView extends PathfinderDemoView {
style[property] === 'none' ? [0, 0, 0, 0] : parseColor(style[property]).rgba;
pathColors.set(color.slice(0, 3), startOffset);
pathColors[startOffset + 3] = color[3] * 255;
}
return pathColors;
}
protected pathTransformsForObject(objectIndex: number): Float32Array {
const instances = this.appController.pathInstances;
const pathTransforms = new Float32Array(4 * (instances.length + 1));
for (let pathIndex = 0; pathIndex < instances.length; pathIndex++) {
// TODO(pcwalton): Set transform.
const startOffset = (pathIndex + 1) * 4;
pathTransforms.set([1, 1, 0, 0], startOffset);
}
const pathColorsBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathColors');
const pathTransformBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathTransform');
pathColorsBufferTexture.upload(this.gl, pathColors);
pathTransformBufferTexture.upload(this.gl, pathTransforms);
this.pathColorsBufferTextures = [pathColorsBufferTexture];
this.pathTransformBufferTextures = [pathTransformBufferTexture];
return pathTransforms;
}
protected createAAStrategy(aaType: AntialiasingStrategyName,

View File

@ -178,7 +178,7 @@ class TextDemoController extends DemoAppController<TextDemoView> {
this.meshes = meshes;
this.view.then(view => {
view.attachText();
view.uploadPathMetadata(this.layout.glyphStorage.uniqueGlyphs.length);
view.uploadPathColors(1);
view.attachMeshes([this.meshes]);
});
});
@ -262,17 +262,19 @@ class TextDemoView extends MonochromePathfinderView {
super.initContext();
}
uploadPathMetadata(pathCount: number) {
protected pathColorsForObject(objectIndex: number): Uint8Array {
const atlasGlyphs = this.appController.atlasGlyphs;
const pathCount = atlasGlyphs.length;
const pathColors = new Uint8Array(4 * (pathCount + 1));
for (let pathIndex = 0; pathIndex < pathCount; pathIndex++) {
for (let channel = 0; channel < 3; channel++)
pathColors[(pathIndex + 1) * 4 + channel] = 0x00; // RGB
pathColors[(pathIndex + 1) * 4 + 3] = 0xff; // alpha
}
const pathColorsBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathColors');
pathColorsBufferTexture.upload(this.gl, pathColors);
this.pathColorsBufferTextures = [pathColorsBufferTexture];
return pathColors;
}
/// Lays out glyphs on the canvas.
@ -342,10 +344,37 @@ class TextDemoView extends MonochromePathfinderView {
const uniqueGlyphIndices = uniqueGlyphs.map(glyph => glyph.index);
uniqueGlyphIndices.sort((a, b) => a - b);
this.uploadPathTransforms(1);
// TODO(pcwalton): Regenerate the IBOs to include only the glyphs we care about.
const transforms = new Float32Array((uniqueGlyphs.length + 1) * 4);
const pathHints = new Float32Array((uniqueGlyphs.length + 1) * 4);
for (let glyphIndex = 0; glyphIndex < atlasGlyphs.length; glyphIndex++) {
const glyph = atlasGlyphs[glyphIndex];
let pathID = _.sortedIndexOf(uniqueGlyphIndices, glyph.index);
assert(pathID >= 0, "No path ID!");
pathID++;
pathHints[pathID * 4 + 0] = hint.xHeight;
pathHints[pathID * 4 + 1] = hint.hintedXHeight;
}
const pathHintsBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathHints');
pathHintsBufferTexture.upload(this.gl, pathHints);
this.pathHintsBufferTexture = pathHintsBufferTexture;
}
protected pathTransformsForObject(objectIndex: number): Float32Array {
const atlasGlyphs = this.appController.atlasGlyphs;
const pixelsPerUnit = this.appController.pixelsPerUnit;
const uniqueGlyphs = this.appController.layout.glyphStorage.uniqueGlyphs;
const uniqueGlyphIndices = uniqueGlyphs.map(glyph => glyph.index);
uniqueGlyphIndices.sort((a, b) => a - b);
const transforms = new Float32Array((uniqueGlyphs.length + 1) * 4);
for (let glyphIndex = 0; glyphIndex < atlasGlyphs.length; glyphIndex++) {
const glyph = atlasGlyphs[glyphIndex];
@ -359,18 +388,9 @@ class TextDemoView extends MonochromePathfinderView {
transforms[pathID * 4 + 1] = pixelsPerUnit;
transforms[pathID * 4 + 2] = atlasOrigin[0];
transforms[pathID * 4 + 3] = atlasOrigin[1];
pathHints[pathID * 4 + 0] = hint.xHeight;
pathHints[pathID * 4 + 1] = hint.hintedXHeight;
}
const pathTransformBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathTransform');
pathTransformBufferTexture.upload(this.gl, transforms);
this.pathTransformBufferTextures = [pathTransformBufferTexture];
const pathHintsBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathHints');
pathHintsBufferTexture.upload(this.gl, pathHints);
this.pathHintsBufferTexture = pathHintsBufferTexture;
return transforms;
}
private createAtlasFramebuffer() {

View File

@ -109,6 +109,8 @@ export abstract class PathfinderDemoView extends PathfinderView {
this.initContext();
this.lastTimings = { atlasRendering: 0, compositing: 0 };
const shaderSource = this.compileShaders(commonShaderSource, shaderSources);
this.shaderPrograms = this.linkShaders(shaderSource);
@ -281,6 +283,9 @@ export abstract class PathfinderDemoView extends PathfinderView {
// Finish timing.
this.finishTiming();
// Invoke the post-render hook.
this.renderingFinished();
// Take a screenshot if desired.
if (this.wantsScreenshot) {
this.wantsScreenshot = false;
@ -288,6 +293,8 @@ export abstract class PathfinderDemoView extends PathfinderView {
}
}
protected renderingFinished(): void {}
private setTransformUniform(uniforms: UniformMap, objectIndex: number) {
const transform = glmatrix.mat4.create();
if (this.antialiasingStrategy != null)
@ -423,10 +430,10 @@ export abstract class PathfinderDemoView extends PathfinderView {
const compositingTime =
this.timerQueryExt.getQueryObjectEXT(this.compositingTimerQuery,
this.timerQueryExt.QUERY_RESULT_EXT);
this.updateTimings({
this.lastTimings = {
atlasRendering: atlasRenderingTime / 1000000.0,
compositing: compositingTime / 1000000.0,
});
};
window.clearInterval(this.timerQueryPollInterval!);
this.timerQueryPollInterval = null;
@ -485,6 +492,34 @@ export abstract class PathfinderDemoView extends PathfinderView {
this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
}
uploadPathColors(objectCount: number) {
this.pathColorsBufferTextures = [];
for (let objectIndex = 0; objectIndex < objectCount; objectIndex++) {
const pathColorsBufferTexture = new PathfinderBufferTexture(this.gl, 'uPathColors');
const pathColors = this.pathColorsForObject(objectIndex);
pathColorsBufferTexture.upload(this.gl, pathColors);
this.pathColorsBufferTextures.push(pathColorsBufferTexture);
}
}
uploadPathTransforms(objectCount: number) {
this.pathTransformBufferTextures = [];
for (let objectIndex = 0; objectIndex < objectCount; objectIndex++) {
const pathTransformBufferTexture = new PathfinderBufferTexture(this.gl,
'uPathTransform');
const pathTransforms = this.pathTransformsForObject(objectIndex);
pathTransformBufferTexture.upload(this.gl, pathTransforms);
this.pathTransformBufferTextures.push(pathTransformBufferTexture);
}
}
protected abstract pathColorsForObject(objectIndex: number): Uint8Array;
protected abstract pathTransformsForObject(objectIndex: number): Float32Array;
protected abstract get depthFunction(): number;
protected abstract createAAStrategy(aaType: AntialiasingStrategyName,
@ -494,8 +529,6 @@ export abstract class PathfinderDemoView extends PathfinderView {
protected abstract compositeIfNecessary(): void;
protected abstract updateTimings(timings: Timings): void;
abstract get destFramebuffer(): WebGLFramebuffer | null;
abstract get destAllocatedSize(): glmatrix.vec2;
@ -536,6 +569,8 @@ export abstract class PathfinderDemoView extends PathfinderView {
private compositingTimerQuery: WebGLQuery;
private timerQueryPollInterval: number | null;
protected lastTimings: Timings;
private wantsScreenshot: boolean;
}