metal: track per-framebuffer damage
This commit is contained in:
parent
f80ac20220
commit
07fb198eb4
17 changed files with 334 additions and 151 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue