Skip to content

Commit

Permalink
improve texture upload performance
Browse files Browse the repository at this point in the history
Two issues highlighted by profiling:

* Clearing the texture takes a non-trivial percentage of the profile.
  The docs suggest that it is better to create a new texture than
  to update large portions of a texture, so add some plumbing so
  that we can do that in the first texture-full case.

* Next on the list is the code that translates from linear BGRA to
  SRGBA.  This is present for reasons that I believe are now legacy,
  but for the moment: those two primitives now have faster and
  easier implementations, so simplify to those.

This improves the timg video playback performance by ~10% for me.

refs: #537
  • Loading branch information
wez committed Mar 14, 2021
1 parent 693a717 commit b8dcfba
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 22 deletions.
7 changes: 5 additions & 2 deletions wezterm-gui/src/renderstate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,12 @@ impl RenderState {
quads,
});
}
Err(OutOfTextureSpace { size: Some(size) }) => {
Err(OutOfTextureSpace {
size: Some(size), ..
}) => {
atlas_size = size;
}
Err(OutOfTextureSpace { size: None }) => {
Err(OutOfTextureSpace { size: None, .. }) => {
anyhow::bail!("requested texture size is impossible!?")
}
};
Expand Down Expand Up @@ -326,6 +328,7 @@ impl RenderState {

if let Some(&OutOfTextureSpace {
size: Some(needed_size),
..
}) = err.downcast_ref::<OutOfTextureSpace>()
{
size.replace(needed_size);
Expand Down
9 changes: 6 additions & 3 deletions wezterm-gui/src/termwindow/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,15 @@ impl super::TermWindow {
match self.paint_opengl_pass() {
Ok(_) => break,
Err(err) => {
if let Some(&OutOfTextureSpace { size: Some(size) }) =
err.downcast_ref::<OutOfTextureSpace>()
if let Some(&OutOfTextureSpace {
size: Some(size),
current_size,
}) = err.downcast_ref::<OutOfTextureSpace>()
{
let result = if pass == 0 {
// Let's try clearing out the atlas and trying again
self.clear_texture_atlas()
// self.clear_texture_atlas()
self.recreate_texture_atlas(Some(current_size))
} else {
log::trace!("grow texture atlas to {}", size);
self.recreate_texture_atlas(Some(size))
Expand Down
16 changes: 10 additions & 6 deletions window/src/bitmaps/atlas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const PADDING: i32 = 1;
#[error("Texture Size exceeded, need {:?}", size)]
pub struct OutOfTextureSpace {
pub size: Option<usize>,
pub current_size: usize,
}

/// Atlases are bitmaps of srgba data that are sized as a power of 2.
Expand Down Expand Up @@ -72,12 +73,14 @@ where

// If we can't convert the sizes to i32, then we'll never
// be able to store this image
let reserve_width: i32 = width
.try_into()
.map_err(|_| OutOfTextureSpace { size: None })?;
let reserve_height: i32 = height
.try_into()
.map_err(|_| OutOfTextureSpace { size: None })?;
let reserve_width: i32 = width.try_into().map_err(|_| OutOfTextureSpace {
size: None,
current_size: self.side,
})?;
let reserve_height: i32 = height.try_into().map_err(|_| OutOfTextureSpace {
size: None,
current_size: self.side,
})?;

// We pad each sprite reservation with blank space to avoid
// surprising and unexpected artifacts when the texture is
Expand Down Expand Up @@ -107,6 +110,7 @@ where
let size = (reserve_width.max(reserve_height) as usize).next_power_of_two();
Err(OutOfTextureSpace {
size: Some((self.side * 2).max(size)),
current_size: self.side,
})
}
}
Expand Down
22 changes: 11 additions & 11 deletions window/src/bitmaps/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,30 +55,30 @@ impl Texture2d for SrgbTexture2d {
.pixels()
.iter()
.map(|&p| {
let (r, g, b, a) = Color(p).as_rgba();
// convert from linear to srgb.
// This brightens up the emoji glyphs so that the
// colors match those of the software renderer and
// other terminal emulators.
// I haven't run down exactly why this is needed but
// suspect that it would be resolved if we could teach
// glium to use SRGB for the texture.
fn conv(v: u8) -> u8 {
let f = (v as f32) / 255.;
let c = if f <= 0.003_130_8 {
f * 12.92
} else {
f.powf(1.0 / 2.4) * 1.055 - 0.055
};
(c * 255.).ceil() as u8
}
Color::rgba(conv(b), conv(g), conv(r), conv(a)).0
let (r, g, b, a) = Color(p).as_rgba();
// Switch from bgra to rgba
Color::with_linear_rgba_u8(b, g, r, a).0
})
.collect(),
width: im_width as u32,
height: im_height as u32,
format: glium::texture::ClientFormat::U8U8U8U8,
};
/* Aspirationally, we want this:
let source = glium::texture::RawImage2d {
data: std::borrow::Cow::Borrowed(im .pixels()),
width: im_width as u32,
height: im_height as u32,
format: glium::texture::ClientFormat::U8U8U8U8,
};
*/

SrgbTexture2d::write(
self,
Expand Down

0 comments on commit b8dcfba

Please sign in to comment.