metal: latch hardware cursors in the backend
This commit is contained in:
parent
12c9b36ded
commit
93bfb9c0b4
7 changed files with 204 additions and 186 deletions
|
|
@ -135,17 +135,19 @@ pub enum ConnectorEvent {
|
|||
FormatsChanged(Rc<Vec<&'static Format>>, &'static Format),
|
||||
}
|
||||
|
||||
pub trait HardwareCursor: Debug {
|
||||
fn set_enabled(&self, enabled: bool);
|
||||
pub trait HardwareCursorUpdate {
|
||||
fn set_enabled(&mut self, enabled: bool);
|
||||
fn get_buffer(&self) -> Rc<dyn GfxFramebuffer>;
|
||||
fn set_position(&self, x: i32, y: i32);
|
||||
fn swap_buffer(&self);
|
||||
fn set_sync_file(&self, sync_file: Option<SyncFile>);
|
||||
fn commit(&self, schedule_present: bool);
|
||||
fn schedule_present(&self) -> bool;
|
||||
fn set_position(&mut self, x: i32, y: i32);
|
||||
fn swap_buffer(&mut self);
|
||||
fn set_sync_file(&mut self, sync_file: Option<SyncFile>);
|
||||
fn size(&self) -> (i32, i32);
|
||||
}
|
||||
|
||||
pub trait HardwareCursor: Debug {
|
||||
fn damage(&self);
|
||||
}
|
||||
|
||||
pub type TransformMatrix = [[f64; 2]; 2];
|
||||
|
||||
linear_ids!(InputDeviceGroupIds, InputDeviceGroupId, usize);
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ use {
|
|||
async_engine::{Phase, SpawnedFuture},
|
||||
backend::{
|
||||
BackendDrmDevice, BackendDrmLease, BackendDrmLessee, BackendEvent, Connector,
|
||||
ConnectorEvent, ConnectorId, ConnectorKernelId, DrmDeviceId, HardwareCursor, Mode,
|
||||
MonitorInfo,
|
||||
ConnectorEvent, ConnectorId, ConnectorKernelId, DrmDeviceId, HardwareCursor,
|
||||
HardwareCursorUpdate, Mode, MonitorInfo,
|
||||
},
|
||||
backends::metal::{MetalBackend, MetalError},
|
||||
drm_feedback::DrmFeedback,
|
||||
|
|
@ -428,7 +428,7 @@ pub struct MetalConnector {
|
|||
pub can_present: Cell<bool>,
|
||||
pub has_damage: Cell<bool>,
|
||||
pub cursor_changed: Cell<bool>,
|
||||
pub cursor_scheduled: Cell<bool>,
|
||||
pub cursor_damage: Cell<bool>,
|
||||
pub next_flip_nsec: Cell<u64>,
|
||||
|
||||
pub display: RefCell<ConnectorDisplayData>,
|
||||
|
|
@ -446,11 +446,10 @@ pub struct MetalConnector {
|
|||
|
||||
pub render_result: RefCell<RenderResult>,
|
||||
|
||||
pub cursor_generation: NumCell<u64>,
|
||||
pub cursor_x: Cell<i32>,
|
||||
pub cursor_y: Cell<i32>,
|
||||
pub cursor_enabled: Cell<bool>,
|
||||
pub cursor_buffers: CloneCell<Option<Rc<[RenderBuffer; 3]>>>,
|
||||
pub cursor_buffers: CloneCell<Option<Rc<[RenderBuffer; 2]>>>,
|
||||
pub cursor_front_buffer: NumCell<usize>,
|
||||
pub cursor_swap_buffer: Cell<bool>,
|
||||
pub cursor_sync_file: CloneCell<Option<SyncFile>>,
|
||||
|
|
@ -472,15 +471,17 @@ impl Debug for MetalConnector {
|
|||
}
|
||||
|
||||
pub struct MetalHardwareCursor {
|
||||
pub generation: u64,
|
||||
pub connector: Rc<MetalConnector>,
|
||||
pub cursor_swap_buffer: Cell<bool>,
|
||||
pub cursor_enabled_pending: Cell<bool>,
|
||||
pub cursor_x_pending: Cell<i32>,
|
||||
pub cursor_y_pending: Cell<i32>,
|
||||
pub cursor_buffers: Rc<[RenderBuffer; 3]>,
|
||||
pub sync_file: CloneCell<Option<SyncFile>>,
|
||||
pub have_changes: Cell<bool>,
|
||||
}
|
||||
|
||||
pub struct MetalHardwareCursorChange<'a> {
|
||||
pub cursor_swap_buffer: bool,
|
||||
pub cursor_enabled: bool,
|
||||
pub cursor_x: i32,
|
||||
pub cursor_y: i32,
|
||||
pub cursor_buffer: &'a RenderBuffer,
|
||||
pub sync_file: Option<SyncFile>,
|
||||
pub cursor_size: (i32, i32),
|
||||
}
|
||||
|
||||
impl Debug for MetalHardwareCursor {
|
||||
|
|
@ -491,72 +492,38 @@ impl Debug for MetalHardwareCursor {
|
|||
}
|
||||
|
||||
impl HardwareCursor for MetalHardwareCursor {
|
||||
fn set_enabled(&self, enabled: bool) {
|
||||
if self.cursor_enabled_pending.replace(enabled) != enabled {
|
||||
self.have_changes.set(true);
|
||||
fn damage(&self) {
|
||||
self.connector.cursor_damage.set(true);
|
||||
if self.connector.can_present.get() {
|
||||
self.connector.schedule_present();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HardwareCursorUpdate for MetalHardwareCursorChange<'_> {
|
||||
fn set_enabled(&mut self, enabled: bool) {
|
||||
self.cursor_enabled = enabled;
|
||||
}
|
||||
|
||||
fn get_buffer(&self) -> Rc<dyn GfxFramebuffer> {
|
||||
let buffer = (self.connector.cursor_front_buffer.get() + 1) % self.cursor_buffers.len();
|
||||
self.cursor_buffers[buffer].render_fb()
|
||||
self.cursor_buffer.render_fb()
|
||||
}
|
||||
|
||||
fn set_position(&self, x: i32, y: i32) {
|
||||
self.cursor_x_pending.set(x);
|
||||
self.cursor_y_pending.set(y);
|
||||
self.have_changes.set(true);
|
||||
fn set_position(&mut self, x: i32, y: i32) {
|
||||
self.cursor_x = x;
|
||||
self.cursor_y = y;
|
||||
}
|
||||
|
||||
fn swap_buffer(&self) {
|
||||
self.cursor_swap_buffer.set(true);
|
||||
self.have_changes.set(true);
|
||||
fn swap_buffer(&mut self) {
|
||||
self.cursor_swap_buffer = true;
|
||||
}
|
||||
|
||||
fn set_sync_file(&self, sync_file: Option<SyncFile>) {
|
||||
self.sync_file.set(sync_file);
|
||||
self.have_changes.set(true);
|
||||
}
|
||||
|
||||
fn commit(&self, schedule_present: bool) {
|
||||
if self.generation != self.connector.cursor_generation.get() {
|
||||
return;
|
||||
}
|
||||
if !self.have_changes.take() {
|
||||
return;
|
||||
}
|
||||
self.connector
|
||||
.cursor_enabled
|
||||
.set(self.cursor_enabled_pending.get());
|
||||
self.connector.cursor_x.set(self.cursor_x_pending.get());
|
||||
self.connector.cursor_y.set(self.cursor_y_pending.get());
|
||||
if self.cursor_swap_buffer.take() {
|
||||
self.connector.cursor_swap_buffer.set(true);
|
||||
}
|
||||
self.connector.cursor_sync_file.set(self.sync_file.take());
|
||||
self.connector.cursor_changed.set(true);
|
||||
if schedule_present {
|
||||
self.schedule_present();
|
||||
}
|
||||
}
|
||||
|
||||
fn schedule_present(&self) -> bool {
|
||||
if self.connector.cursor_changed.get() {
|
||||
self.connector.cursor_scheduled.set(true);
|
||||
if self.connector.can_present.get() {
|
||||
self.connector.schedule_present();
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
fn set_sync_file(&mut self, sync_file: Option<SyncFile>) {
|
||||
self.sync_file = sync_file;
|
||||
}
|
||||
|
||||
fn size(&self) -> (i32, i32) {
|
||||
(
|
||||
self.connector.dev.cursor_width as _,
|
||||
self.connector.dev.cursor_height as _,
|
||||
)
|
||||
self.cursor_size
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -622,7 +589,12 @@ impl MetalConnector {
|
|||
self.state.ring.timeout(next_present).await.unwrap();
|
||||
}
|
||||
}
|
||||
match self.present(true) {
|
||||
let Some(node) = self.state.root.outputs.get(&self.connector_id) else {
|
||||
return;
|
||||
};
|
||||
self.latch_cursor(&node);
|
||||
node.schedule.latched();
|
||||
match self.present(&node, true) {
|
||||
Ok(_) => self.state.set_backend_idle(false),
|
||||
Err(e) => {
|
||||
log::error!("Could not present: {}", ErrorFmt(e));
|
||||
|
|
@ -671,21 +643,11 @@ impl MetalConnector {
|
|||
| FrontState::Connected { non_desktop: true } => return,
|
||||
FrontState::Connected { non_desktop: false } => {}
|
||||
}
|
||||
let generation = self.cursor_generation.fetch_add(1) + 1;
|
||||
let hc = match self.cursor_buffers.get() {
|
||||
Some(cp) => Some(Rc::new(MetalHardwareCursor {
|
||||
generation,
|
||||
let hc = self.cursor_buffers.is_some().then(|| {
|
||||
Rc::new(MetalHardwareCursor {
|
||||
connector: self.clone(),
|
||||
cursor_swap_buffer: Cell::new(false),
|
||||
cursor_enabled_pending: Cell::new(self.cursor_enabled.get()),
|
||||
cursor_x_pending: Cell::new(self.cursor_x.get()),
|
||||
cursor_y_pending: Cell::new(self.cursor_y.get()),
|
||||
cursor_buffers: cp.clone(),
|
||||
sync_file: Default::default(),
|
||||
have_changes: Cell::new(false),
|
||||
}) as _),
|
||||
_ => None,
|
||||
};
|
||||
}) as _
|
||||
});
|
||||
self.on_change
|
||||
.send_event(ConnectorEvent::HardwareCursor(hc));
|
||||
}
|
||||
|
|
@ -948,12 +910,48 @@ impl MetalConnector {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn present(&self, try_direct_scanout: bool) -> Result<(), MetalError> {
|
||||
fn latch_cursor(&self, node: &Rc<OutputNode>) {
|
||||
if !self.cursor_damage.take() {
|
||||
return;
|
||||
}
|
||||
if self.cursor_plane.is_none() {
|
||||
return;
|
||||
}
|
||||
let buffers = self.cursor_buffers.get().unwrap();
|
||||
let mut c = MetalHardwareCursorChange {
|
||||
cursor_enabled: self.cursor_enabled.get(),
|
||||
cursor_swap_buffer: false,
|
||||
cursor_x: self.cursor_x.get(),
|
||||
cursor_y: self.cursor_y.get(),
|
||||
cursor_buffer: &buffers[(self.cursor_front_buffer.get() + 1) % buffers.len()],
|
||||
sync_file: None,
|
||||
cursor_size: (self.dev.cursor_width as _, self.dev.cursor_height as _),
|
||||
};
|
||||
self.state.present_hardware_cursor(node, &mut c);
|
||||
self.cursor_swap_buffer.set(c.cursor_swap_buffer);
|
||||
if c.sync_file.is_some() {
|
||||
self.cursor_sync_file.set(c.sync_file);
|
||||
}
|
||||
let mut cursor_changed = false;
|
||||
cursor_changed |= self.cursor_enabled.replace(c.cursor_enabled) != c.cursor_enabled;
|
||||
cursor_changed |= c.cursor_swap_buffer;
|
||||
cursor_changed |= self.cursor_x.replace(c.cursor_x) != c.cursor_x;
|
||||
cursor_changed |= self.cursor_y.replace(c.cursor_y) != c.cursor_y;
|
||||
if cursor_changed {
|
||||
self.cursor_changed.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn present(
|
||||
&self,
|
||||
node: &Rc<OutputNode>,
|
||||
try_direct_scanout: bool,
|
||||
) -> Result<(), MetalError> {
|
||||
let crtc = match self.crtc.get() {
|
||||
Some(crtc) => crtc,
|
||||
_ => return Ok(()),
|
||||
};
|
||||
if (!self.has_damage.get() && !self.cursor_scheduled.get()) || !self.can_present.get() {
|
||||
if (!self.has_damage.get() && !self.cursor_changed.get()) || !self.can_present.get() {
|
||||
return Ok(());
|
||||
}
|
||||
if !crtc.active.value.get() {
|
||||
|
|
@ -967,9 +965,6 @@ impl MetalConnector {
|
|||
Some(b) => b,
|
||||
_ => return Ok(()),
|
||||
};
|
||||
let Some(node) = self.state.root.outputs.get(&self.connector_id) else {
|
||||
return Ok(());
|
||||
};
|
||||
let cursor = self.cursor_plane.get();
|
||||
let mut new_fb = None;
|
||||
let mut changes = self.master.change();
|
||||
|
|
@ -1097,7 +1092,7 @@ impl MetalConnector {
|
|||
}
|
||||
if let Some(fb) = &new_fb {
|
||||
if let Some(dsd) = &fb.direct_scanout_data {
|
||||
if self.present(false).is_ok() {
|
||||
if self.present(node, false).is_ok() {
|
||||
let mut cache = self.scanout_buffers.borrow_mut();
|
||||
if let Some(buffer) = cache.remove(&dsd.dma_buf_id) {
|
||||
cache.insert(
|
||||
|
|
@ -1130,7 +1125,6 @@ impl MetalConnector {
|
|||
apply_change!(plane.crtc_y);
|
||||
apply_change!(plane.crtc_w);
|
||||
apply_change!(plane.crtc_h);
|
||||
node.schedule.presented();
|
||||
self.perform_screencopies(&new_fb, &node);
|
||||
if let Some(fb) = new_fb {
|
||||
if fb.direct_scanout_data.is_none() {
|
||||
|
|
@ -1146,7 +1140,6 @@ impl MetalConnector {
|
|||
self.can_present.set(false);
|
||||
self.has_damage.set(false);
|
||||
self.cursor_changed.set(false);
|
||||
self.cursor_scheduled.set(false);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -1609,7 +1602,6 @@ fn create_connector(
|
|||
on_change: Default::default(),
|
||||
present_trigger: Default::default(),
|
||||
render_result: RefCell::new(Default::default()),
|
||||
cursor_generation: Default::default(),
|
||||
cursor_x: Cell::new(0),
|
||||
cursor_y: Cell::new(0),
|
||||
cursor_enabled: Cell::new(false),
|
||||
|
|
@ -1617,7 +1609,7 @@ fn create_connector(
|
|||
display: RefCell::new(display),
|
||||
frontend_state: Cell::new(FrontState::Disconnected),
|
||||
cursor_changed: Cell::new(false),
|
||||
cursor_scheduled: Cell::new(false),
|
||||
cursor_damage: Cell::new(false),
|
||||
cursor_front_buffer: Default::default(),
|
||||
cursor_swap_buffer: Cell::new(false),
|
||||
cursor_sync_file: Default::default(),
|
||||
|
|
@ -2378,7 +2370,6 @@ impl MetalBackend {
|
|||
connector.can_present.set(true);
|
||||
connector.has_damage.set(true);
|
||||
connector.cursor_changed.set(true);
|
||||
connector.cursor_scheduled.set(true);
|
||||
}
|
||||
if dev.unprocessed_change.get() {
|
||||
return self.handle_drm_change_(dev, false);
|
||||
|
|
@ -2439,7 +2430,10 @@ impl MetalBackend {
|
|||
if let Some(fb) = connector.next_framebuffer.take() {
|
||||
*connector.active_framebuffer.borrow_mut() = Some(fb);
|
||||
}
|
||||
if connector.has_damage.get() || connector.cursor_scheduled.get() {
|
||||
if connector.has_damage.get()
|
||||
|| connector.cursor_damage.get()
|
||||
|| connector.cursor_changed.get()
|
||||
{
|
||||
connector.schedule_present();
|
||||
}
|
||||
let dd = connector.display.borrow_mut();
|
||||
|
|
@ -3185,7 +3179,6 @@ impl MetalBackend {
|
|||
}
|
||||
connector.has_damage.set(true);
|
||||
connector.cursor_changed.set(true);
|
||||
connector.cursor_scheduled.set(true);
|
||||
connector.schedule_present();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ impl ServerCursors {
|
|||
let load =
|
||||
|names: &[&str]| ServerCursorTemplate::load(names, theme, &scales, &sizes, &paths, ctx);
|
||||
Ok(Some(Self {
|
||||
// default: load(&["wait", "watch"])?,
|
||||
default: load(&["default", "left_ptr"])?,
|
||||
context_menu: load(&["context-menu"])?,
|
||||
help: load(&["help"])?,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
backend::HardwareCursorUpdate,
|
||||
cursor::{Cursor, KnownCursor, DEFAULT_CURSOR_SIZE},
|
||||
fixed::Fixed,
|
||||
rect::Rect,
|
||||
|
|
@ -103,7 +104,7 @@ impl CursorUserGroup {
|
|||
|
||||
fn remove_hardware_cursor(&self) {
|
||||
self.state.hardware_tick_cursor.push(None);
|
||||
self.state.disable_hardware_cursors();
|
||||
self.state.damage_hardware_cursors(false);
|
||||
self.state.cursor_user_group_hardware_cursor.take();
|
||||
}
|
||||
|
||||
|
|
@ -234,6 +235,18 @@ impl CursorUserGroup {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn present_hardware_cursor(
|
||||
&self,
|
||||
output: &Rc<OutputNode>,
|
||||
hc: &mut dyn HardwareCursorUpdate,
|
||||
) {
|
||||
let Some(active) = self.active.get() else {
|
||||
hc.set_enabled(false);
|
||||
return;
|
||||
};
|
||||
active.present_hardware_cursor(output, hc);
|
||||
}
|
||||
}
|
||||
|
||||
impl CursorUser {
|
||||
|
|
@ -427,86 +440,81 @@ impl CursorUser {
|
|||
return;
|
||||
}
|
||||
let cursor = self.cursor.get();
|
||||
self.group.state.hardware_tick_cursor.push(cursor.clone());
|
||||
let cursor = match cursor {
|
||||
Some(c) => c,
|
||||
_ => {
|
||||
self.group.state.disable_hardware_cursors();
|
||||
return;
|
||||
self.group.state.hardware_tick_cursor.push(cursor);
|
||||
for output in self.group.state.root.outputs.lock().values() {
|
||||
if let Some(hc) = output.hardware_cursor.get() {
|
||||
if render {
|
||||
output.hardware_cursor_needs_render.set(true);
|
||||
}
|
||||
let defer = output.schedule.defer_cursor_updates();
|
||||
if defer {
|
||||
output.schedule.hardware_cursor_changed();
|
||||
} else {
|
||||
hc.damage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn present_hardware_cursor(&self, output: &Rc<OutputNode>, hc: &mut dyn HardwareCursorUpdate) {
|
||||
let Some(cursor) = self.cursor.get() else {
|
||||
hc.set_enabled(false);
|
||||
return;
|
||||
};
|
||||
let (x, y) = self.pos.get();
|
||||
let transform = output.global.persistent.transform.get();
|
||||
let render = output.hardware_cursor_needs_render.take();
|
||||
let scale = output.global.persistent.scale.get();
|
||||
if render {
|
||||
cursor.tick();
|
||||
}
|
||||
let (x, y) = self.pos.get();
|
||||
for output in self.group.state.root.outputs.lock().values() {
|
||||
if let Some(hc) = output.hardware_cursor.get() {
|
||||
let commit = || {
|
||||
let defer = output.schedule.defer_cursor_updates();
|
||||
hc.commit(!defer);
|
||||
if defer {
|
||||
output.schedule.hardware_cursor_changed();
|
||||
}
|
||||
};
|
||||
let transform = output.global.persistent.transform.get();
|
||||
let render = render | output.hardware_cursor_needs_render.take();
|
||||
let scale = output.global.persistent.scale.get();
|
||||
let extents = cursor.extents_at_scale(scale);
|
||||
let (hc_width, hc_height) = hc.size();
|
||||
if render {
|
||||
let (max_width, max_height) = transform.maybe_swap((hc_width, hc_height));
|
||||
if extents.width() > max_width || extents.height() > max_height {
|
||||
hc.set_enabled(false);
|
||||
commit();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let opos = output.global.pos.get();
|
||||
let (x_rel, y_rel);
|
||||
if scale == 1 {
|
||||
x_rel = x.round_down() - opos.x1();
|
||||
y_rel = y.round_down() - opos.y1();
|
||||
} else {
|
||||
let scalef = scale.to_f64();
|
||||
x_rel = ((x - Fixed::from_int(opos.x1())).to_f64() * scalef).round() as i32;
|
||||
y_rel = ((y - Fixed::from_int(opos.y1())).to_f64() * scalef).round() as i32;
|
||||
}
|
||||
let (width, height) = output.global.pixel_size();
|
||||
if extents.intersects(&Rect::new_sized(-x_rel, -y_rel, width, height).unwrap()) {
|
||||
if render {
|
||||
let buffer = hc.get_buffer();
|
||||
let res = buffer.render_hardware_cursor(
|
||||
cursor.deref(),
|
||||
&self.group.state,
|
||||
scale,
|
||||
transform,
|
||||
);
|
||||
match res {
|
||||
Ok(sync_file) => {
|
||||
hc.set_sync_file(sync_file);
|
||||
hc.swap_buffer();
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Could not render hardware cursor: {}", ErrorFmt(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
hc.set_enabled(true);
|
||||
let mode = output.global.mode.get();
|
||||
let (x_rel, y_rel) =
|
||||
transform.apply_point(mode.width, mode.height, (x_rel, y_rel));
|
||||
let (hot_x, hot_y) =
|
||||
transform.apply_point(hc_width, hc_height, (-extents.x1(), -extents.y1()));
|
||||
hc.set_position(x_rel - hot_x, y_rel - hot_y);
|
||||
} else {
|
||||
if render {
|
||||
output.hardware_cursor_needs_render.set(true);
|
||||
}
|
||||
hc.set_enabled(false);
|
||||
}
|
||||
commit();
|
||||
let extents = cursor.extents_at_scale(scale);
|
||||
let (hc_width, hc_height) = hc.size();
|
||||
if render {
|
||||
let (max_width, max_height) = transform.maybe_swap((hc_width, hc_height));
|
||||
if extents.width() > max_width || extents.height() > max_height {
|
||||
hc.set_enabled(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
let opos = output.global.pos.get();
|
||||
let (x_rel, y_rel);
|
||||
if scale == 1 {
|
||||
x_rel = x.round_down() - opos.x1();
|
||||
y_rel = y.round_down() - opos.y1();
|
||||
} else {
|
||||
let scalef = scale.to_f64();
|
||||
x_rel = ((x - Fixed::from_int(opos.x1())).to_f64() * scalef).round() as i32;
|
||||
y_rel = ((y - Fixed::from_int(opos.y1())).to_f64() * scalef).round() as i32;
|
||||
}
|
||||
let (width, height) = output.global.pixel_size();
|
||||
if !extents.intersects(&Rect::new_sized(-x_rel, -y_rel, width, height).unwrap()) {
|
||||
if render {
|
||||
output.hardware_cursor_needs_render.set(true);
|
||||
}
|
||||
hc.set_enabled(false);
|
||||
return;
|
||||
}
|
||||
if render {
|
||||
let buffer = hc.get_buffer();
|
||||
let res =
|
||||
buffer.render_hardware_cursor(cursor.deref(), &self.group.state, scale, transform);
|
||||
match res {
|
||||
Ok(sync_file) => {
|
||||
hc.set_sync_file(sync_file);
|
||||
hc.swap_buffer();
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Could not render hardware cursor: {}", ErrorFmt(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
hc.set_enabled(true);
|
||||
let mode = output.global.mode.get();
|
||||
let (x_rel, y_rel) = transform.apply_point(mode.width, mode.height, (x_rel, y_rel));
|
||||
let (hot_x, hot_y) =
|
||||
transform.apply_point(hc_width, hc_height, (-extents.x1(), -extents.y1()));
|
||||
hc.set_position(x_rel - hot_x, y_rel - hot_y);
|
||||
}
|
||||
|
||||
fn reload_known_cursor(&self) {
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ impl OutputSchedule {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn presented(&self) {
|
||||
pub fn latched(&self) {
|
||||
self.last_present_nsec.set(self.eng.now().nsec());
|
||||
self.present_scheduled.set(false);
|
||||
self.iteration.fetch_add(1);
|
||||
|
|
@ -166,9 +166,8 @@ impl OutputSchedule {
|
|||
}
|
||||
if self.needs_hardware_cursor_commit.take() {
|
||||
if let Some(hc) = self.hardware_cursor.get() {
|
||||
if hc.schedule_present() {
|
||||
self.present_scheduled.set(true);
|
||||
}
|
||||
hc.damage();
|
||||
self.present_scheduled.set(true);
|
||||
}
|
||||
}
|
||||
if self.needs_software_cursor_damage.take() {
|
||||
|
|
|
|||
26
src/state.rs
26
src/state.rs
|
|
@ -4,8 +4,8 @@ use {
|
|||
async_engine::{AsyncEngine, SpawnedFuture},
|
||||
backend::{
|
||||
Backend, BackendDrmDevice, BackendEvent, Connector, ConnectorId, ConnectorIds,
|
||||
DrmDeviceId, DrmDeviceIds, InputDevice, InputDeviceGroupIds, InputDeviceId,
|
||||
InputDeviceIds, MonitorInfo,
|
||||
DrmDeviceId, DrmDeviceIds, HardwareCursorUpdate, InputDevice, InputDeviceGroupIds,
|
||||
InputDeviceId, InputDeviceIds, MonitorInfo,
|
||||
},
|
||||
backends::dummy::DummyBackend,
|
||||
cli::RunArgs,
|
||||
|
|
@ -847,11 +847,13 @@ impl State {
|
|||
self.slow_ei_clients.clear();
|
||||
}
|
||||
|
||||
pub fn disable_hardware_cursors(&self) {
|
||||
pub fn damage_hardware_cursors(&self, render: bool) {
|
||||
for output in self.root.outputs.lock().values() {
|
||||
if let Some(hc) = output.hardware_cursor.get() {
|
||||
hc.set_enabled(false);
|
||||
hc.commit(true);
|
||||
if render {
|
||||
output.hardware_cursor_needs_render.set(true);
|
||||
}
|
||||
hc.damage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -863,7 +865,19 @@ impl State {
|
|||
return;
|
||||
}
|
||||
}
|
||||
self.disable_hardware_cursors()
|
||||
self.damage_hardware_cursors(false)
|
||||
}
|
||||
|
||||
pub fn present_hardware_cursor(
|
||||
&self,
|
||||
output: &Rc<OutputNode>,
|
||||
hc: &mut dyn HardwareCursorUpdate,
|
||||
) {
|
||||
let Some(g) = self.cursor_user_group_hardware_cursor.get() else {
|
||||
hc.set_enabled(false);
|
||||
return;
|
||||
};
|
||||
g.present_hardware_cursor(output, hc);
|
||||
}
|
||||
|
||||
pub fn for_each_seat_tester<F: Fn(&JaySeatEvents)>(&self, f: F) {
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@ pub async fn handle_hardware_cursor_tick(state: Rc<State>) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
state.refresh_hardware_cursors();
|
||||
cursor.tick();
|
||||
state.damage_hardware_cursors(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue