Benchmark the server-side partitioning
This commit is contained in:
parent
7f84e98e6e
commit
b6c6c70ef0
|
@ -102,6 +102,12 @@ button > svg path {
|
|||
overflow: scroll;
|
||||
max-height: 75vh;
|
||||
}
|
||||
.pf-benchmark-results-global {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
.pf-benchmark-results-label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/*
|
||||
* Arrow
|
||||
|
|
|
@ -45,6 +45,11 @@
|
|||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="pf-benchmark-results-global">
|
||||
<span class="pf-benchmark-results-label">Partitioning:</span>
|
||||
|
||||
<span id="pf-benchmark-results-partitioning-time">0</span> µs/glyph
|
||||
</div>
|
||||
<table class="table table-striped">
|
||||
<thead class="thead-default">
|
||||
<tr><th>Font size (px)</th><th>GPU time per glyph (µs)</th></tr>
|
||||
|
|
|
@ -166,9 +166,9 @@ class ThreeDController extends DemoAppController<ThreeDView> {
|
|||
this.glyphStorage = new TextFrameGlyphStorage(fileData, textFrames, font);
|
||||
this.glyphStorage.layoutRuns();
|
||||
|
||||
this.glyphStorage.partition().then((baseMeshes: PathfinderMeshData) => {
|
||||
this.baseMeshes = baseMeshes;
|
||||
this.expandedMeshes = this.glyphStorage.expandMeshes(baseMeshes);
|
||||
this.glyphStorage.partition().then(result => {
|
||||
this.baseMeshes = result.meshes;
|
||||
this.expandedMeshes = this.glyphStorage.expandMeshes(this.baseMeshes);
|
||||
this.view.then(view => {
|
||||
view.uploadPathColors(this.expandedMeshes.length);
|
||||
view.uploadPathTransforms(this.expandedMeshes.length);
|
||||
|
|
|
@ -58,6 +58,9 @@ class BenchmarkAppController extends DemoAppController<BenchmarkTestView> {
|
|||
this.resultsTableBody =
|
||||
unwrapNull(document.getElementById('pf-benchmark-results-table-body')) as
|
||||
HTMLTableSectionElement;
|
||||
this.resultsPartitioningTimeLabel =
|
||||
unwrapNull(document.getElementById('pf-benchmark-results-partitioning-time')) as
|
||||
HTMLSpanElement;
|
||||
|
||||
const resultsCloseButton =
|
||||
unwrapNull(document.getElementById('pf-benchmark-results-close-button'));
|
||||
|
@ -82,10 +85,18 @@ class BenchmarkAppController extends DemoAppController<BenchmarkTestView> {
|
|||
const textFrame = new TextFrame([textRun], font);
|
||||
this.glyphStorage = new TextFrameGlyphStorage(fileData, [textFrame], font);
|
||||
|
||||
this.glyphStorage.partition().then(baseMeshes => {
|
||||
this.baseMeshes = baseMeshes;
|
||||
const expandedMeshes = this.glyphStorage.expandMeshes(baseMeshes)[0];
|
||||
this.glyphStorage.partition().then(result => {
|
||||
this.baseMeshes = result.meshes;
|
||||
|
||||
const partitionTime = result.time / this.glyphStorage.uniqueGlyphs.length * 1e6;
|
||||
const timeLabel = this.resultsPartitioningTimeLabel;
|
||||
while (timeLabel.firstChild != null)
|
||||
timeLabel.removeChild(timeLabel.firstChild);
|
||||
timeLabel.appendChild(document.createTextNode("" + partitionTime));
|
||||
|
||||
const expandedMeshes = this.glyphStorage.expandMeshes(this.baseMeshes)[0];
|
||||
this.expandedMeshes = expandedMeshes;
|
||||
|
||||
this.view.then(view => {
|
||||
view.uploadPathColors(1);
|
||||
view.uploadPathTransforms(1);
|
||||
|
@ -149,6 +160,7 @@ class BenchmarkAppController extends DemoAppController<BenchmarkTestView> {
|
|||
|
||||
private resultsModal: HTMLDivElement;
|
||||
private resultsTableBody: HTMLTableSectionElement;
|
||||
private resultsPartitioningTimeLabel: HTMLSpanElement;
|
||||
|
||||
private glyphStorage: TextFrameGlyphStorage<BenchmarkGlyph>;
|
||||
private baseMeshes: PathfinderMeshData;
|
||||
|
@ -156,6 +168,7 @@ class BenchmarkAppController extends DemoAppController<BenchmarkTestView> {
|
|||
|
||||
private pixelsPerEm: number;
|
||||
private elapsedTimes: ElapsedTime[];
|
||||
private partitionTime: number;
|
||||
|
||||
font: opentype.Font | null;
|
||||
textRun: TextRun<BenchmarkGlyph> | null;
|
||||
|
|
|
@ -156,7 +156,7 @@ class MeshDebuggerAppController extends AppController {
|
|||
|
||||
const glyph = new MeshDebuggerGlyph(opentypeGlyph);
|
||||
const glyphStorage = new GlyphStorage(this.fileData, [glyph], this.file);
|
||||
promise = glyphStorage.partition();
|
||||
promise = glyphStorage.partition().then(result => result.meshes);
|
||||
} else if (this.file instanceof SVGLoader) {
|
||||
promise = this.file.partition(this.fontPathSelect.selectedIndex);
|
||||
} else {
|
||||
|
|
|
@ -176,10 +176,10 @@ class TextDemoController extends DemoAppController<TextDemoView> {
|
|||
const newLayout = new SimpleTextLayout(fileData,
|
||||
this.text,
|
||||
glyph => new GlyphInstance(glyph));
|
||||
newLayout.glyphStorage.partition().then((meshes: PathfinderMeshData) => {
|
||||
newLayout.glyphStorage.partition().then(result => {
|
||||
this.view.then(view => {
|
||||
this.layout = newLayout;
|
||||
this.meshes = meshes;
|
||||
this.meshes = result.meshes;
|
||||
|
||||
view.attachText();
|
||||
view.uploadPathColors(1);
|
||||
|
|
|
@ -25,6 +25,11 @@ export interface ExpandedMeshData {
|
|||
meshes: PathfinderMeshData;
|
||||
}
|
||||
|
||||
export interface PartitionResult {
|
||||
meshes: PathfinderMeshData,
|
||||
time: number,
|
||||
}
|
||||
|
||||
type CreateGlyphFn<Glyph> = (glyph: opentype.Glyph) => Glyph;
|
||||
|
||||
export interface PixelMetrics {
|
||||
|
@ -250,7 +255,7 @@ export class GlyphStorage<Glyph extends PathfinderGlyph> {
|
|||
this.uniqueGlyphs = _.sortedUniqBy(this.uniqueGlyphs, glyph => glyph.index);
|
||||
}
|
||||
|
||||
partition(): Promise<PathfinderMeshData> {
|
||||
partition(): Promise<PartitionResult> {
|
||||
// Build the partitioning request to the server.
|
||||
//
|
||||
// FIXME(pcwalton): If this is a builtin font, don't resend it to the server!
|
||||
|
@ -278,7 +283,10 @@ export class GlyphStorage<Glyph extends PathfinderGlyph> {
|
|||
const response = JSON.parse(responseText);
|
||||
if (!('Ok' in response))
|
||||
panic("Failed to partition the font!");
|
||||
return new PathfinderMeshData(response.Ok.pathData);
|
||||
return {
|
||||
meshes: new PathfinderMeshData(response.Ok.pathData),
|
||||
time: response.Ok.time,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ use std::fs::File;
|
|||
use std::io::{self, Read};
|
||||
use std::mem;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::{Duration, Instant};
|
||||
use std::u32;
|
||||
|
||||
static STATIC_INDEX_PATH: &'static str = "../client/index.html";
|
||||
|
@ -152,6 +153,7 @@ struct PartitionFontResponse {
|
|||
glyph_info: Vec<PartitionGlyphInfo>,
|
||||
#[serde(rename = "pathData")]
|
||||
path_data: PartitionEncodedPathData,
|
||||
time: f64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||
|
@ -255,8 +257,17 @@ struct PartitionSvgPathsResponse {
|
|||
path_data: PartitionEncodedPathData,
|
||||
}
|
||||
|
||||
fn partition_paths(partitioner: &mut Partitioner, subpath_indices: &[SubpathRange])
|
||||
-> (PartitionEncodedPathData, Vec<PartitionPathIndices>) {
|
||||
struct PathPartitioningResult {
|
||||
encoded_data: PartitionEncodedPathData,
|
||||
indices: Vec<PartitionPathIndices>,
|
||||
time: Duration,
|
||||
}
|
||||
|
||||
impl PathPartitioningResult {
|
||||
fn compute(partitioner: &mut Partitioner, subpath_indices: &[SubpathRange])
|
||||
-> PathPartitioningResult {
|
||||
let timestamp_before = Instant::now();
|
||||
|
||||
let (mut b_quads, mut b_vertex_positions) = (vec![], vec![]);
|
||||
let (mut b_vertex_path_ids, mut b_vertex_loop_blinn_data) = (vec![], vec![]);
|
||||
let (mut cover_interior_indices, mut cover_curve_indices) = (vec![], vec![]);
|
||||
|
@ -274,7 +285,8 @@ fn partition_paths(partitioner: &mut Partitioner, subpath_indices: &[SubpathRang
|
|||
let cover_indices = partitioner.cover_indices();
|
||||
let edge_indices = partitioner.edge_indices();
|
||||
|
||||
let positions_start = IndexRange::from_data(&mut b_vertex_positions,
|
||||
let positions_start =
|
||||
IndexRange::from_data(&mut b_vertex_positions,
|
||||
path_b_vertex_positions).unwrap().start as u32;
|
||||
IndexRange::from_data(&mut b_vertex_path_ids, path_b_vertex_path_ids).unwrap();
|
||||
|
||||
|
@ -316,7 +328,8 @@ fn partition_paths(partitioner: &mut Partitioner, subpath_indices: &[SubpathRang
|
|||
&path_cover_interior_indices).unwrap(),
|
||||
cover_curve_indices: IndexRange::from_data(&mut cover_curve_indices,
|
||||
&path_cover_curve_indices).unwrap(),
|
||||
edge_upper_line_indices: IndexRange::from_data(&mut edge_upper_line_indices,
|
||||
edge_upper_line_indices:
|
||||
IndexRange::from_data(&mut edge_upper_line_indices,
|
||||
&path_edge_upper_line_indices).unwrap(),
|
||||
edge_upper_curve_indices:
|
||||
IndexRange::from_data(&mut edge_upper_curve_indices,
|
||||
|
@ -343,6 +356,8 @@ fn partition_paths(partitioner: &mut Partitioner, subpath_indices: &[SubpathRang
|
|||
}
|
||||
cover_interior_indices = new_cover_interior_indices;
|
||||
|
||||
let time_elapsed = timestamp_before.elapsed();
|
||||
|
||||
let encoded_path_data = PartitionEncodedPathData {
|
||||
b_quads: base64::encode(&b_quads),
|
||||
b_vertex_positions: base64::encode(&b_vertex_positions),
|
||||
|
@ -356,7 +371,12 @@ fn partition_paths(partitioner: &mut Partitioner, subpath_indices: &[SubpathRang
|
|||
edge_lower_curve_indices: base64::encode(&edge_lower_curve_indices),
|
||||
};
|
||||
|
||||
(encoded_path_data, path_indices)
|
||||
PathPartitioningResult {
|
||||
encoded_data: encoded_path_data,
|
||||
indices: path_indices,
|
||||
time: time_elapsed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[post("/partition-font", format = "application/json", data = "<request>")]
|
||||
|
@ -428,11 +448,14 @@ fn partition_font(request: Json<PartitionFontRequest>)
|
|||
// Partition the decoded glyph outlines.
|
||||
let mut partitioner = Partitioner::new();
|
||||
partitioner.init_with_path_buffer(&path_buffer);
|
||||
let (encoded_path_data, path_indices) = partition_paths(&mut partitioner, &subpath_indices);
|
||||
let path_partitioning_result = PathPartitioningResult::compute(&mut partitioner,
|
||||
&subpath_indices);
|
||||
|
||||
// Package up other miscellaneous glyph info.
|
||||
let mut glyph_info = vec![];
|
||||
for (glyph, glyph_path_indices) in request.glyphs.iter().zip(path_indices.iter()) {
|
||||
for (glyph, glyph_path_indices) in request.glyphs
|
||||
.iter()
|
||||
.zip(path_partitioning_result.indices.iter()) {
|
||||
let glyph_key = GlyphKey::new(glyph.id);
|
||||
|
||||
let dimensions = match font_context.glyph_dimensions(&font_instance_key, &glyph_key) {
|
||||
|
@ -453,10 +476,14 @@ fn partition_font(request: Json<PartitionFontRequest>)
|
|||
})
|
||||
}
|
||||
|
||||
let time = path_partitioning_result.time.as_secs() as f64 +
|
||||
path_partitioning_result.time.subsec_nanos() as f64 * 1e-9;
|
||||
|
||||
// Return the response.
|
||||
Json(Ok(PartitionFontResponse {
|
||||
glyph_info: glyph_info,
|
||||
path_data: encoded_path_data,
|
||||
path_data: path_partitioning_result.encoded_data,
|
||||
time: time,
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -531,12 +558,12 @@ fn partition_svg_paths(request: Json<PartitionSvgPathsRequest>)
|
|||
// Partition the paths.
|
||||
let mut partitioner = Partitioner::new();
|
||||
partitioner.init_with_path_buffer(&path_buffer);
|
||||
let (encoded_path_data, path_indices) = partition_paths(&mut partitioner, &paths);
|
||||
let path_partitioning_result = PathPartitioningResult::compute(&mut partitioner, &paths);
|
||||
|
||||
// Return the response.
|
||||
Json(Ok(PartitionSvgPathsResponse {
|
||||
path_indices: path_indices,
|
||||
path_data: encoded_path_data,
|
||||
path_indices: path_partitioning_result.indices,
|
||||
path_data: path_partitioning_result.encoded_data,
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue