Merge pull request #260 from mahkoh/jorth/vblank-events
Handle output events with EventListeners
This commit is contained in:
commit
f4da029166
25 changed files with 235 additions and 217 deletions
|
|
@ -221,7 +221,6 @@ impl Backend for MetalBackend {
|
||||||
connector.crtc.take();
|
connector.crtc.take();
|
||||||
connector.on_change.clear();
|
connector.on_change.clear();
|
||||||
connector.present_trigger.clear();
|
connector.present_trigger.clear();
|
||||||
connector.render_result.take();
|
|
||||||
connector.active_framebuffer.take();
|
connector.active_framebuffer.take();
|
||||||
connector.next_framebuffer.take();
|
connector.next_framebuffer.take();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,7 @@ impl MetalConnector {
|
||||||
self.latch_cursor(&node)?;
|
self.latch_cursor(&node)?;
|
||||||
let cursor_programming = self.compute_cursor_programming();
|
let cursor_programming = self.compute_cursor_programming();
|
||||||
let latched = self.latch(&node);
|
let latched = self.latch(&node);
|
||||||
node.schedule.latched();
|
node.latched();
|
||||||
|
|
||||||
if cursor_programming.is_none() && latched.is_none() {
|
if cursor_programming.is_none() && latched.is_none() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
@ -237,9 +237,6 @@ impl MetalConnector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Err(e) = res {
|
if let Err(e) = res {
|
||||||
self.render_result
|
|
||||||
.borrow_mut()
|
|
||||||
.discard_presentation_feedback();
|
|
||||||
if let MetalError::Commit(DrmError::Atomic(OsError(c::EACCES))) = e {
|
if let MetalError::Commit(DrmError::Atomic(OsError(c::EACCES))) = e {
|
||||||
log::debug!("Could not perform atomic commit, likely because we're no longer the DRM master");
|
log::debug!("Could not perform atomic commit, likely because we're no longer the DRM master");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
@ -272,6 +269,10 @@ impl MetalConnector {
|
||||||
self.can_present.set(false);
|
self.can_present.set(false);
|
||||||
if let Some(latched) = latched {
|
if let Some(latched) = latched {
|
||||||
self.has_damage.fetch_sub(latched.damage);
|
self.has_damage.fetch_sub(latched.damage);
|
||||||
|
node.global
|
||||||
|
.connector
|
||||||
|
.damaged
|
||||||
|
.set(self.has_damage.is_not_zero());
|
||||||
}
|
}
|
||||||
self.cursor_changed.set(false);
|
self.cursor_changed.set(false);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -485,8 +486,6 @@ impl MetalConnector {
|
||||||
if damage == 0 {
|
if damage == 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let mut rr = self.render_result.borrow_mut();
|
|
||||||
rr.output_id = node.id;
|
|
||||||
let render_hw_cursor = !self.cursor_enabled.get();
|
let render_hw_cursor = !self.cursor_enabled.get();
|
||||||
let mode = node.global.mode.get();
|
let mode = node.global.mode.get();
|
||||||
let pass = create_render_pass(
|
let pass = create_render_pass(
|
||||||
|
|
@ -494,7 +493,6 @@ impl MetalConnector {
|
||||||
&**node,
|
&**node,
|
||||||
&self.state,
|
&self.state,
|
||||||
Some(node.global.pos.get()),
|
Some(node.global.pos.get()),
|
||||||
Some(&mut rr),
|
|
||||||
node.global.persistent.scale.get(),
|
node.global.persistent.scale.get(),
|
||||||
true,
|
true,
|
||||||
render_hw_cursor,
|
render_hw_cursor,
|
||||||
|
|
@ -502,7 +500,6 @@ impl MetalConnector {
|
||||||
node.global.persistent.transform.get(),
|
node.global.persistent.transform.get(),
|
||||||
Some(&self.state.damage_visualizer),
|
Some(&self.state.damage_visualizer),
|
||||||
);
|
);
|
||||||
rr.dispatch_frame_requests(self.state.now_msec());
|
|
||||||
Some(Latched { pass, damage })
|
Some(Latched { pass, damage })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ use {
|
||||||
wl_output::OutputId,
|
wl_output::OutputId,
|
||||||
wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC},
|
wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC},
|
||||||
},
|
},
|
||||||
renderer::RenderResult,
|
|
||||||
state::State,
|
state::State,
|
||||||
udev::UdevDevice,
|
udev::UdevDevice,
|
||||||
utils::{
|
utils::{
|
||||||
|
|
@ -447,8 +446,6 @@ pub struct MetalConnector {
|
||||||
|
|
||||||
pub present_trigger: AsyncEvent,
|
pub present_trigger: AsyncEvent,
|
||||||
|
|
||||||
pub render_result: RefCell<RenderResult>,
|
|
||||||
|
|
||||||
pub cursor_x: Cell<i32>,
|
pub cursor_x: Cell<i32>,
|
||||||
pub cursor_y: Cell<i32>,
|
pub cursor_y: Cell<i32>,
|
||||||
pub cursor_enabled: Cell<bool>,
|
pub cursor_enabled: Cell<bool>,
|
||||||
|
|
@ -1044,7 +1041,6 @@ fn create_connector(
|
||||||
crtc: Default::default(),
|
crtc: Default::default(),
|
||||||
on_change: Default::default(),
|
on_change: Default::default(),
|
||||||
present_trigger: Default::default(),
|
present_trigger: Default::default(),
|
||||||
render_result: RefCell::new(Default::default()),
|
|
||||||
cursor_x: Cell::new(0),
|
cursor_x: Cell::new(0),
|
||||||
cursor_y: Cell::new(0),
|
cursor_y: Cell::new(0),
|
||||||
cursor_enabled: Cell::new(false),
|
cursor_enabled: Cell::new(false),
|
||||||
|
|
@ -1912,6 +1908,7 @@ impl MetalBackend {
|
||||||
};
|
};
|
||||||
self.update_sequence(&connector, sequence);
|
self.update_sequence(&connector, sequence);
|
||||||
connector.queue_sequence();
|
connector.queue_sequence();
|
||||||
|
self.state.vblank(connector.connector_id);
|
||||||
let dd = connector.display.borrow();
|
let dd = connector.display.borrow();
|
||||||
connector
|
connector
|
||||||
.next_flip_nsec
|
.next_flip_nsec
|
||||||
|
|
@ -1978,27 +1975,14 @@ impl MetalBackend {
|
||||||
.set(tv_sec as u64 * 1_000_000_000 + tv_usec as u64 * 1000 + dd.refresh as u64);
|
.set(tv_sec as u64 * 1_000_000_000 + tv_usec as u64 * 1000 + dd.refresh as u64);
|
||||||
{
|
{
|
||||||
let global = self.state.root.outputs.get(&connector.connector_id);
|
let global = self.state.root.outputs.get(&connector.connector_id);
|
||||||
let mut rr = connector.render_result.borrow_mut();
|
|
||||||
if let Some(g) = &global {
|
if let Some(g) = &global {
|
||||||
let refresh = dd.refresh;
|
g.presented(
|
||||||
let bindings = g.global.bindings.borrow_mut();
|
tv_sec as _,
|
||||||
for fb in rr.presentation_feedbacks.drain(..) {
|
tv_usec * 1000,
|
||||||
if let Some(bindings) = bindings.get(&fb.client.id) {
|
dd.refresh,
|
||||||
for binding in bindings.values() {
|
connector.sequence.get(),
|
||||||
fb.send_sync_output(binding);
|
KIND_VSYNC | KIND_HW_COMPLETION,
|
||||||
}
|
);
|
||||||
}
|
|
||||||
fb.send_presented(
|
|
||||||
tv_sec as _,
|
|
||||||
tv_usec * 1000,
|
|
||||||
refresh,
|
|
||||||
connector.sequence.get(),
|
|
||||||
KIND_VSYNC | KIND_HW_COMPLETION,
|
|
||||||
);
|
|
||||||
let _ = fb.client.remove_obj(&*fb);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
rr.discard_presentation_feedback();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ use {
|
||||||
format::XRGB8888,
|
format::XRGB8888,
|
||||||
gfx_api::{GfxContext, GfxError, GfxFramebuffer, GfxTexture},
|
gfx_api::{GfxContext, GfxError, GfxFramebuffer, GfxTexture},
|
||||||
ifs::wl_output::OutputId,
|
ifs::wl_output::OutputId,
|
||||||
renderer::RenderResult,
|
|
||||||
state::State,
|
state::State,
|
||||||
utils::{
|
utils::{
|
||||||
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell,
|
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, numcell::NumCell,
|
||||||
|
|
@ -239,7 +238,6 @@ pub async fn create(state: &Rc<State>) -> Result<Rc<XBackend>, XBackendError> {
|
||||||
root,
|
root,
|
||||||
scheduled_present: Default::default(),
|
scheduled_present: Default::default(),
|
||||||
grab_requests: Default::default(),
|
grab_requests: Default::default(),
|
||||||
render_result: Default::default(),
|
|
||||||
drm_device_id: state.drm_dev_ids.next(),
|
drm_device_id: state.drm_dev_ids.next(),
|
||||||
drm_dev,
|
drm_dev,
|
||||||
});
|
});
|
||||||
|
|
@ -274,7 +272,6 @@ pub struct XBackend {
|
||||||
root: u32,
|
root: u32,
|
||||||
scheduled_present: AsyncQueue<Rc<XOutput>>,
|
scheduled_present: AsyncQueue<Rc<XOutput>>,
|
||||||
grab_requests: AsyncQueue<(Rc<XSeat>, bool)>,
|
grab_requests: AsyncQueue<(Rc<XSeat>, bool)>,
|
||||||
render_result: RefCell<RenderResult>,
|
|
||||||
drm_device_id: DrmDeviceId,
|
drm_device_id: DrmDeviceId,
|
||||||
drm_dev: dev_t,
|
drm_dev: dev_t,
|
||||||
}
|
}
|
||||||
|
|
@ -702,6 +699,7 @@ impl XBackend {
|
||||||
} else {
|
} else {
|
||||||
image.render_on_idle.set(true);
|
image.render_on_idle.set(true);
|
||||||
}
|
}
|
||||||
|
self.state.vblank(output.id);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -745,13 +743,9 @@ impl XBackend {
|
||||||
image.last_serial.set(serial);
|
image.last_serial.set(serial);
|
||||||
|
|
||||||
if let Some(node) = self.state.root.outputs.get(&output.id) {
|
if let Some(node) = self.state.root.outputs.get(&output.id) {
|
||||||
let res = self.state.present_output(
|
let res = self
|
||||||
&node,
|
.state
|
||||||
&image.fb.get(),
|
.present_output(&node, &image.fb.get(), &image.tex.get(), true);
|
||||||
&image.tex.get(),
|
|
||||||
&mut self.render_result.borrow_mut(),
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
if let Err(e) = res {
|
if let Err(e) = res {
|
||||||
log::error!("Could not render screen: {}", ErrorFmt(e));
|
log::error!("Could not render screen: {}", ErrorFmt(e));
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -449,10 +449,19 @@ fn create_dummy_output(state: &Rc<State>) {
|
||||||
let connector = Rc::new(DummyOutput {
|
let connector = Rc::new(DummyOutput {
|
||||||
id: state.connector_ids.next(),
|
id: state.connector_ids.next(),
|
||||||
}) as Rc<dyn Connector>;
|
}) as Rc<dyn Connector>;
|
||||||
|
let connector_data = Rc::new(ConnectorData {
|
||||||
|
connector,
|
||||||
|
handler: Cell::new(None),
|
||||||
|
connected: Cell::new(true),
|
||||||
|
name: "Dummy".to_string(),
|
||||||
|
drm_dev: None,
|
||||||
|
async_event: Default::default(),
|
||||||
|
damaged: Cell::new(false),
|
||||||
|
});
|
||||||
let schedule = Rc::new(OutputSchedule::new(
|
let schedule = Rc::new(OutputSchedule::new(
|
||||||
&state.ring,
|
&state.ring,
|
||||||
&state.eng,
|
&state.eng,
|
||||||
&connector,
|
&connector_data,
|
||||||
&persistent_state,
|
&persistent_state,
|
||||||
));
|
));
|
||||||
let dummy_output = Rc::new(OutputNode {
|
let dummy_output = Rc::new(OutputNode {
|
||||||
|
|
@ -460,14 +469,7 @@ fn create_dummy_output(state: &Rc<State>) {
|
||||||
global: Rc::new(WlOutputGlobal::new(
|
global: Rc::new(WlOutputGlobal::new(
|
||||||
state.globals.name(),
|
state.globals.name(),
|
||||||
state,
|
state,
|
||||||
&Rc::new(ConnectorData {
|
&connector_data,
|
||||||
connector,
|
|
||||||
handler: Cell::new(None),
|
|
||||||
connected: Cell::new(true),
|
|
||||||
name: "Dummy".to_string(),
|
|
||||||
drm_dev: None,
|
|
||||||
async_event: Default::default(),
|
|
||||||
}),
|
|
||||||
Vec::new(),
|
Vec::new(),
|
||||||
&backend::Mode {
|
&backend::Mode {
|
||||||
width: 0,
|
width: 0,
|
||||||
|
|
@ -502,7 +504,9 @@ fn create_dummy_output(state: &Rc<State>) {
|
||||||
screencopies: Default::default(),
|
screencopies: Default::default(),
|
||||||
title_visible: Cell::new(false),
|
title_visible: Cell::new(false),
|
||||||
schedule,
|
schedule,
|
||||||
|
vblank_event: Default::default(),
|
||||||
latch_event: Default::default(),
|
latch_event: Default::default(),
|
||||||
|
presentation_event: Default::default(),
|
||||||
});
|
});
|
||||||
let dummy_workspace = Rc::new(WorkspaceNode {
|
let dummy_workspace = Rc::new(WorkspaceNode {
|
||||||
id: state.node_ids.next(),
|
id: state.node_ids.next(),
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ pub async fn visualize_damage(state: Rc<State>) {
|
||||||
fn damage_all(state: &State) {
|
fn damage_all(state: &State) {
|
||||||
for connector in state.connectors.lock().values() {
|
for connector in state.connectors.lock().values() {
|
||||||
if connector.connected.get() {
|
if connector.connected.get() {
|
||||||
connector.connector.damage();
|
connector.damage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use {
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
format::Format,
|
format::Format,
|
||||||
rect::{Rect, Region},
|
rect::{Rect, Region},
|
||||||
renderer::{renderer_base::RendererBase, RenderResult, Renderer},
|
renderer::{renderer_base::RendererBase, Renderer},
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
state::State,
|
state::State,
|
||||||
theme::Color,
|
theme::Color,
|
||||||
|
|
@ -345,7 +345,6 @@ impl dyn GfxFramebuffer {
|
||||||
node: &dyn Node,
|
node: &dyn Node,
|
||||||
state: &State,
|
state: &State,
|
||||||
cursor_rect: Option<Rect>,
|
cursor_rect: Option<Rect>,
|
||||||
result: Option<&mut RenderResult>,
|
|
||||||
scale: Scale,
|
scale: Scale,
|
||||||
render_cursor: bool,
|
render_cursor: bool,
|
||||||
render_hardware_cursor: bool,
|
render_hardware_cursor: bool,
|
||||||
|
|
@ -358,7 +357,6 @@ impl dyn GfxFramebuffer {
|
||||||
node,
|
node,
|
||||||
state,
|
state,
|
||||||
cursor_rect,
|
cursor_rect,
|
||||||
result,
|
|
||||||
scale,
|
scale,
|
||||||
render_cursor,
|
render_cursor,
|
||||||
render_hardware_cursor,
|
render_hardware_cursor,
|
||||||
|
|
@ -377,7 +375,6 @@ impl dyn GfxFramebuffer {
|
||||||
node: &OutputNode,
|
node: &OutputNode,
|
||||||
state: &State,
|
state: &State,
|
||||||
cursor_rect: Option<Rect>,
|
cursor_rect: Option<Rect>,
|
||||||
result: Option<&mut RenderResult>,
|
|
||||||
scale: Scale,
|
scale: Scale,
|
||||||
render_hardware_cursor: bool,
|
render_hardware_cursor: bool,
|
||||||
) -> Result<Option<SyncFile>, GfxError> {
|
) -> Result<Option<SyncFile>, GfxError> {
|
||||||
|
|
@ -385,7 +382,6 @@ impl dyn GfxFramebuffer {
|
||||||
node,
|
node,
|
||||||
state,
|
state,
|
||||||
cursor_rect,
|
cursor_rect,
|
||||||
result,
|
|
||||||
scale,
|
scale,
|
||||||
true,
|
true,
|
||||||
render_hardware_cursor,
|
render_hardware_cursor,
|
||||||
|
|
@ -399,7 +395,6 @@ impl dyn GfxFramebuffer {
|
||||||
node: &dyn Node,
|
node: &dyn Node,
|
||||||
state: &State,
|
state: &State,
|
||||||
cursor_rect: Option<Rect>,
|
cursor_rect: Option<Rect>,
|
||||||
result: Option<&mut RenderResult>,
|
|
||||||
scale: Scale,
|
scale: Scale,
|
||||||
render_cursor: bool,
|
render_cursor: bool,
|
||||||
render_hardware_cursor: bool,
|
render_hardware_cursor: bool,
|
||||||
|
|
@ -410,7 +405,6 @@ impl dyn GfxFramebuffer {
|
||||||
node,
|
node,
|
||||||
state,
|
state,
|
||||||
cursor_rect,
|
cursor_rect,
|
||||||
result,
|
|
||||||
scale,
|
scale,
|
||||||
render_cursor,
|
render_cursor,
|
||||||
render_hardware_cursor,
|
render_hardware_cursor,
|
||||||
|
|
@ -432,7 +426,6 @@ impl dyn GfxFramebuffer {
|
||||||
let mut renderer = Renderer {
|
let mut renderer = Renderer {
|
||||||
base: self.renderer_base(&mut ops, scale, transform),
|
base: self.renderer_base(&mut ops, scale, transform),
|
||||||
state,
|
state,
|
||||||
result: None,
|
|
||||||
logical_extents: Rect::new_empty(0, 0),
|
logical_extents: Rect::new_empty(0, 0),
|
||||||
pixel_extents: {
|
pixel_extents: {
|
||||||
let (width, height) = self.logical_size(transform);
|
let (width, height) = self.logical_size(transform);
|
||||||
|
|
@ -638,7 +631,6 @@ pub fn create_render_pass(
|
||||||
node: &dyn Node,
|
node: &dyn Node,
|
||||||
state: &State,
|
state: &State,
|
||||||
cursor_rect: Option<Rect>,
|
cursor_rect: Option<Rect>,
|
||||||
result: Option<&mut RenderResult>,
|
|
||||||
scale: Scale,
|
scale: Scale,
|
||||||
render_cursor: bool,
|
render_cursor: bool,
|
||||||
render_hardware_cursor: bool,
|
render_hardware_cursor: bool,
|
||||||
|
|
@ -650,7 +642,6 @@ pub fn create_render_pass(
|
||||||
let mut renderer = Renderer {
|
let mut renderer = Renderer {
|
||||||
base: renderer_base(physical_size, &mut ops, scale, transform),
|
base: renderer_base(physical_size, &mut ops, scale, transform),
|
||||||
state,
|
state,
|
||||||
result,
|
|
||||||
logical_extents: node.node_absolute_position().at_point(0, 0),
|
logical_extents: node.node_absolute_position().at_point(0, 0),
|
||||||
pixel_extents: {
|
pixel_extents: {
|
||||||
let (width, height) = logical_size(physical_size, transform);
|
let (width, height) = logical_size(physical_size, transform);
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,6 @@ impl JayScreencast {
|
||||||
tl.tl_as_node(),
|
tl.tl_as_node(),
|
||||||
&self.client.state,
|
&self.client.state,
|
||||||
Some(tl.node_absolute_position()),
|
Some(tl.node_absolute_position()),
|
||||||
None,
|
|
||||||
scale,
|
scale,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ impl WlCompositorRequestHandler for WlCompositor {
|
||||||
type Error = WlCompositorError;
|
type Error = WlCompositorError;
|
||||||
|
|
||||||
fn create_surface(&self, req: CreateSurface, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn create_surface(&self, req: CreateSurface, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
let surface = Rc::new(WlSurface::new(req.id, &self.client, self.version));
|
let surface = Rc::new_cyclic(|slf| WlSurface::new(req.id, &self.client, self.version, slf));
|
||||||
track!(self.client, surface);
|
track!(self.client, surface);
|
||||||
self.client.add_client_obj(&surface)?;
|
self.client.add_client_obj(&surface)?;
|
||||||
if self.client.is_xwayland {
|
if self.client.is_xwayland {
|
||||||
|
|
|
||||||
|
|
@ -63,13 +63,15 @@ use {
|
||||||
rect::{DamageQueue, Rect, Region},
|
rect::{DamageQueue, Rect, Region},
|
||||||
renderer::Renderer,
|
renderer::Renderer,
|
||||||
tree::{
|
tree::{
|
||||||
ContainerNode, FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, NodeVisitorBase,
|
ContainerNode, FindTreeResult, FoundNode, LatchListener, Node, NodeId, NodeVisitor,
|
||||||
OutputNode, OutputNodeId, PlaceholderNode, ToplevelNode,
|
NodeVisitorBase, OutputNode, PlaceholderNode, PresentationListener, ToplevelNode,
|
||||||
|
VblankListener,
|
||||||
},
|
},
|
||||||
utils::{
|
utils::{
|
||||||
cell_ext::CellExt, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
cell_ext::CellExt, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
||||||
double_buffered::DoubleBuffered, errorfmt::ErrorFmt, linkedlist::LinkedList,
|
double_buffered::DoubleBuffered, errorfmt::ErrorFmt, event_listener::EventListener,
|
||||||
numcell::NumCell, smallmap::SmallMap, transform_ext::TransformExt,
|
linkedlist::LinkedList, numcell::NumCell, smallmap::SmallMap,
|
||||||
|
transform_ext::TransformExt,
|
||||||
},
|
},
|
||||||
video::{
|
video::{
|
||||||
dmabuf::DMA_BUF_SYNC_READ,
|
dmabuf::DMA_BUF_SYNC_READ,
|
||||||
|
|
@ -91,7 +93,7 @@ use {
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
mem,
|
mem,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
rc::Rc,
|
rc::{Rc, Weak},
|
||||||
},
|
},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
zwp_idle_inhibitor_v1::ZwpIdleInhibitorV1,
|
zwp_idle_inhibitor_v1::ZwpIdleInhibitorV1,
|
||||||
|
|
@ -274,15 +276,14 @@ pub struct WlSurface {
|
||||||
pub buffer_abs_pos: Cell<Rect>,
|
pub buffer_abs_pos: Cell<Rect>,
|
||||||
pub need_extents_update: Cell<bool>,
|
pub need_extents_update: Cell<bool>,
|
||||||
pub buffer: CloneCell<Option<Rc<SurfaceBuffer>>>,
|
pub buffer: CloneCell<Option<Rc<SurfaceBuffer>>>,
|
||||||
buffer_presented: Cell<bool>,
|
|
||||||
buffer_had_frame_request: Cell<bool>,
|
|
||||||
pub shm_textures: DoubleBuffered<SurfaceShmTexture>,
|
pub shm_textures: DoubleBuffered<SurfaceShmTexture>,
|
||||||
pub buf_x: NumCell<i32>,
|
pub buf_x: NumCell<i32>,
|
||||||
pub buf_y: NumCell<i32>,
|
pub buf_y: NumCell<i32>,
|
||||||
pub children: RefCell<Option<Box<ParentData>>>,
|
pub children: RefCell<Option<Box<ParentData>>>,
|
||||||
ext: CloneCell<Rc<dyn SurfaceExt>>,
|
ext: CloneCell<Rc<dyn SurfaceExt>>,
|
||||||
pub frame_requests: RefCell<Vec<Rc<WlCallback>>>,
|
frame_requests: RefCell<Vec<Rc<WlCallback>>>,
|
||||||
pub presentation_feedback: RefCell<Vec<Rc<WpPresentationFeedback>>>,
|
presentation_feedback: RefCell<Vec<Rc<WpPresentationFeedback>>>,
|
||||||
|
latched_presentation_feedback: RefCell<Vec<Rc<WpPresentationFeedback>>>,
|
||||||
seat_state: NodeSeatState,
|
seat_state: NodeSeatState,
|
||||||
toplevel: CloneCell<Option<Rc<dyn ToplevelNode>>>,
|
toplevel: CloneCell<Option<Rc<dyn ToplevelNode>>>,
|
||||||
cursors: SmallMap<CursorUserId, Rc<CursorSurface>, 1>,
|
cursors: SmallMap<CursorUserId, Rc<CursorSurface>, 1>,
|
||||||
|
|
@ -306,6 +307,11 @@ pub struct WlSurface {
|
||||||
alpha_modifier: CloneCell<Option<Rc<WpAlphaModifierSurfaceV1>>>,
|
alpha_modifier: CloneCell<Option<Rc<WpAlphaModifierSurfaceV1>>>,
|
||||||
alpha: Cell<Option<f32>>,
|
alpha: Cell<Option<f32>>,
|
||||||
pub text_input_connections: SmallMap<SeatId, Rc<TextInputConnection>, 1>,
|
pub text_input_connections: SmallMap<SeatId, Rc<TextInputConnection>, 1>,
|
||||||
|
vblank_listener: EventListener<dyn VblankListener>,
|
||||||
|
latch_listener: EventListener<dyn LatchListener>,
|
||||||
|
presentation_listener: EventListener<dyn PresentationListener>,
|
||||||
|
commit_version: NumCell<u64>,
|
||||||
|
latched_commit_version: Cell<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for WlSurface {
|
impl Debug for WlSurface {
|
||||||
|
|
@ -566,7 +572,7 @@ pub struct StackElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WlSurface {
|
impl WlSurface {
|
||||||
pub fn new(id: WlSurfaceId, client: &Rc<Client>, version: Version) -> Self {
|
pub fn new(id: WlSurfaceId, client: &Rc<Client>, version: Version, slf: &Weak<Self>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id,
|
id,
|
||||||
node_id: client.state.node_ids.next(),
|
node_id: client.state.node_ids.next(),
|
||||||
|
|
@ -587,8 +593,6 @@ impl WlSurface {
|
||||||
buffer_abs_pos: Cell::new(Default::default()),
|
buffer_abs_pos: Cell::new(Default::default()),
|
||||||
need_extents_update: Default::default(),
|
need_extents_update: Default::default(),
|
||||||
buffer: Default::default(),
|
buffer: Default::default(),
|
||||||
buffer_presented: Default::default(),
|
|
||||||
buffer_had_frame_request: Default::default(),
|
|
||||||
shm_textures: DoubleBuffered::new(DamageQueue::new().map(|damage| SurfaceShmTexture {
|
shm_textures: DoubleBuffered::new(DamageQueue::new().map(|damage| SurfaceShmTexture {
|
||||||
tex: Default::default(),
|
tex: Default::default(),
|
||||||
damage,
|
damage,
|
||||||
|
|
@ -599,6 +603,7 @@ impl WlSurface {
|
||||||
ext: CloneCell::new(client.state.none_surface_ext.clone()),
|
ext: CloneCell::new(client.state.none_surface_ext.clone()),
|
||||||
frame_requests: Default::default(),
|
frame_requests: Default::default(),
|
||||||
presentation_feedback: Default::default(),
|
presentation_feedback: Default::default(),
|
||||||
|
latched_presentation_feedback: Default::default(),
|
||||||
seat_state: Default::default(),
|
seat_state: Default::default(),
|
||||||
toplevel: Default::default(),
|
toplevel: Default::default(),
|
||||||
cursors: Default::default(),
|
cursors: Default::default(),
|
||||||
|
|
@ -622,6 +627,11 @@ impl WlSurface {
|
||||||
alpha_modifier: Default::default(),
|
alpha_modifier: Default::default(),
|
||||||
alpha: Default::default(),
|
alpha: Default::default(),
|
||||||
text_input_connections: Default::default(),
|
text_input_connections: Default::default(),
|
||||||
|
vblank_listener: EventListener::new(slf.clone()),
|
||||||
|
latch_listener: EventListener::new(slf.clone()),
|
||||||
|
presentation_listener: EventListener::new(slf.clone()),
|
||||||
|
commit_version: Default::default(),
|
||||||
|
latched_commit_version: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -652,6 +662,9 @@ impl WlSurface {
|
||||||
if old.id == output.id {
|
if old.id == output.id {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if self.visible.get() {
|
||||||
|
self.attach_events_to_output(output);
|
||||||
|
}
|
||||||
output.global.send_enter(self);
|
output.global.send_enter(self);
|
||||||
old.global.send_leave(self);
|
old.global.send_leave(self);
|
||||||
if old.global.persistent.scale.get() != output.global.persistent.scale.get() {
|
if old.global.persistent.scale.get() != output.global.persistent.scale.get() {
|
||||||
|
|
@ -1107,10 +1120,6 @@ impl WlSurface {
|
||||||
release,
|
release,
|
||||||
};
|
};
|
||||||
self.buffer.set(Some(Rc::new(surface_buffer)));
|
self.buffer.set(Some(Rc::new(surface_buffer)));
|
||||||
if pending.has_damage() {
|
|
||||||
self.buffer_presented.set(false);
|
|
||||||
self.buffer_had_frame_request.set(false);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
self.reset_shm_textures();
|
self.reset_shm_textures();
|
||||||
self.buf_x.set(0);
|
self.buf_x.set(0);
|
||||||
|
|
@ -1222,22 +1231,20 @@ impl WlSurface {
|
||||||
damage_full = true;
|
damage_full = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let had_frame_requests = self.buffer_had_frame_request.get();
|
|
||||||
let has_frame_requests = {
|
let has_frame_requests = {
|
||||||
let frs = &mut *self.frame_requests.borrow_mut();
|
let frs = &mut *self.frame_requests.borrow_mut();
|
||||||
frs.append(&mut pending.frame_request);
|
frs.append(&mut pending.frame_request);
|
||||||
frs.is_not_empty()
|
frs.is_not_empty()
|
||||||
};
|
};
|
||||||
self.buffer_had_frame_request
|
let has_presentation_feedback = {
|
||||||
.set(had_frame_requests || has_frame_requests);
|
|
||||||
{
|
|
||||||
let mut fbs = self.presentation_feedback.borrow_mut();
|
let mut fbs = self.presentation_feedback.borrow_mut();
|
||||||
for fb in fbs.drain(..) {
|
for fb in fbs.drain(..) {
|
||||||
fb.send_discarded();
|
fb.send_discarded();
|
||||||
let _ = self.client.remove_obj(&*fb);
|
let _ = self.client.remove_obj(&*fb);
|
||||||
}
|
}
|
||||||
mem::swap(fbs.deref_mut(), &mut pending.presentation_feedback);
|
mem::swap(fbs.deref_mut(), &mut pending.presentation_feedback);
|
||||||
}
|
fbs.is_not_empty()
|
||||||
|
};
|
||||||
{
|
{
|
||||||
if let Some(region) = pending.input_region.take() {
|
if let Some(region) = pending.input_region.take() {
|
||||||
self.input_region.set(region);
|
self.input_region.set(region);
|
||||||
|
|
@ -1278,6 +1285,13 @@ impl WlSurface {
|
||||||
}
|
}
|
||||||
self.ext.get().after_apply_commit();
|
self.ext.get().after_apply_commit();
|
||||||
if self.visible.get() {
|
if self.visible.get() {
|
||||||
|
let output = self.output.get();
|
||||||
|
if has_frame_requests {
|
||||||
|
self.vblank_listener.attach(&output.vblank_event);
|
||||||
|
}
|
||||||
|
if has_presentation_feedback {
|
||||||
|
self.latch_listener.attach(&output.latch_event);
|
||||||
|
}
|
||||||
if damage_full {
|
if damage_full {
|
||||||
let mut damage = buffer_abs_pos
|
let mut damage = buffer_abs_pos
|
||||||
.with_size(max_surface_size.0, max_surface_size.1)
|
.with_size(max_surface_size.0, max_surface_size.1)
|
||||||
|
|
@ -1286,35 +1300,16 @@ impl WlSurface {
|
||||||
damage = damage.intersect(tl.node_absolute_position());
|
damage = damage.intersect(tl.node_absolute_position());
|
||||||
}
|
}
|
||||||
self.client.state.damage(damage);
|
self.client.state.damage(damage);
|
||||||
} else if self.buffer_presented.get() {
|
} else if pending.has_damage() {
|
||||||
// If the currently attached buffer has already been fully presented ...
|
|
||||||
if has_frame_requests {
|
|
||||||
// ... and there are new frame requests ...
|
|
||||||
if had_frame_requests {
|
|
||||||
// ... and we've already dispatched frame requests for that buffer,
|
|
||||||
// then schedule new presentation of the primary output and
|
|
||||||
// unset the buffer_presented flag. This is for clients that
|
|
||||||
// send frame requests at an uncapped rate and expect the
|
|
||||||
// compositor to dispatch frame requests at the monitor
|
|
||||||
// refresh rate (e.g. firefox). This is very inefficient and
|
|
||||||
// disables VRR from working correctly. But since only firefox
|
|
||||||
// is affected, I'm ok with this.
|
|
||||||
let rect = self.output.get().global.pos.get();
|
|
||||||
self.client.state.damage(rect);
|
|
||||||
self.buffer_presented.set(false);
|
|
||||||
} else {
|
|
||||||
// ... and this is the first commit that attaches a frame request
|
|
||||||
// for that buffer, then dispatch the frame requests
|
|
||||||
// immediately.
|
|
||||||
let now = self.client.state.now_msec() as _;
|
|
||||||
for fr in self.frame_requests.borrow_mut().drain(..) {
|
|
||||||
fr.send_done(now);
|
|
||||||
let _ = fr.client.remove_obj(&*fr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.apply_damage(pending);
|
self.apply_damage(pending);
|
||||||
|
if has_frame_requests {
|
||||||
|
output.global.connector.damage();
|
||||||
|
}
|
||||||
|
} else if has_frame_requests && output.schedule.vrr_enabled() {
|
||||||
|
// Frame requests must be dispatched at the highest possible frame rate.
|
||||||
|
// Therefore we must trigger a vsync of the output as soon as possible.
|
||||||
|
let rect = output.global.pos.get();
|
||||||
|
self.client.state.damage(rect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pending.buffer_damage.clear();
|
pending.buffer_damage.clear();
|
||||||
|
|
@ -1327,6 +1322,7 @@ impl WlSurface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.commit_version.fetch_add(1);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1469,10 +1465,18 @@ impl WlSurface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn attach_events_to_output(&self, output: &OutputNode) {
|
||||||
|
self.vblank_listener.attach(&output.vblank_event);
|
||||||
|
self.latch_listener.attach(&output.latch_event);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_visible(&self, visible: bool) {
|
pub fn set_visible(&self, visible: bool) {
|
||||||
if self.visible.replace(visible) == visible {
|
if self.visible.replace(visible) == visible {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if visible {
|
||||||
|
self.attach_events_to_output(&self.output.get());
|
||||||
|
}
|
||||||
for (_, inhibitor) in &self.idle_inhibitors {
|
for (_, inhibitor) in &self.idle_inhibitors {
|
||||||
if visible {
|
if visible {
|
||||||
inhibitor.activate();
|
inhibitor.activate();
|
||||||
|
|
@ -1491,12 +1495,6 @@ impl WlSurface {
|
||||||
self.seat_state.set_visible(self, visible);
|
self.seat_state.set_visible(self, visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn presented(&self, on: OutputNodeId) {
|
|
||||||
if on == self.output.get().id {
|
|
||||||
self.buffer_presented.set(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn detach_node(&self, set_invisible: bool) {
|
pub fn detach_node(&self, set_invisible: bool) {
|
||||||
for (_, constraint) in &self.constraints {
|
for (_, constraint) in &self.constraints {
|
||||||
constraint.deactivate();
|
constraint.deactivate();
|
||||||
|
|
@ -1586,6 +1584,7 @@ impl Object for WlSurface {
|
||||||
self.idle_inhibitors.clear();
|
self.idle_inhibitors.clear();
|
||||||
mem::take(self.pending.borrow_mut().deref_mut());
|
mem::take(self.pending.borrow_mut().deref_mut());
|
||||||
self.presentation_feedback.borrow_mut().clear();
|
self.presentation_feedback.borrow_mut().clear();
|
||||||
|
self.latched_presentation_feedback.borrow_mut().clear();
|
||||||
self.viewporter.take();
|
self.viewporter.take();
|
||||||
self.fractional_scale.take();
|
self.fractional_scale.take();
|
||||||
self.tearing_control.take();
|
self.tearing_control.take();
|
||||||
|
|
@ -2053,3 +2052,62 @@ impl DamageMatrix {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl VblankListener for WlSurface {
|
||||||
|
fn after_vblank(self: Rc<Self>) {
|
||||||
|
if self.visible.get() {
|
||||||
|
let now = self.client.state.now_usec();
|
||||||
|
for fr in self.frame_requests.borrow_mut().drain(..) {
|
||||||
|
fr.send_done(now as _);
|
||||||
|
let _ = fr.client.remove_obj(&*fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.vblank_listener.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LatchListener for WlSurface {
|
||||||
|
fn after_latch(self: Rc<Self>) {
|
||||||
|
if self.visible.get() {
|
||||||
|
if self.latched_commit_version.get() < self.commit_version.get() {
|
||||||
|
let latched = &mut *self.latched_presentation_feedback.borrow_mut();
|
||||||
|
for pf in latched.drain(..) {
|
||||||
|
pf.send_discarded();
|
||||||
|
let _ = pf.client.remove_obj(&*pf);
|
||||||
|
}
|
||||||
|
latched.append(&mut self.presentation_feedback.borrow_mut());
|
||||||
|
if latched.is_not_empty() {
|
||||||
|
self.presentation_listener
|
||||||
|
.attach(&self.output.get().presentation_event);
|
||||||
|
}
|
||||||
|
self.latched_commit_version.set(self.commit_version.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.latch_listener.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PresentationListener for WlSurface {
|
||||||
|
fn presented(
|
||||||
|
self: Rc<Self>,
|
||||||
|
output: &OutputNode,
|
||||||
|
tv_sec: u64,
|
||||||
|
tv_nsec: u32,
|
||||||
|
refresh: u32,
|
||||||
|
seq: u64,
|
||||||
|
flags: u32,
|
||||||
|
) {
|
||||||
|
let bindings = output.global.bindings.borrow();
|
||||||
|
let bindings = bindings.get(&self.client.id);
|
||||||
|
for pf in self.latched_presentation_feedback.borrow_mut().drain(..) {
|
||||||
|
if let Some(bindings) = bindings {
|
||||||
|
for binding in bindings.values() {
|
||||||
|
pf.send_sync_output(binding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pf.send_presented(tv_sec, tv_nsec, refresh, seq, flags);
|
||||||
|
let _ = pf.client.remove_obj(&*pf);
|
||||||
|
}
|
||||||
|
self.presentation_listener.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,10 @@ impl Cursor for CursorSurface {
|
||||||
fr.send_discarded();
|
fr.send_discarded();
|
||||||
let _ = fr.client.remove_obj(fr.deref());
|
let _ = fr.client.remove_obj(fr.deref());
|
||||||
}
|
}
|
||||||
|
for fr in node.latched_presentation_feedback.borrow_mut().drain(..) {
|
||||||
|
fr.send_discarded();
|
||||||
|
let _ = fr.client.remove_obj(fr.deref());
|
||||||
|
}
|
||||||
node.node_visit_children(self);
|
node.node_visit_children(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -423,6 +423,9 @@ impl ToplevelNodeBase for Xwindow {
|
||||||
if self.data.info.override_redirect.get() {
|
if self.data.info.override_redirect.get() {
|
||||||
self.data.state.damage(old);
|
self.data.state.damage(old);
|
||||||
self.data.state.damage(*rect);
|
self.data.state.damage(*rect);
|
||||||
|
let (x, y) = rect.center();
|
||||||
|
let output = self.data.state.find_closest_output(x, y).0;
|
||||||
|
self.x.surface.set_output(&output);
|
||||||
} else {
|
} else {
|
||||||
self.data
|
self.data
|
||||||
.state
|
.state
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ impl ZwlrScreencopyFrameV1 {
|
||||||
self.buffer.set(Some(buffer));
|
self.buffer.set(Some(buffer));
|
||||||
if !with_damage {
|
if !with_damage {
|
||||||
if let Some(global) = self.output.get() {
|
if let Some(global) = self.output.get() {
|
||||||
global.connector.connector.damage();
|
global.connector.damage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.with_damage.set(with_damage);
|
self.with_damage.set(with_damage);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ pub mod test_container_node_ext;
|
||||||
pub mod test_expected_event;
|
pub mod test_expected_event;
|
||||||
pub mod test_object_ext;
|
pub mod test_object_ext;
|
||||||
pub mod test_ouput_node_ext;
|
pub mod test_ouput_node_ext;
|
||||||
pub mod test_rect_ext;
|
|
||||||
pub mod test_surface_ext;
|
pub mod test_surface_ext;
|
||||||
pub mod test_toplevel_node_ext;
|
pub mod test_toplevel_node_ext;
|
||||||
pub mod test_window;
|
pub mod test_window;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
use crate::rect::Rect;
|
|
||||||
|
|
||||||
pub trait TestRectExt {
|
|
||||||
fn center(&self) -> (i32, i32);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TestRectExt for Rect {
|
|
||||||
fn center(&self) -> (i32, i32) {
|
|
||||||
((self.x1() + self.x2()) / 2, (self.y1() + self.y2()) / 2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{it::test_utils::test_rect_ext::TestRectExt, tree::ToplevelNode};
|
use crate::tree::ToplevelNode;
|
||||||
|
|
||||||
pub trait TestToplevelNodeExt {
|
pub trait TestToplevelNodeExt {
|
||||||
fn center(&self) -> (i32, i32);
|
fn center(&self) -> (i32, i32);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
ifs::wl_seat::BTN_LEFT,
|
ifs::wl_seat::BTN_LEFT,
|
||||||
it::{test_error::TestResult, test_utils::test_rect_ext::TestRectExt, testrun::TestRun},
|
it::{test_error::TestResult, testrun::TestRun},
|
||||||
tree::Node,
|
tree::Node,
|
||||||
},
|
},
|
||||||
std::rc::Rc,
|
std::rc::Rc,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
it::{test_error::TestResult, test_utils::test_rect_ext::TestRectExt, testrun::TestRun},
|
it::{test_error::TestResult, testrun::TestRun},
|
||||||
tree::Node,
|
tree::Node,
|
||||||
},
|
},
|
||||||
std::rc::Rc,
|
std::rc::Rc,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::AsyncEngine,
|
async_engine::AsyncEngine,
|
||||||
backend::{Connector, HardwareCursor},
|
backend::HardwareCursor,
|
||||||
ifs::wl_output::PersistentOutputState,
|
ifs::wl_output::PersistentOutputState,
|
||||||
io_uring::{IoUring, IoUringError},
|
io_uring::{IoUring, IoUringError},
|
||||||
|
state::ConnectorData,
|
||||||
utils::{
|
utils::{
|
||||||
asyncevent::AsyncEvent, cell_ext::CellExt, clonecell::CloneCell, errorfmt::ErrorFmt,
|
asyncevent::AsyncEvent, cell_ext::CellExt, clonecell::CloneCell, errorfmt::ErrorFmt,
|
||||||
numcell::NumCell,
|
numcell::NumCell,
|
||||||
|
|
@ -18,7 +19,7 @@ pub struct OutputSchedule {
|
||||||
changed: AsyncEvent,
|
changed: AsyncEvent,
|
||||||
run: Cell<bool>,
|
run: Cell<bool>,
|
||||||
|
|
||||||
connector: Rc<dyn Connector>,
|
connector: Rc<ConnectorData>,
|
||||||
hardware_cursor: CloneCell<Option<Rc<dyn HardwareCursor>>>,
|
hardware_cursor: CloneCell<Option<Rc<dyn HardwareCursor>>>,
|
||||||
|
|
||||||
persistent: Rc<PersistentOutputState>,
|
persistent: Rc<PersistentOutputState>,
|
||||||
|
|
@ -42,7 +43,7 @@ impl OutputSchedule {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
ring: &Rc<IoUring>,
|
ring: &Rc<IoUring>,
|
||||||
eng: &Rc<AsyncEngine>,
|
eng: &Rc<AsyncEngine>,
|
||||||
connector: &Rc<dyn Connector>,
|
connector: &Rc<ConnectorData>,
|
||||||
persistent: &Rc<PersistentOutputState>,
|
persistent: &Rc<PersistentOutputState>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let slf = Self {
|
let slf = Self {
|
||||||
|
|
|
||||||
|
|
@ -236,4 +236,11 @@ impl Rect {
|
||||||
pub fn size(&self) -> (i32, i32) {
|
pub fn size(&self) -> (i32, i32) {
|
||||||
(self.width(), self.height())
|
(self.width(), self.height())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn center(&self) -> (i32, i32) {
|
||||||
|
(
|
||||||
|
self.raw.x1 + self.width() / 2,
|
||||||
|
self.raw.y1 + self.height() / 2,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,11 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
gfx_api::{AcquireSync, GfxApiOpt, ReleaseSync, SampleRect},
|
gfx_api::{AcquireSync, GfxApiOpt, ReleaseSync, SampleRect},
|
||||||
ifs::{
|
ifs::wl_surface::{
|
||||||
wl_callback::WlCallback,
|
x_surface::xwindow::Xwindow,
|
||||||
wl_surface::{
|
xdg_surface::{xdg_toplevel::XdgToplevel, XdgSurface},
|
||||||
x_surface::xwindow::Xwindow,
|
zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
|
||||||
xdg_surface::{xdg_toplevel::XdgToplevel, XdgSurface},
|
SurfaceBuffer, WlSurface,
|
||||||
zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
|
|
||||||
SurfaceBuffer, WlSurface,
|
|
||||||
},
|
|
||||||
wp_presentation_feedback::WpPresentationFeedback,
|
|
||||||
},
|
},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
renderer::renderer_base::RendererBase,
|
renderer::renderer_base::RendererBase,
|
||||||
|
|
@ -17,62 +13,18 @@ use {
|
||||||
state::State,
|
state::State,
|
||||||
theme::Color,
|
theme::Color,
|
||||||
tree::{
|
tree::{
|
||||||
ContainerNode, DisplayNode, FloatNode, OutputNode, OutputNodeId, PlaceholderNode,
|
ContainerNode, DisplayNode, FloatNode, OutputNode, PlaceholderNode, ToplevelData,
|
||||||
ToplevelData, ToplevelNodeBase, WorkspaceNode,
|
ToplevelNodeBase, WorkspaceNode,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
std::{
|
std::{ops::Deref, rc::Rc, slice},
|
||||||
fmt::{Debug, Formatter},
|
|
||||||
ops::Deref,
|
|
||||||
rc::Rc,
|
|
||||||
slice,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod renderer_base;
|
pub mod renderer_base;
|
||||||
|
|
||||||
pub struct RenderResult {
|
|
||||||
pub frame_requests: Vec<Rc<WlCallback>>,
|
|
||||||
pub presentation_feedbacks: Vec<Rc<WpPresentationFeedback>>,
|
|
||||||
pub output_id: OutputNodeId,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for RenderResult {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
frame_requests: Default::default(),
|
|
||||||
presentation_feedbacks: Default::default(),
|
|
||||||
output_id: OutputNodeId::none(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RenderResult {
|
|
||||||
pub fn dispatch_frame_requests(&mut self, now: u64) {
|
|
||||||
for fr in self.frame_requests.drain(..) {
|
|
||||||
fr.send_done(now as _);
|
|
||||||
let _ = fr.client.remove_obj(&*fr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn discard_presentation_feedback(&mut self) {
|
|
||||||
for fb in self.presentation_feedbacks.drain(..) {
|
|
||||||
fb.send_discarded();
|
|
||||||
let _ = fb.client.remove_obj(&*fb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for RenderResult {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
f.debug_struct("RenderResult").finish_non_exhaustive()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Renderer<'a> {
|
pub struct Renderer<'a> {
|
||||||
pub base: RendererBase<'a>,
|
pub base: RendererBase<'a>,
|
||||||
pub state: &'a State,
|
pub state: &'a State,
|
||||||
pub result: Option<&'a mut RenderResult>,
|
|
||||||
pub logical_extents: Rect,
|
pub logical_extents: Rect,
|
||||||
pub pixel_extents: Rect,
|
pub pixel_extents: Rect,
|
||||||
}
|
}
|
||||||
|
|
@ -437,17 +389,6 @@ impl Renderer<'_> {
|
||||||
} else {
|
} else {
|
||||||
self.render_buffer(surface, &buffer, alpha, x, y, *tpoints, size, bounds);
|
self.render_buffer(surface, &buffer, alpha, x, y, *tpoints, size, bounds);
|
||||||
}
|
}
|
||||||
if let Some(result) = self.result.as_deref_mut() {
|
|
||||||
{
|
|
||||||
let mut fr = surface.frame_requests.borrow_mut();
|
|
||||||
result.frame_requests.extend(fr.drain(..));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let mut fbs = surface.presentation_feedback.borrow_mut();
|
|
||||||
result.presentation_feedbacks.extend(fbs.drain(..));
|
|
||||||
}
|
|
||||||
surface.presented(result.output_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_buffer(
|
pub fn render_buffer(
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,6 @@ pub fn take_screenshot(
|
||||||
state.root.deref(),
|
state.root.deref(),
|
||||||
state,
|
state,
|
||||||
Some(state.root.extents.get()),
|
Some(state.root.extents.get()),
|
||||||
None,
|
|
||||||
Scale::from_int(1),
|
Scale::from_int(1),
|
||||||
include_cursor,
|
include_cursor,
|
||||||
true,
|
true,
|
||||||
|
|
|
||||||
24
src/state.rs
24
src/state.rs
|
|
@ -63,7 +63,7 @@ use {
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
logger::Logger,
|
logger::Logger,
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
renderer::{RenderResult, Renderer},
|
renderer::Renderer,
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
security_context_acceptor::SecurityContextAcceptors,
|
security_context_acceptor::SecurityContextAcceptors,
|
||||||
theme::{Color, Theme},
|
theme::{Color, Theme},
|
||||||
|
|
@ -300,6 +300,7 @@ pub struct ConnectorData {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub drm_dev: Option<Rc<DrmDevData>>,
|
pub drm_dev: Option<Rc<DrmDevData>>,
|
||||||
pub async_event: Rc<AsyncEvent>,
|
pub async_event: Rc<AsyncEvent>,
|
||||||
|
pub damaged: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OutputData {
|
pub struct OutputData {
|
||||||
|
|
@ -321,6 +322,14 @@ pub struct DrmDevData {
|
||||||
pub lease_global: Rc<WpDrmLeaseDeviceV1Global>,
|
pub lease_global: Rc<WpDrmLeaseDeviceV1Global>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ConnectorData {
|
||||||
|
pub fn damage(&self) {
|
||||||
|
if !self.damaged.replace(true) {
|
||||||
|
self.connector.damage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl DrmDevData {
|
impl DrmDevData {
|
||||||
pub fn make_render_device(&self) {
|
pub fn make_render_device(&self) {
|
||||||
log::info!(
|
log::info!(
|
||||||
|
|
@ -761,7 +770,7 @@ impl State {
|
||||||
if cursor && output.schedule.defer_cursor_updates() {
|
if cursor && output.schedule.defer_cursor_updates() {
|
||||||
output.schedule.software_cursor_changed();
|
output.schedule.software_cursor_changed();
|
||||||
} else {
|
} else {
|
||||||
output.global.connector.connector.damage();
|
output.global.connector.damage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -892,19 +901,17 @@ impl State {
|
||||||
output: &OutputNode,
|
output: &OutputNode,
|
||||||
fb: &Rc<dyn GfxFramebuffer>,
|
fb: &Rc<dyn GfxFramebuffer>,
|
||||||
tex: &Rc<dyn GfxTexture>,
|
tex: &Rc<dyn GfxTexture>,
|
||||||
rr: &mut RenderResult,
|
|
||||||
render_hw_cursor: bool,
|
render_hw_cursor: bool,
|
||||||
) -> Result<Option<SyncFile>, GfxError> {
|
) -> Result<Option<SyncFile>, GfxError> {
|
||||||
let sync_file = fb.render_output(
|
let sync_file = fb.render_output(
|
||||||
output,
|
output,
|
||||||
self,
|
self,
|
||||||
Some(output.global.pos.get()),
|
Some(output.global.pos.get()),
|
||||||
Some(rr),
|
|
||||||
output.global.persistent.scale.get(),
|
output.global.persistent.scale.get(),
|
||||||
render_hw_cursor,
|
render_hw_cursor,
|
||||||
)?;
|
)?;
|
||||||
|
output.latched();
|
||||||
output.perform_screencopies(tex, !render_hw_cursor, 0, 0, None);
|
output.perform_screencopies(tex, !render_hw_cursor, 0, 0, None);
|
||||||
rr.dispatch_frame_requests(self.now_msec());
|
|
||||||
Ok(sync_file)
|
Ok(sync_file)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -923,7 +930,6 @@ impl State {
|
||||||
let mut renderer = Renderer {
|
let mut renderer = Renderer {
|
||||||
base: target.renderer_base(&mut ops, Scale::from_int(1), Transform::None),
|
base: target.renderer_base(&mut ops, Scale::from_int(1), Transform::None),
|
||||||
state: self,
|
state: self,
|
||||||
result: None,
|
|
||||||
logical_extents: position.at_point(0, 0),
|
logical_extents: position.at_point(0, 0),
|
||||||
pixel_extents: {
|
pixel_extents: {
|
||||||
let (width, height) = target.logical_size(Transform::None);
|
let (width, height) = target.logical_size(Transform::None);
|
||||||
|
|
@ -1173,6 +1179,12 @@ impl State {
|
||||||
self.ei_acceptor_future.take();
|
self.ei_acceptor_future.take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn vblank(&self, connector: ConnectorId) {
|
||||||
|
if let Some(output) = self.root.outputs.get(&connector) {
|
||||||
|
output.vblank();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ pub fn handle(state: &Rc<State>, connector: &Rc<dyn Connector>) {
|
||||||
name: connector.kernel_id().to_string(),
|
name: connector.kernel_id().to_string(),
|
||||||
drm_dev: drm_dev.clone(),
|
drm_dev: drm_dev.clone(),
|
||||||
async_event: Rc::new(AsyncEvent::default()),
|
async_event: Rc::new(AsyncEvent::default()),
|
||||||
|
damaged: Cell::new(false),
|
||||||
});
|
});
|
||||||
if let Some(dev) = drm_dev {
|
if let Some(dev) = drm_dev {
|
||||||
dev.connectors.set(id, data.clone());
|
dev.connectors.set(id, data.clone());
|
||||||
|
|
@ -137,7 +138,7 @@ impl ConnectorHandler {
|
||||||
let schedule = Rc::new(OutputSchedule::new(
|
let schedule = Rc::new(OutputSchedule::new(
|
||||||
&self.state.ring,
|
&self.state.ring,
|
||||||
&self.state.eng,
|
&self.state.eng,
|
||||||
&self.data.connector,
|
&self.data,
|
||||||
&desired_state,
|
&desired_state,
|
||||||
));
|
));
|
||||||
let _schedule = self.state.eng.spawn(schedule.clone().drive());
|
let _schedule = self.state.eng.spawn(schedule.clone().drive());
|
||||||
|
|
@ -176,6 +177,8 @@ impl ConnectorHandler {
|
||||||
title_visible: Default::default(),
|
title_visible: Default::default(),
|
||||||
schedule,
|
schedule,
|
||||||
latch_event: Default::default(),
|
latch_event: Default::default(),
|
||||||
|
vblank_event: Default::default(),
|
||||||
|
presentation_event: Default::default(),
|
||||||
});
|
});
|
||||||
on.update_visible();
|
on.update_visible();
|
||||||
on.update_rects();
|
on.update_rects();
|
||||||
|
|
|
||||||
|
|
@ -81,12 +81,30 @@ pub struct OutputNode {
|
||||||
pub title_visible: Cell<bool>,
|
pub title_visible: Cell<bool>,
|
||||||
pub schedule: Rc<OutputSchedule>,
|
pub schedule: Rc<OutputSchedule>,
|
||||||
pub latch_event: EventSource<dyn LatchListener>,
|
pub latch_event: EventSource<dyn LatchListener>,
|
||||||
|
pub vblank_event: EventSource<dyn VblankListener>,
|
||||||
|
pub presentation_event: EventSource<dyn PresentationListener>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait LatchListener {
|
pub trait LatchListener {
|
||||||
fn after_latch(self: Rc<Self>);
|
fn after_latch(self: Rc<Self>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait VblankListener {
|
||||||
|
fn after_vblank(self: Rc<Self>);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait PresentationListener {
|
||||||
|
fn presented(
|
||||||
|
self: Rc<Self>,
|
||||||
|
output: &OutputNode,
|
||||||
|
tv_sec: u64,
|
||||||
|
tv_nsec: u32,
|
||||||
|
refresh: u32,
|
||||||
|
seq: u64,
|
||||||
|
flags: u32,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
pub enum PointerType {
|
pub enum PointerType {
|
||||||
Seat(SeatId),
|
Seat(SeatId),
|
||||||
|
|
@ -106,6 +124,25 @@ pub async fn output_render_data(state: Rc<State>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutputNode {
|
impl OutputNode {
|
||||||
|
pub fn latched(&self) {
|
||||||
|
self.schedule.latched();
|
||||||
|
for listener in self.latch_event.iter() {
|
||||||
|
listener.after_latch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn vblank(&self) {
|
||||||
|
for listener in self.vblank_event.iter() {
|
||||||
|
listener.after_vblank();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn presented(&self, tv_sec: u64, tv_nsec: u32, refresh: u32, seq: u64, flags: u32) {
|
||||||
|
for listener in self.presentation_event.iter() {
|
||||||
|
listener.presented(self, tv_sec, tv_nsec, refresh, seq, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update_exclusive_zones(self: &Rc<Self>) {
|
pub fn update_exclusive_zones(self: &Rc<Self>) {
|
||||||
let mut exclusive = ExclusiveSize::default();
|
let mut exclusive = ExclusiveSize::default();
|
||||||
for layer in &self.layers {
|
for layer in &self.layers {
|
||||||
|
|
@ -153,9 +190,6 @@ impl OutputNode {
|
||||||
y_off: i32,
|
y_off: i32,
|
||||||
size: Option<(i32, i32)>,
|
size: Option<(i32, i32)>,
|
||||||
) {
|
) {
|
||||||
for listener in self.latch_event.iter() {
|
|
||||||
listener.after_latch();
|
|
||||||
}
|
|
||||||
if let Some(workspace) = self.workspace.get() {
|
if let Some(workspace) = self.workspace.get() {
|
||||||
if !workspace.may_capture.get() {
|
if !workspace.may_capture.get() {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue