mirror of
https://github.com/alacritty/alacritty.git
synced 2025-04-14 17:53:03 -04: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:
parent
6dc670cde0
commit
90552e3e7f
7 changed files with 81 additions and 34 deletions
|
@ -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
|
||||
- Incorrect built-in glyphs for `U+2567` and `U+2568`
|
||||
- Character mappings in the DEC special graphics character set (line drawing)
|
||||
- Window flickering on resize on Wayland
|
||||
|
||||
## 0.10.1
|
||||
|
||||
|
|
|
@ -237,7 +237,7 @@ pub struct 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) {
|
||||
if let Some(title) = &self.title {
|
||||
identity.title = title.clone();
|
||||
|
|
|
@ -359,6 +359,9 @@ pub struct Display {
|
|||
/// Unprocessed display updates.
|
||||
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,
|
||||
debug_damage: bool,
|
||||
damage_rects: Vec<DamageRect>,
|
||||
|
@ -367,6 +370,19 @@ pub struct Display {
|
|||
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 {
|
||||
pub fn new<E>(
|
||||
config: &UiConfig,
|
||||
|
@ -425,7 +441,7 @@ impl Display {
|
|||
// 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 (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 {
|
||||
(cell_width, cell_height)
|
||||
};
|
||||
|
@ -433,7 +449,7 @@ impl Display {
|
|||
// Load font common glyphs to accelerate rendering.
|
||||
debug!("Filling glyph cache with common glyphs");
|
||||
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) {
|
||||
|
@ -520,6 +536,7 @@ impl Display {
|
|||
visual_bell: VisualBell::from(&config.bell),
|
||||
colors: List::from(&config.colors),
|
||||
pending_update: Default::default(),
|
||||
pending_renderer_update: Default::default(),
|
||||
is_damage_supported,
|
||||
debug_damage,
|
||||
damage_rects,
|
||||
|
@ -529,30 +546,31 @@ impl Display {
|
|||
/// Update font size and cell dimensions.
|
||||
///
|
||||
/// This will return a tuple of the cell width and height.
|
||||
fn update_glyph_cache(
|
||||
renderer: &mut Renderer,
|
||||
fn update_font_size(
|
||||
glyph_cache: &mut GlyphCache,
|
||||
scale_factor: f64,
|
||||
config: &UiConfig,
|
||||
font: &Font,
|
||||
) -> (f32, f32) {
|
||||
renderer.with_loader(|mut api| {
|
||||
let _ = glyph_cache.update_font_size(font, scale_factor, &mut api);
|
||||
});
|
||||
let _ = glyph_cache.update_font_size(font, scale_factor);
|
||||
|
||||
// Compute new cell sizes.
|
||||
compute_cell_size(config, &glyph_cache.font_metrics())
|
||||
}
|
||||
|
||||
/// Clear glyph cache.
|
||||
fn clear_glyph_cache(&mut self) {
|
||||
/// Reset glyph cache.
|
||||
fn reset_glyph_cache(&mut self) {
|
||||
let cache = &mut self.glyph_cache;
|
||||
self.renderer.with_loader(|mut api| {
|
||||
cache.clear_glyph_cache(&mut api);
|
||||
cache.reset_glyph_cache(&mut api);
|
||||
});
|
||||
}
|
||||
|
||||
/// 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>(
|
||||
&mut self,
|
||||
terminal: &mut Term<T>,
|
||||
|
@ -568,31 +586,29 @@ impl Display {
|
|||
let (mut cell_width, mut cell_height) =
|
||||
(self.size_info.cell_width(), self.size_info.cell_height());
|
||||
|
||||
// Ensure we're modifying the correct OpenGL context.
|
||||
self.window.make_current();
|
||||
if pending_update.font().is_some() || pending_update.cursor_dirty() {
|
||||
let renderer_update = self.pending_renderer_update.get_or_insert(Default::default());
|
||||
renderer_update.clear_font_cache = true
|
||||
}
|
||||
|
||||
// Update font size and cell dimensions.
|
||||
if let Some(font) = pending_update.font() {
|
||||
let scale_factor = self.window.scale_factor;
|
||||
let cell_dimensions = Self::update_glyph_cache(
|
||||
&mut self.renderer,
|
||||
&mut self.glyph_cache,
|
||||
scale_factor,
|
||||
config,
|
||||
font,
|
||||
);
|
||||
let cell_dimensions =
|
||||
Self::update_font_size(&mut self.glyph_cache, scale_factor, config, font);
|
||||
cell_width = cell_dimensions.0;
|
||||
cell_height = cell_dimensions.1;
|
||||
|
||||
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());
|
||||
if let Some(dimensions) = pending_update.dimensions() {
|
||||
width = dimensions.width 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);
|
||||
|
@ -618,10 +634,36 @@ impl Display {
|
|||
|
||||
// Resize terminal.
|
||||
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.
|
||||
let physical = PhysicalSize::new(self.size_info.width() as _, self.size_info.height() as _);
|
||||
self.window.resize(physical);
|
||||
if renderer_update.resize {
|
||||
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);
|
||||
|
||||
if self.collect_damage() {
|
||||
|
|
|
@ -463,7 +463,7 @@ pub struct TextShaderProgram {
|
|||
///
|
||||
/// 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
|
||||
/// 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.
|
||||
u_rendering_pass: GLint,
|
||||
|
|
|
@ -264,19 +264,22 @@ impl GlyphCache {
|
|||
loader.load_glyph(&glyph)
|
||||
}
|
||||
|
||||
/// Clear currently cached data in both GL and the registry.
|
||||
pub fn clear_glyph_cache<L: LoadGlyph>(&mut self, loader: &mut L) {
|
||||
/// Reset currently cached data in both GL and the registry to default state.
|
||||
pub fn reset_glyph_cache<L: LoadGlyph>(&mut self, loader: &mut L) {
|
||||
loader.clear();
|
||||
self.cache = HashMap::default();
|
||||
self.cache = Default::default();
|
||||
|
||||
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,
|
||||
font: &Font,
|
||||
scale_factor: f64,
|
||||
loader: &mut L,
|
||||
) -> Result<(), crossfont::Error> {
|
||||
// Update dpi scaling.
|
||||
self.rasterizer.update_dpr(scale_factor as f32);
|
||||
|
@ -304,8 +307,6 @@ impl GlyphCache {
|
|||
self.metrics = metrics;
|
||||
self.builtin_box_drawing = font.builtin_box_drawing;
|
||||
|
||||
self.clear_glyph_cache(loader);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -325,6 +325,9 @@ impl WindowContext {
|
|||
}
|
||||
|
||||
if self.dirty {
|
||||
// Force the display to process any pending display update.
|
||||
self.display.process_renderer_update();
|
||||
|
||||
self.dirty = false;
|
||||
|
||||
// Request immediate re-draw if visual bell animation is not finished yet.
|
||||
|
|
|
@ -20,8 +20,8 @@ pub struct Rgb {
|
|||
}
|
||||
|
||||
impl Rgb {
|
||||
/// Implementation of W3C's luminance algorithm:
|
||||
/// https://www.w3.org/TR/WCAG20/#relativeluminancedef
|
||||
/// Implementation of W3C's luminance
|
||||
/// [algorithm](https://www.w3.org/TR/WCAG20/#relativeluminancedef)
|
||||
fn luminance(self) -> f64 {
|
||||
let channel_luminance = |channel| {
|
||||
let channel = channel as f64 / 255.;
|
||||
|
|
Loading…
Add table
Reference in a new issue