From ecd3717bbfd28883eb1729ac8abf664b115da85f Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 9 Jan 2024 12:25:53 -0800 Subject: [PATCH] Update to `softbuffer` 0.3, tracking up to `age` sets of primitives --- Cargo.toml | 2 +- renderer/src/compositor.rs | 1 + tiny_skia/src/window/compositor.rs | 121 ++++++++++++++++++----------- 3 files changed, 79 insertions(+), 45 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0afbcd513d..d86dae5d1c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -145,7 +145,7 @@ raw-window-handle = "0.5" resvg = "0.36" rustc-hash = "1.0" smol = "1.0" -softbuffer = "0.2" +softbuffer = "0.3.4" syntect = "5.1" sysinfo = "0.28" thiserror = "1.0" diff --git a/renderer/src/compositor.rs b/renderer/src/compositor.rs index 9d0ff9ab3c..f9afdea484 100644 --- a/renderer/src/compositor.rs +++ b/renderer/src/compositor.rs @@ -238,6 +238,7 @@ impl Candidate { default_font: settings.default_font, default_text_size: settings.default_text_size, }, + _compatible_window, ); Ok(Compositor::TinySkia(compositor)) diff --git a/tiny_skia/src/window/compositor.rs b/tiny_skia/src/window/compositor.rs index 87ded74640..d99b85d44b 100644 --- a/tiny_skia/src/window/compositor.rs +++ b/tiny_skia/src/window/compositor.rs @@ -5,18 +5,21 @@ use crate::graphics::{Error, Viewport}; use crate::{Backend, Primitive, Renderer, Settings}; use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle}; +use std::collections::VecDeque; use std::marker::PhantomData; +use std::num::NonZeroU32; pub struct Compositor { + context: Option, settings: Settings, _theme: PhantomData, } pub struct Surface { - window: softbuffer::GraphicsContext, - buffer: Vec, + window: softbuffer::Surface, clip_mask: tiny_skia::Mask, - primitives: Option>, + // Primitives of existing buffers, by decreasing age + primitives: VecDeque>, background_color: Color, } @@ -27,9 +30,9 @@ impl crate::graphics::Compositor for Compositor { fn new( settings: Self::Settings, - _compatible_window: Option<&W>, + compatible_window: Option<&W>, ) -> Result { - Ok(new(settings)) + Ok(new(settings, compatible_window)) } fn create_renderer(&self) -> Self::Renderer { @@ -47,16 +50,21 @@ impl crate::graphics::Compositor for Compositor { height: u32, ) -> Surface { #[allow(unsafe_code)] - let window = - unsafe { softbuffer::GraphicsContext::new(window, window) } - .expect("Create softbuffer for window"); + let window = if let Some(context) = self.context.as_ref() { + unsafe { softbuffer::Surface::new(context, window) } + .expect("Create softbuffer surface for window") + } else { + let context = unsafe { softbuffer::Context::new(window) } + .expect("Create softbuffer context for window"); + unsafe { softbuffer::Surface::new(&context, window) } + .expect("Create softbuffer surface for window") + }; Surface { window, - buffer: vec![0; width as usize * height as usize], clip_mask: tiny_skia::Mask::new(width, height) .expect("Create clip mask"), - primitives: None, + primitives: VecDeque::new(), background_color: Color::BLACK, } } @@ -67,10 +75,9 @@ impl crate::graphics::Compositor for Compositor { width: u32, height: u32, ) { - surface.buffer.resize((width * height) as usize, 0); surface.clip_mask = tiny_skia::Mask::new(width, height).expect("Create clip mask"); - surface.primitives = None; + surface.primitives.clear(); } fn fetch_information(&self) -> Information { @@ -121,8 +128,15 @@ impl crate::graphics::Compositor for Compositor { } } -pub fn new(settings: Settings) -> Compositor { +pub fn new( + settings: Settings, + compatible_window: Option<&W>, +) -> Compositor { + #[allow(unsafe_code)] + let context = compatible_window + .and_then(|w| unsafe { softbuffer::Context::new(w) }.ok()); Compositor { + context, settings, _theme: PhantomData, } @@ -139,48 +153,67 @@ pub fn present>( let physical_size = viewport.physical_size(); let scale_factor = viewport.scale_factor() as f32; - let mut pixels = tiny_skia::PixmapMut::from_bytes( - bytemuck::cast_slice_mut(&mut surface.buffer), - physical_size.width, - physical_size.height, - ) - .expect("Create pixel map"); + surface + .window + .resize( + NonZeroU32::new(physical_size.width).unwrap(), + NonZeroU32::new(physical_size.height).unwrap(), + ) + .unwrap(); + + // TODO Add variants to `SurfaceError`? + let mut buffer = surface + .window + .buffer_mut() + .map_err(|_| compositor::SurfaceError::Lost)?; + + let age = buffer.age(); - let damage = surface - .primitives - .as_deref() + // Forget primatives for back buffers older than `age` + // Or if this is a new buffer, keep at most two. + let max = if age == 0 { 2 } else { age }; + while surface.primitives.len() as u8 > max { + let _ = surface.primitives.pop_front(); + } + + let last_primitives = if surface.primitives.len() as u8 == age { + surface.primitives.pop_front() + } else { + None + }; + + let damage = last_primitives .and_then(|last_primitives| { (surface.background_color == background_color) - .then(|| damage::list(last_primitives, primitives)) + .then(|| damage::list(&last_primitives, primitives)) }) .unwrap_or_else(|| vec![Rectangle::with_size(viewport.logical_size())]); - if damage.is_empty() { - return Ok(()); - } - - surface.primitives = Some(primitives.to_vec()); + surface.primitives.push_back(primitives.to_vec()); surface.background_color = background_color; - let damage = damage::group(damage, scale_factor, physical_size); + if !damage.is_empty() { + let damage = damage::group(damage, scale_factor, physical_size); - backend.draw( - &mut pixels, - &mut surface.clip_mask, - primitives, - viewport, - &damage, - background_color, - overlay, - ); + let mut pixels = tiny_skia::PixmapMut::from_bytes( + bytemuck::cast_slice_mut(&mut buffer), + physical_size.width, + physical_size.height, + ) + .expect("Create pixel map"); - surface.window.set_buffer( - &surface.buffer, - physical_size.width as u16, - physical_size.height as u16, - ); + backend.draw( + &mut pixels, + &mut surface.clip_mask, + primitives, + viewport, + &damage, + background_color, + overlay, + ); + } - Ok(()) + buffer.present().map_err(|_| compositor::SurfaceError::Lost) } pub fn screenshot>(