1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-22 21:01:36 +03:00

perf: adjust clustering when bidi is disabled

When a line is rapidly updated with only some of the cells being
actually changed (eg: progress counter or other status being frequently
updated), it is desirable to avoid paying the cost of shaping the entire
line.

When bidi is not enabled we can assume that it is safe to break clusters
on whitespace boundaries. Doing so allows each of those whitespace
separated words to be shaped and potentially cached independently,
which reduces the amount of CPU time spent for the whole line.

This commit just adjusts the clustering, which reduces the CPU
utilization a bit.

refs: https://github.com/wez/wezterm/issues/2701
This commit is contained in:
Wez Furlong 2022-11-13 20:10:10 -07:00
parent 0516b61f62
commit 831eda86b9
No known key found for this signature in database
2 changed files with 58 additions and 42 deletions

View File

@ -102,17 +102,29 @@ impl CellCluster {
// the terminal is wide and a long series of short lines are printed;
// the shaper can cache the few variations of trailing whitespace
// and focus on shaping the shorter cluster sequences.
// Or:
// when bidi is disabled, force break on whitespace boundaries.
// This reduces shaping load in the case where is a line is
// updated continually, but only a portion of it changes
// (eg: progress counter).
let was_whitespace = whitespace_run > 0;
if cell_str == " " {
whitespace_run += 1;
} else {
whitespace_run = 0;
only_whitespace = false;
}
if !only_whitespace && whitespace_run > 2 {
let force_break = (!only_whitespace && whitespace_run > 2)
|| (!only_whitespace && bidi_hint.is_none() && was_whitespace);
if force_break {
clusters.push(last);
only_whitespace = cell_str == " ";
whitespace_run = 1;
if whitespace_run > 0 {
whitespace_run = 1;
}
Some(CellCluster::new(
hint,
presentation,

View File

@ -128,7 +128,6 @@ mod test {
use crate::shapecache::{GlyphPosition, ShapedInfo};
use crate::utilsprites::RenderMetrics;
use config::{FontAttributes, TextStyle};
use k9::assert_equal as assert_eq;
use std::rc::Rc;
use termwiz::cell::CellAttributes;
use termwiz::surface::{Line, SEQ_ZERO};
@ -149,48 +148,53 @@ mod test {
{
let line = Line::from_text(text, &CellAttributes::default(), SEQ_ZERO, None);
eprintln!("{:?}", line);
let cell_clusters = line.cluster(None);
assert_eq!(cell_clusters.len(), 1);
let cluster = &cell_clusters[0];
let presentation_width = PresentationWidth::with_cluster(&cluster);
let infos = font
.shape(
&cluster.text,
|| {},
|_| {},
None,
Direction::LeftToRight,
None,
Some(&presentation_width),
)
.unwrap();
let glyphs = infos
.iter()
.map(|info| {
let cell_idx = cluster.byte_to_cell_idx(info.cluster as usize);
let num_cells = cluster.byte_to_cell_width(info.cluster as usize);
let mut all_infos = vec![];
let mut all_glyphs = vec![];
let followed_by_space = match line.get_cell(cell_idx + 1) {
Some(cell) => cell.str() == " ",
None => false,
};
for cluster in line.cluster(None) {
let presentation_width = PresentationWidth::with_cluster(&cluster);
let mut infos = font
.shape(
&cluster.text,
|| {},
|_| {},
None,
Direction::LeftToRight,
None,
Some(&presentation_width),
)
.unwrap();
let mut glyphs = infos
.iter()
.map(|info| {
let cell_idx = cluster.byte_to_cell_idx(info.cluster as usize);
let num_cells = cluster.byte_to_cell_width(info.cluster as usize);
glyph_cache
.cached_glyph(
info,
&style,
followed_by_space,
font,
render_metrics,
num_cells,
)
.unwrap()
})
.collect::<Vec<_>>();
let followed_by_space = match line.get_cell(cell_idx + 1) {
Some(cell) => cell.str() == " ",
None => false,
};
eprintln!("infos: {:#?}", infos);
eprintln!("glyphs: {:#?}", glyphs);
ShapedInfo::process(&infos, &glyphs)
glyph_cache
.cached_glyph(
info,
&style,
followed_by_space,
font,
render_metrics,
num_cells,
)
.unwrap()
})
.collect::<Vec<_>>();
all_infos.append(&mut infos);
all_glyphs.append(&mut glyphs);
}
eprintln!("infos: {:#?}", all_infos);
eprintln!("glyphs: {:#?}", all_glyphs);
ShapedInfo::process(&all_infos, &all_glyphs)
.into_iter()
.map(|p| p.pos)
.collect()