1
0
Fork 0
forked from wry/wry

metal: track per-framebuffer damage

This commit is contained in:
Julian Orth 2025-02-18 16:43:30 +01:00
parent f80ac20220
commit 07fb198eb4
17 changed files with 334 additions and 151 deletions

View file

@ -4,6 +4,7 @@ use {
crate::{
backend,
client::{Client, ClientError, ClientId},
damage::DamageMatrix,
format::{Format, XRGB8888},
globals::{Global, GlobalName},
ifs::{wl_surface::WlSurface, zxdg_output_v1::ZxdgOutputV1},
@ -55,7 +56,7 @@ const MODE_PREFERRED: u32 = 2;
pub struct WlOutputGlobal {
pub name: GlobalName,
pub _state: Rc<State>,
pub state: Rc<State>,
pub connector: Rc<ConnectorData>,
pub pos: Cell<Rect>,
pub output_id: Rc<OutputId>,
@ -71,6 +72,7 @@ pub struct WlOutputGlobal {
pub legacy_scale: Cell<u32>,
pub persistent: Rc<PersistentOutputState>,
pub opt: Rc<OutputGlobalOpt>,
pub damage_matrix: Cell<DamageMatrix>,
}
#[derive(Default)]
@ -151,9 +153,9 @@ impl WlOutputGlobal {
persistent_state.transform.get(),
scale,
);
Self {
let global = Self {
name,
_state: state.clone(),
state: state.clone(),
connector: connector.clone(),
pos: Cell::new(Rect::new_sized(x, y, width, height).unwrap()),
output_id: output_id.clone(),
@ -169,7 +171,10 @@ impl WlOutputGlobal {
legacy_scale: Cell::new(scale.round_up()),
persistent: persistent_state.clone(),
opt: Default::default(),
}
damage_matrix: Default::default(),
};
global.update_damage_matrix();
global
}
pub fn position(&self) -> Rect {
@ -253,6 +258,40 @@ impl WlOutputGlobal {
.get()
.maybe_swap((mode.width, mode.height))
}
pub fn update_damage_matrix(&self) {
let pos = self.pos.get();
let mode = self.mode.get();
let matrix = DamageMatrix::new(
self.persistent.transform.get().inverse(),
1,
pos.width(),
pos.height(),
None,
mode.width,
mode.height,
);
self.damage_matrix.set(matrix);
self.connector
.damage_intersect
.set(Rect::new_sized_unchecked(0, 0, mode.width, mode.height));
}
pub fn add_damage_area(&self, area: &Rect) {
let pos = self.pos.get();
let rect = area.move_(-pos.x1(), -pos.y1());
let mut rect = self.damage_matrix.get().apply(0, 0, rect);
let damage = &mut *self.connector.damage.borrow_mut();
const MAX_CONNECTOR_DAMAGE: usize = 32;
if damage.len() >= MAX_CONNECTOR_DAMAGE {
rect = rect.union(damage.pop().unwrap());
}
damage.push(rect.intersect(self.connector.damage_intersect.get()));
}
pub fn add_visualizer_damage(&self) {
self.state.damage_visualizer.copy_damage(self);
}
}
global_base!(WlOutputGlobal, WlOutput, WlOutputError);

View file

@ -23,6 +23,7 @@ use {
backend::KeyState,
client::{Client, ClientError},
cursor_user::{CursorUser, CursorUserId},
damage::DamageMatrix,
drm_feedback::DrmFeedback,
fixed::Fixed,
gfx_api::{
@ -2027,117 +2028,6 @@ efrom!(WlSurfaceError, XdgSurfaceError);
efrom!(WlSurfaceError, ZwlrLayerSurfaceV1Error);
efrom!(WlSurfaceError, CommitTimelineError);
#[derive(Copy, Clone, Debug)]
struct DamageMatrix {
transform: Transform,
mx: f64,
my: f64,
dx: f64,
dy: f64,
smear: i32,
}
impl Default for DamageMatrix {
fn default() -> Self {
Self {
transform: Default::default(),
mx: 1.0,
my: 1.0,
dx: 0.0,
dy: 0.0,
smear: 0,
}
}
}
impl DamageMatrix {
fn apply(&self, dx: i32, dy: i32, rect: Rect) -> Rect {
let x1 = rect.x1() - self.smear;
let x2 = rect.x2() + self.smear;
let y1 = rect.y1() - self.smear;
let y2 = rect.y2() + self.smear;
let [x1, y1, x2, y2] = match self.transform {
Transform::None => [x1, y1, x2, y2],
Transform::Rotate90 => [-y2, x1, -y1, x2],
Transform::Rotate180 => [-x2, -y2, -x1, -y1],
Transform::Rotate270 => [y1, -x2, y2, -x1],
Transform::Flip => [-x2, y1, -x1, y2],
Transform::FlipRotate90 => [y1, x1, y2, x2],
Transform::FlipRotate180 => [x1, -y2, x2, -y1],
Transform::FlipRotate270 => [-y2, -x2, -y1, -x1],
};
let x1 = (x1 as f64 * self.mx + self.dx).floor() as i32 + dx;
let y1 = (y1 as f64 * self.my + self.dy).floor() as i32 + dy;
let x2 = (x2 as f64 * self.mx + self.dx).ceil() as i32 + dx;
let y2 = (y2 as f64 * self.my + self.dy).ceil() as i32 + dy;
Rect::new(x1, y1, x2, y2).unwrap()
}
fn new(
transform: Transform,
legacy_scale: i32,
buffer_width: i32,
buffer_height: i32,
viewport: Option<[Fixed; 4]>,
dst_width: i32,
dst_height: i32,
) -> DamageMatrix {
let mut buffer_width = buffer_width as f64;
let mut buffer_height = buffer_height as f64;
let dst_width = dst_width as f64;
let dst_height = dst_height as f64;
let mut mx = 1.0;
let mut my = 1.0;
if legacy_scale != 1 {
let scale_inv = 1.0 / (legacy_scale as f64);
mx = scale_inv;
my = scale_inv;
buffer_width *= scale_inv;
buffer_height *= scale_inv;
}
let (mut buffer_width, mut buffer_height) =
transform.maybe_swap((buffer_width, buffer_height));
let (mut dx, mut dy) = match transform {
Transform::None => (0.0, 0.0),
Transform::Rotate90 => (buffer_width, 0.0),
Transform::Rotate180 => (buffer_width, buffer_height),
Transform::Rotate270 => (0.0, buffer_height),
Transform::Flip => (buffer_width, 0.0),
Transform::FlipRotate90 => (0.0, 0.0),
Transform::FlipRotate180 => (0.0, buffer_height),
Transform::FlipRotate270 => (buffer_width, buffer_height),
};
if let Some([x, y, w, h]) = viewport {
dx -= x.to_f64();
dy -= y.to_f64();
buffer_width = w.to_f64();
buffer_height = h.to_f64();
}
let mut smear = false;
if dst_width != buffer_width {
let scale = dst_width / buffer_width;
mx *= scale;
dx *= scale;
smear |= dst_width > buffer_width;
}
if dst_height != buffer_height {
let scale = dst_height / buffer_height;
my *= scale;
dy *= scale;
smear |= dst_height > buffer_height;
}
DamageMatrix {
transform,
mx,
my,
dx,
dy,
smear: smear as _,
}
}
}
impl VblankListener for WlSurface {
fn after_vblank(self: Rc<Self>) {
if self.visible.get() {