1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-22 22:42:48 +03:00

wezterm: add excess padding for image protocols

When allocating space in the texture atlas, we typically use
a small padding to avoid accidentally interpolating textures
into glyphs.

When it comes to rendering images via iterm2 or sixel image
protocols, the image emitted by the user may not exactly fill
the cell dimensions, and due to the how the shader works to
apply those textures we could end up revealing nearby images
in the texture when displaying an unrelated image.

This commit adjusts the texture atlas allocation when making
space for image protocol textures; excess padding based on
an overestimate of the cell dimensions is added to the right
and bottom of the image, guaranteeing that that border will
be filled with transparent pixels.

This is a bit wasteful of texture space, but isn't egregiously
bad and is easy to reason about and makes things look less
janky.

refs: #292
This commit is contained in:
Wez Furlong 2020-10-24 12:46:49 -07:00
parent e2bf111426
commit 52908712c6
3 changed files with 36 additions and 6 deletions

View File

@ -253,7 +253,11 @@ impl<T: Texture2d> GlyphCache<T> {
Ok(Rc::new(glyph))
}
pub fn cached_image(&mut self, image_data: &Arc<ImageData>) -> anyhow::Result<Sprite<T>> {
pub fn cached_image(
&mut self,
image_data: &Arc<ImageData>,
padding: Option<usize>,
) -> anyhow::Result<Sprite<T>> {
if let Some(sprite) = self.image_cache.get(&image_data.id()) {
return Ok(sprite.clone());
}
@ -266,7 +270,7 @@ impl<T: Texture2d> GlyphCache<T> {
decoded_image.to_vec(),
);
let sprite = self.atlas.allocate(&image)?;
let sprite = self.atlas.allocate_with_padding(&image, padding)?;
self.image_cache.insert(image_data.id(), sprite.clone());

View File

@ -2501,7 +2501,7 @@ impl TermWindow {
quad.set_texture(white_space);
if let Some(im) = self.window_background.as_ref() {
let sprite = gl_state.glyph_cache.borrow_mut().cached_image(im)?;
let sprite = gl_state.glyph_cache.borrow_mut().cached_image(im, None)?;
quad.set_texture(sprite.texture_coords());
quad.set_is_background_image();
}
@ -2832,10 +2832,22 @@ impl TermWindow {
if let Some(image) = attrs.image() {
// Render iTerm2 style image attributes
let padding = self
.render_metrics
.cell_size
.height
.max(self.render_metrics.cell_size.width)
as usize;
let padding = if padding.is_power_of_two() {
padding
} else {
padding.next_power_of_two()
};
let sprite = gl_state
.glyph_cache
.borrow_mut()
.cached_image(image.image_data())?;
.cached_image(image.image_data(), Some(padding))?;
let width = sprite.coords.size.width;
let height = sprite.coords.size.height;

View File

@ -39,6 +39,12 @@ where
"texture must be square!"
);
let side = texture.width();
let iside = side as isize;
let image = crate::Image::new(side, side);
let rect = Rect::new(Point::new(0, 0), Size::new(iside, iside));
texture.write(rect, &image);
let allocator = AtlasAllocator::new(AtlasSize::new(side.try_into()?, side.try_into()?));
Ok(Self {
texture: Rc::clone(texture),
@ -54,6 +60,14 @@ where
/// Reserve space for a sprite of the given size
pub fn allocate(&mut self, im: &dyn BitmapImage) -> Result<Sprite<T>, OutOfTextureSpace> {
self.allocate_with_padding(im, None)
}
pub fn allocate_with_padding(
&mut self,
im: &dyn BitmapImage,
padding: Option<usize>,
) -> Result<Sprite<T>, OutOfTextureSpace> {
let (width, height) = im.image_dimensions();
// If we can't convert the sizes to i32, then we'll never
@ -68,8 +82,8 @@ where
// We pad each sprite reservation with blank space to avoid
// surprising and unexpected artifacts when the texture is
// interpolated on to the render surface.
let reserve_width = reserve_width + PADDING * 2;
let reserve_height = reserve_height + PADDING * 2;
let reserve_width = reserve_width + padding.unwrap_or(0) as i32 + PADDING * 2;
let reserve_height = reserve_height + padding.unwrap_or(0) as i32 + PADDING * 2;
if let Some(allocation) = self
.allocator