1
0
Fork 0
mirror of https://github.com/alacritty/alacritty.git synced 2024-11-11 13:51:01 -05:00

Fix flickering during resize on Wayland

This also fixes an issue of windows not being rendered while resizing.

Fixes #6069.
This commit is contained in:
Kirill Chibisov 2022-06-09 19:31:08 +03:00 committed by GitHub
parent 6dc670cde0
commit 90552e3e7f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 81 additions and 34 deletions

View file

@ -38,6 +38,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Bottom gap for certain builtin box drawing characters - Bottom gap for certain builtin box drawing characters
- Incorrect built-in glyphs for `U+2567` and `U+2568` - Incorrect built-in glyphs for `U+2567` and `U+2568`
- Character mappings in the DEC special graphics character set (line drawing) - Character mappings in the DEC special graphics character set (line drawing)
- Window flickering on resize on Wayland
## 0.10.1 ## 0.10.1

View file

@ -237,7 +237,7 @@ pub struct WindowIdentity {
} }
impl WindowIdentity { impl WindowIdentity {
/// Override the [`WindowIdentityConfig`]'s fields with the [`WindowOptions`]. /// Override the [`WindowIdentity`]'s fields with the [`WindowOptions`].
pub fn override_identity_config(&self, identity: &mut Identity) { pub fn override_identity_config(&self, identity: &mut Identity) {
if let Some(title) = &self.title { if let Some(title) = &self.title {
identity.title = title.clone(); identity.title = title.clone();

View file

@ -359,6 +359,9 @@ pub struct Display {
/// Unprocessed display updates. /// Unprocessed display updates.
pub pending_update: DisplayUpdate, pub pending_update: DisplayUpdate,
/// The renderer update that takes place only once before the actual rendering.
pub pending_renderer_update: Option<RendererUpdate>,
is_damage_supported: bool, is_damage_supported: bool,
debug_damage: bool, debug_damage: bool,
damage_rects: Vec<DamageRect>, damage_rects: Vec<DamageRect>,
@ -367,6 +370,19 @@ pub struct Display {
meter: Meter, meter: Meter,
} }
/// Pending renderer updates.
///
/// All renderer updates are cached to be applied just before rendering, to avoid platform-specific
/// rendering issues.
#[derive(Debug, Default, Copy, Clone)]
pub struct RendererUpdate {
/// Should resize the window.
resize: bool,
/// Clear font caches.
clear_font_cache: bool,
}
impl Display { impl Display {
pub fn new<E>( pub fn new<E>(
config: &UiConfig, config: &UiConfig,
@ -425,7 +441,7 @@ impl Display {
// If the scaling factor changed update the glyph cache and mark for resize. // If the scaling factor changed update the glyph cache and mark for resize.
let should_resize = (estimated_scale_factor - window.scale_factor).abs() > f64::EPSILON; let should_resize = (estimated_scale_factor - window.scale_factor).abs() > f64::EPSILON;
let (cell_width, cell_height) = if should_resize { let (cell_width, cell_height) = if should_resize {
Self::update_glyph_cache(&mut renderer, &mut glyph_cache, scale_factor, config, font) Self::update_font_size(&mut glyph_cache, scale_factor, config, font)
} else { } else {
(cell_width, cell_height) (cell_width, cell_height)
}; };
@ -433,7 +449,7 @@ impl Display {
// Load font common glyphs to accelerate rendering. // Load font common glyphs to accelerate rendering.
debug!("Filling glyph cache with common glyphs"); debug!("Filling glyph cache with common glyphs");
renderer.with_loader(|mut api| { renderer.with_loader(|mut api| {
glyph_cache.load_common_glyphs(&mut api); glyph_cache.reset_glyph_cache(&mut api);
}); });
if let Some(dimensions) = dimensions.filter(|_| should_resize) { if let Some(dimensions) = dimensions.filter(|_| should_resize) {
@ -520,6 +536,7 @@ impl Display {
visual_bell: VisualBell::from(&config.bell), visual_bell: VisualBell::from(&config.bell),
colors: List::from(&config.colors), colors: List::from(&config.colors),
pending_update: Default::default(), pending_update: Default::default(),
pending_renderer_update: Default::default(),
is_damage_supported, is_damage_supported,
debug_damage, debug_damage,
damage_rects, damage_rects,
@ -529,30 +546,31 @@ impl Display {
/// Update font size and cell dimensions. /// Update font size and cell dimensions.
/// ///
/// This will return a tuple of the cell width and height. /// This will return a tuple of the cell width and height.
fn update_glyph_cache( fn update_font_size(
renderer: &mut Renderer,
glyph_cache: &mut GlyphCache, glyph_cache: &mut GlyphCache,
scale_factor: f64, scale_factor: f64,
config: &UiConfig, config: &UiConfig,
font: &Font, font: &Font,
) -> (f32, f32) { ) -> (f32, f32) {
renderer.with_loader(|mut api| { let _ = glyph_cache.update_font_size(font, scale_factor);
let _ = glyph_cache.update_font_size(font, scale_factor, &mut api);
});
// Compute new cell sizes. // Compute new cell sizes.
compute_cell_size(config, &glyph_cache.font_metrics()) compute_cell_size(config, &glyph_cache.font_metrics())
} }
/// Clear glyph cache. /// Reset glyph cache.
fn clear_glyph_cache(&mut self) { fn reset_glyph_cache(&mut self) {
let cache = &mut self.glyph_cache; let cache = &mut self.glyph_cache;
self.renderer.with_loader(|mut api| { self.renderer.with_loader(|mut api| {
cache.clear_glyph_cache(&mut api); cache.reset_glyph_cache(&mut api);
}); });
} }
/// Process update events. /// Process update events.
///
/// XXX: this function must not call to any `OpenGL` related tasks. Only logical update
/// of the state is being performed here. Rendering update takes part right before the
/// actual rendering.
pub fn handle_update<T>( pub fn handle_update<T>(
&mut self, &mut self,
terminal: &mut Term<T>, terminal: &mut Term<T>,
@ -568,31 +586,29 @@ impl Display {
let (mut cell_width, mut cell_height) = let (mut cell_width, mut cell_height) =
(self.size_info.cell_width(), self.size_info.cell_height()); (self.size_info.cell_width(), self.size_info.cell_height());
// Ensure we're modifying the correct OpenGL context. if pending_update.font().is_some() || pending_update.cursor_dirty() {
self.window.make_current(); let renderer_update = self.pending_renderer_update.get_or_insert(Default::default());
renderer_update.clear_font_cache = true
}
// Update font size and cell dimensions. // Update font size and cell dimensions.
if let Some(font) = pending_update.font() { if let Some(font) = pending_update.font() {
let scale_factor = self.window.scale_factor; let scale_factor = self.window.scale_factor;
let cell_dimensions = Self::update_glyph_cache( let cell_dimensions =
&mut self.renderer, Self::update_font_size(&mut self.glyph_cache, scale_factor, config, font);
&mut self.glyph_cache,
scale_factor,
config,
font,
);
cell_width = cell_dimensions.0; cell_width = cell_dimensions.0;
cell_height = cell_dimensions.1; cell_height = cell_dimensions.1;
info!("Cell size: {} x {}", cell_width, cell_height); info!("Cell size: {} x {}", cell_width, cell_height);
} else if pending_update.cursor_dirty() {
self.clear_glyph_cache();
} }
let (mut width, mut height) = (self.size_info.width(), self.size_info.height()); let (mut width, mut height) = (self.size_info.width(), self.size_info.height());
if let Some(dimensions) = pending_update.dimensions() { if let Some(dimensions) = pending_update.dimensions() {
width = dimensions.width as f32; width = dimensions.width as f32;
height = dimensions.height as f32; height = dimensions.height as f32;
let renderer_update = self.pending_renderer_update.get_or_insert(Default::default());
renderer_update.resize = true
} }
let padding = config.window.padding(self.window.scale_factor); let padding = config.window.padding(self.window.scale_factor);
@ -618,10 +634,36 @@ impl Display {
// Resize terminal. // Resize terminal.
terminal.resize(self.size_info); terminal.resize(self.size_info);
}
/// Update the state of the renderer.
///
/// NOTE: The update to the renderer is split from the display update on purpose, since
/// on some platforms, like Wayland, resize and other OpenGL operations must be performed
/// right before rendering, otherwise they could lock the back buffer resulting in
/// rendering with the buffer of old size.
///
/// This also resolves any flickering, since the resize is now synced with frame callbacks.
pub fn process_renderer_update(&mut self) {
let renderer_update = match self.pending_renderer_update.take() {
Some(renderer_update) => renderer_update,
_ => return,
};
// Resize renderer. // Resize renderer.
let physical = PhysicalSize::new(self.size_info.width() as _, self.size_info.height() as _); if renderer_update.resize {
self.window.resize(physical); let physical =
PhysicalSize::new(self.size_info.width() as _, self.size_info.height() as _);
self.window.resize(physical);
}
// Ensure we're modifying the correct OpenGL context.
self.window.make_current();
if renderer_update.clear_font_cache {
self.reset_glyph_cache();
}
self.renderer.resize(&self.size_info); self.renderer.resize(&self.size_info);
if self.collect_damage() { if self.collect_damage() {

View file

@ -463,7 +463,7 @@ pub struct TextShaderProgram {
/// ///
/// If GL_EXT_blend_func_extended is not available, the rendering is split into 4 passes. /// If GL_EXT_blend_func_extended is not available, the rendering is split into 4 passes.
/// One is used for the background and the rest to perform subpixel text rendering according to /// One is used for the background and the rest to perform subpixel text rendering according to
/// https://github.com/servo/webrender/blob/master/webrender/doc/text-rendering.md. /// <https://github.com/servo/webrender/blob/master/webrender/doc/text-rendering.md>.
/// ///
/// Rendering is split into three passes. /// Rendering is split into three passes.
u_rendering_pass: GLint, u_rendering_pass: GLint,

View file

@ -264,19 +264,22 @@ impl GlyphCache {
loader.load_glyph(&glyph) loader.load_glyph(&glyph)
} }
/// Clear currently cached data in both GL and the registry. /// Reset currently cached data in both GL and the registry to default state.
pub fn clear_glyph_cache<L: LoadGlyph>(&mut self, loader: &mut L) { pub fn reset_glyph_cache<L: LoadGlyph>(&mut self, loader: &mut L) {
loader.clear(); loader.clear();
self.cache = HashMap::default(); self.cache = Default::default();
self.load_common_glyphs(loader); self.load_common_glyphs(loader);
} }
pub fn update_font_size<L: LoadGlyph>( /// Update the inner font size.
///
/// NOTE: To reload the renderers's fonts [`Self::reset_glyph_cache`] should be called
/// afterwards.
pub fn update_font_size(
&mut self, &mut self,
font: &Font, font: &Font,
scale_factor: f64, scale_factor: f64,
loader: &mut L,
) -> Result<(), crossfont::Error> { ) -> Result<(), crossfont::Error> {
// Update dpi scaling. // Update dpi scaling.
self.rasterizer.update_dpr(scale_factor as f32); self.rasterizer.update_dpr(scale_factor as f32);
@ -304,8 +307,6 @@ impl GlyphCache {
self.metrics = metrics; self.metrics = metrics;
self.builtin_box_drawing = font.builtin_box_drawing; self.builtin_box_drawing = font.builtin_box_drawing;
self.clear_glyph_cache(loader);
Ok(()) Ok(())
} }

View file

@ -325,6 +325,9 @@ impl WindowContext {
} }
if self.dirty { if self.dirty {
// Force the display to process any pending display update.
self.display.process_renderer_update();
self.dirty = false; self.dirty = false;
// Request immediate re-draw if visual bell animation is not finished yet. // Request immediate re-draw if visual bell animation is not finished yet.

View file

@ -20,8 +20,8 @@ pub struct Rgb {
} }
impl Rgb { impl Rgb {
/// Implementation of W3C's luminance algorithm: /// Implementation of W3C's luminance
/// https://www.w3.org/TR/WCAG20/#relativeluminancedef /// [algorithm](https://www.w3.org/TR/WCAG20/#relativeluminancedef)
fn luminance(self) -> f64 { fn luminance(self) -> f64 {
let channel_luminance = |channel| { let channel_luminance = |channel| {
let channel = channel as f64 / 255.; let channel = channel as f64 / 255.;