anvil: flatten DrmRenderer into AnvilState
This commit is contained in:
parent
4bf6bfa08d
commit
85440840c8
|
@ -45,6 +45,7 @@ pub struct AnvilState<BackendData> {
|
||||||
pub pointer_location: Rc<RefCell<(f64, f64)>>,
|
pub pointer_location: Rc<RefCell<(f64, f64)>>,
|
||||||
pub cursor_status: Arc<Mutex<CursorImageStatus>>,
|
pub cursor_status: Arc<Mutex<CursorImageStatus>>,
|
||||||
pub seat_name: String,
|
pub seat_name: String,
|
||||||
|
pub start_time: std::time::Instant,
|
||||||
#[cfg(feature = "egl")]
|
#[cfg(feature = "egl")]
|
||||||
pub egl_reader: Rc<RefCell<Option<EGLBufferReader>>>,
|
pub egl_reader: Rc<RefCell<Option<EGLBufferReader>>>,
|
||||||
// things we must keep alive
|
// things we must keep alive
|
||||||
|
@ -169,7 +170,9 @@ impl<BackendData: Backend + 'static> AnvilState<BackendData> {
|
||||||
cursor_status,
|
cursor_status,
|
||||||
pointer_location: Rc::new(RefCell::new((0.0, 0.0))),
|
pointer_location: Rc::new(RefCell::new((0.0, 0.0))),
|
||||||
seat_name,
|
seat_name,
|
||||||
|
#[cfg(feature = "egl")]
|
||||||
egl_reader,
|
egl_reader,
|
||||||
|
start_time: std::time::Instant::now(),
|
||||||
#[cfg(feature = "xwayland")]
|
#[cfg(feature = "xwayland")]
|
||||||
_xwayland,
|
_xwayland,
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::{
|
||||||
os::unix::io::{AsRawFd, RawFd},
|
os::unix::io::{AsRawFd, RawFd},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::{atomic::Ordering, Arc, Mutex},
|
sync::atomic::Ordering,
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -78,6 +78,7 @@ pub struct UdevData {
|
||||||
backends: HashMap<dev_t, BackendData>,
|
backends: HashMap<dev_t, BackendData>,
|
||||||
signaler: Signaler<SessionSignal>,
|
signaler: Signaler<SessionSignal>,
|
||||||
pointer_image: ImageBuffer<Rgba<u8>, Vec<u8>>,
|
pointer_image: ImageBuffer<Rgba<u8>, Vec<u8>>,
|
||||||
|
render_timer: TimerHandle<(u64, crtc::Handle)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Backend for UdevData {
|
impl Backend for UdevData {
|
||||||
|
@ -116,6 +117,10 @@ pub fn run_udev(
|
||||||
*/
|
*/
|
||||||
let pointer_bytes = include_bytes!("../resources/cursor2.rgba");
|
let pointer_bytes = include_bytes!("../resources/cursor2.rgba");
|
||||||
let primary_gpu = primary_gpu(&session.seat()).unwrap_or_default();
|
let primary_gpu = primary_gpu(&session.seat()).unwrap_or_default();
|
||||||
|
|
||||||
|
// setup the timer
|
||||||
|
let timer = Timer::new().unwrap();
|
||||||
|
|
||||||
let data = UdevData {
|
let data = UdevData {
|
||||||
session,
|
session,
|
||||||
output_map: output_map.clone(),
|
output_map: output_map.clone(),
|
||||||
|
@ -123,6 +128,7 @@ pub fn run_udev(
|
||||||
backends: HashMap::new(),
|
backends: HashMap::new(),
|
||||||
signaler: session_signal.clone(),
|
signaler: session_signal.clone(),
|
||||||
pointer_image: ImageBuffer::from_raw(64, 64, pointer_bytes.to_vec()).unwrap(),
|
pointer_image: ImageBuffer::from_raw(64, 64, pointer_bytes.to_vec()).unwrap(),
|
||||||
|
render_timer: timer.handle(),
|
||||||
};
|
};
|
||||||
let mut state = AnvilState::init(
|
let mut state = AnvilState::init(
|
||||||
display.clone(),
|
display.clone(),
|
||||||
|
@ -133,6 +139,14 @@ pub fn run_udev(
|
||||||
log.clone(),
|
log.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// re-render timer
|
||||||
|
event_loop
|
||||||
|
.handle()
|
||||||
|
.insert_source(timer, |(dev_id, crtc), _, anvil_state| {
|
||||||
|
anvil_state.render(dev_id, Some(crtc))
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the udev backend
|
* Initialize the udev backend
|
||||||
*/
|
*/
|
||||||
|
@ -277,6 +291,8 @@ struct BackendData {
|
||||||
gbm: GbmDevice<SessionFd>,
|
gbm: GbmDevice<SessionFd>,
|
||||||
registration_token: RegistrationToken,
|
registration_token: RegistrationToken,
|
||||||
event_dispatcher: Dispatcher<'static, DrmDevice<SessionFd>, AnvilState<UdevData>>,
|
event_dispatcher: Dispatcher<'static, DrmDevice<SessionFd>, AnvilState<UdevData>>,
|
||||||
|
dev_id: u64,
|
||||||
|
pointer_image: Gles2Texture,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scan_connectors(
|
pub fn scan_connectors(
|
||||||
|
@ -466,49 +482,25 @@ impl AnvilState<UdevData> {
|
||||||
.expect("Failed to load pointer")
|
.expect("Failed to load pointer")
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set the handler.
|
let dev_id = device.device_id();
|
||||||
// Note: if you replicate this (very simple) structure, it is rather easy
|
let handle = self.handle.clone();
|
||||||
// to introduce reference cycles with Rc. Be sure about your drop order
|
|
||||||
let renderer = Rc::new(DrmRenderer {
|
|
||||||
device_id,
|
|
||||||
#[cfg(feature = "egl")]
|
|
||||||
egl_buffer_reader: if is_primary {
|
|
||||||
self.egl_reader.borrow().clone()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
compositor_token: self.ctoken,
|
|
||||||
backends: backends.clone(),
|
|
||||||
window_map: self.window_map.clone(),
|
|
||||||
output_map: self.backend_data.output_map.clone(),
|
|
||||||
pointer_location: self.pointer_location.clone(),
|
|
||||||
pointer_image,
|
|
||||||
cursor_status: self.cursor_status.clone(),
|
|
||||||
dnd_icon: self.dnd_icon.clone(),
|
|
||||||
logger: self.log.clone(),
|
|
||||||
start_time: std::time::Instant::now(),
|
|
||||||
});
|
|
||||||
let mut listener = DrmRendererSessionListener {
|
|
||||||
renderer: renderer.clone(),
|
|
||||||
loop_handle: self.handle.clone(),
|
|
||||||
};
|
|
||||||
let restart_token = self.backend_data.signaler.register(move |signal| match signal {
|
let restart_token = self.backend_data.signaler.register(move |signal| match signal {
|
||||||
SessionSignal::ActivateSession | SessionSignal::ActivateDevice { .. } => listener.activate(),
|
SessionSignal::ActivateSession | SessionSignal::ActivateDevice { .. } => {
|
||||||
|
handle.insert_idle(move |anvil_state| anvil_state.render(dev_id, None));
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
});
|
});
|
||||||
let mut drm_handler = DrmHandlerImpl {
|
|
||||||
renderer,
|
|
||||||
loop_handle: self.handle.clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
device.link(self.backend_data.signaler.clone());
|
device.link(self.backend_data.signaler.clone());
|
||||||
let dev_id = device.device_id();
|
let event_dispatcher = Dispatcher::new(
|
||||||
let event_dispatcher = Dispatcher::new(device, move |event, _, _| match event {
|
device,
|
||||||
DrmEvent::VBlank(crtc) => drm_handler.vblank(crtc),
|
move |event, _, anvil_state: &mut AnvilState<_>| match event {
|
||||||
|
DrmEvent::VBlank(crtc) => anvil_state.render(dev_id, Some(crtc)),
|
||||||
DrmEvent::Error(error) => {
|
DrmEvent::Error(error) => {
|
||||||
error!(drm_handler.renderer.logger, "{:?}", error);
|
error!(anvil_state.log, "{:?}", error);
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
);
|
||||||
let registration_token = self.handle.register_dispatcher(event_dispatcher.clone()).unwrap();
|
let registration_token = self.handle.register_dispatcher(event_dispatcher.clone()).unwrap();
|
||||||
|
|
||||||
trace!(self.log, "Backends: {:?}", backends.borrow().keys());
|
trace!(self.log, "Backends: {:?}", backends.borrow().keys());
|
||||||
|
@ -528,6 +520,8 @@ impl AnvilState<UdevData> {
|
||||||
egl,
|
egl,
|
||||||
context,
|
context,
|
||||||
gbm,
|
gbm,
|
||||||
|
pointer_image,
|
||||||
|
dev_id,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -591,80 +585,50 @@ impl AnvilState<UdevData> {
|
||||||
debug!(self.log, "Dropping device");
|
debug!(self.log, "Dropping device");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DrmHandlerImpl<Data: 'static> {
|
// If crtc is `Some()`, render it, else render all crtcs
|
||||||
renderer: Rc<DrmRenderer>,
|
fn render(&mut self, dev_id: u64, crtc: Option<crtc::Handle>) {
|
||||||
loop_handle: LoopHandle<'static, Data>,
|
let device_backend = match self.backend_data.backends.get_mut(&dev_id) {
|
||||||
}
|
Some(backend) => backend,
|
||||||
|
None => {
|
||||||
impl<Data: 'static> DrmHandlerImpl<Data> {
|
error!(self.log, "Trying to render on non-existent backend {}", dev_id);
|
||||||
fn vblank(&mut self, crtc: crtc::Handle) {
|
return;
|
||||||
self.renderer.clone().render(crtc, None, Some(&self.loop_handle))
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
// setup two iterators on the stack, one over all surfaces for this backend, and
|
||||||
|
// one containing only the one given as argument.
|
||||||
|
// They make a trait-object to dynamically choose between the two
|
||||||
|
let surfaces = device_backend.surfaces.borrow();
|
||||||
|
let mut surfaces_iter = surfaces.iter();
|
||||||
|
let mut option_iter = crtc
|
||||||
|
.iter()
|
||||||
|
.flat_map(|crtc| surfaces.get(&crtc).map(|surface| (crtc, surface)));
|
||||||
|
|
||||||
pub struct DrmRendererSessionListener<Data: 'static> {
|
let to_render_iter: &mut dyn Iterator<Item = (&crtc::Handle, &Rc<RefCell<RenderSurface>>)> =
|
||||||
renderer: Rc<DrmRenderer>,
|
if crtc.is_some() {
|
||||||
loop_handle: LoopHandle<'static, Data>,
|
&mut option_iter
|
||||||
}
|
} else {
|
||||||
|
&mut surfaces_iter
|
||||||
|
};
|
||||||
|
|
||||||
impl<Data: 'static> DrmRendererSessionListener<Data> {
|
for (&crtc, surface) in to_render_iter {
|
||||||
fn activate(&mut self) {
|
let result = render_surface(
|
||||||
// we want to be called, after all session handling is done (TODO this is not so nice)
|
|
||||||
let renderer = self.renderer.clone();
|
|
||||||
let handle = self.loop_handle.clone();
|
|
||||||
self.loop_handle
|
|
||||||
.insert_idle(move |_| renderer.render_all(Some(&handle)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DrmRenderer {
|
|
||||||
device_id: dev_t,
|
|
||||||
#[cfg(feature = "egl")]
|
|
||||||
egl_buffer_reader: Option<EGLBufferReader>,
|
|
||||||
compositor_token: CompositorToken<Roles>,
|
|
||||||
backends: Rc<RefCell<HashMap<crtc::Handle, Rc<RefCell<RenderSurface>>>>>,
|
|
||||||
window_map: Rc<RefCell<MyWindowMap>>,
|
|
||||||
output_map: Rc<RefCell<Vec<MyOutput>>>,
|
|
||||||
pointer_location: Rc<RefCell<(f64, f64)>>,
|
|
||||||
pointer_image: Gles2Texture,
|
|
||||||
cursor_status: Arc<Mutex<CursorImageStatus>>,
|
|
||||||
dnd_icon: Arc<Mutex<Option<wl_surface::WlSurface>>>,
|
|
||||||
logger: ::slog::Logger,
|
|
||||||
start_time: std::time::Instant,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DrmRenderer {
|
|
||||||
fn render_all<Data: 'static>(self: Rc<Self>, evt_handle: Option<&LoopHandle<'static, Data>>) {
|
|
||||||
for crtc in self.backends.borrow().keys() {
|
|
||||||
self.clone().render(*crtc, None, evt_handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn render<Data: 'static>(
|
|
||||||
self: Rc<Self>,
|
|
||||||
crtc: crtc::Handle,
|
|
||||||
timer: Option<TimerHandle<(std::rc::Weak<DrmRenderer>, crtc::Handle)>>,
|
|
||||||
evt_handle: Option<&LoopHandle<'static, Data>>,
|
|
||||||
) {
|
|
||||||
if let Some(surface) = self.backends.borrow().get(&crtc) {
|
|
||||||
let result = DrmRenderer::render_surface(
|
|
||||||
&mut *surface.borrow_mut(),
|
&mut *surface.borrow_mut(),
|
||||||
#[cfg(feature = "egl")]
|
#[cfg(feature = "egl")]
|
||||||
self.egl_buffer_reader.as_ref(),
|
self.egl_reader.borrow().as_ref(),
|
||||||
self.device_id,
|
device_backend.dev_id,
|
||||||
crtc,
|
crtc,
|
||||||
&mut *self.window_map.borrow_mut(),
|
&mut *self.window_map.borrow_mut(),
|
||||||
&mut *self.output_map.borrow_mut(),
|
&mut *self.backend_data.output_map.borrow_mut(),
|
||||||
&self.compositor_token,
|
&self.ctoken,
|
||||||
&*self.pointer_location.borrow(),
|
&*self.pointer_location.borrow(),
|
||||||
&self.pointer_image,
|
&device_backend.pointer_image,
|
||||||
&*self.dnd_icon.lock().unwrap(),
|
&*self.dnd_icon.lock().unwrap(),
|
||||||
&mut *self.cursor_status.lock().unwrap(),
|
&mut *self.cursor_status.lock().unwrap(),
|
||||||
&self.logger,
|
&self.log,
|
||||||
);
|
);
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
warn!(self.logger, "Error during rendering: {:?}", err);
|
warn!(self.log, "Error during rendering: {:?}", err);
|
||||||
let reschedule = match err {
|
let reschedule = match err {
|
||||||
SwapBuffersError::AlreadySwapped => false,
|
SwapBuffersError::AlreadySwapped => false,
|
||||||
SwapBuffersError::TemporaryFailure(err) => !matches!(
|
SwapBuffersError::TemporaryFailure(err) => !matches!(
|
||||||
|
@ -679,36 +643,12 @@ impl DrmRenderer {
|
||||||
};
|
};
|
||||||
|
|
||||||
if reschedule {
|
if reschedule {
|
||||||
debug!(self.logger, "Rescheduling");
|
debug!(self.log, "Rescheduling");
|
||||||
match (timer, evt_handle) {
|
self.backend_data.render_timer.add_timeout(
|
||||||
(Some(handle), _) => {
|
|
||||||
let _ = handle.add_timeout(
|
|
||||||
Duration::from_millis(1000 /*a seconds*/ / 60 /*refresh rate*/),
|
Duration::from_millis(1000 /*a seconds*/ / 60 /*refresh rate*/),
|
||||||
(Rc::downgrade(&self), crtc),
|
(device_backend.dev_id, crtc),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
(None, Some(evt_handle)) => {
|
|
||||||
let timer = Timer::new().unwrap();
|
|
||||||
let handle = timer.handle();
|
|
||||||
let _ = handle.add_timeout(
|
|
||||||
Duration::from_millis(1000 /*a seconds*/ / 60 /*refresh rate*/),
|
|
||||||
(Rc::downgrade(&self), crtc),
|
|
||||||
);
|
|
||||||
evt_handle
|
|
||||||
.insert_source(timer, |(renderer, crtc), handle, _data| {
|
|
||||||
if let Some(renderer) = renderer.upgrade() {
|
|
||||||
renderer.render(
|
|
||||||
crtc,
|
|
||||||
Some(handle.clone()),
|
|
||||||
Option::<&LoopHandle<'static, Data>>::None,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// TODO: only send drawn windows the frames callback
|
// TODO: only send drawn windows the frames callback
|
||||||
// Send frame events so that client start drawing their next frame
|
// Send frame events so that client start drawing their next frame
|
||||||
|
@ -718,9 +658,10 @@ impl DrmRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn render_surface(
|
fn render_surface(
|
||||||
surface: &mut RenderSurface,
|
surface: &mut RenderSurface,
|
||||||
#[cfg(feature = "egl")] egl_buffer_reader: Option<&EGLBufferReader>,
|
#[cfg(feature = "egl")] egl_buffer_reader: Option<&EGLBufferReader>,
|
||||||
device_id: dev_t,
|
device_id: dev_t,
|
||||||
|
@ -733,7 +674,7 @@ impl DrmRenderer {
|
||||||
dnd_icon: &Option<wl_surface::WlSurface>,
|
dnd_icon: &Option<wl_surface::WlSurface>,
|
||||||
cursor_status: &mut CursorImageStatus,
|
cursor_status: &mut CursorImageStatus,
|
||||||
logger: &slog::Logger,
|
logger: &slog::Logger,
|
||||||
) -> Result<(), SwapBuffersError> {
|
) -> Result<(), SwapBuffersError> {
|
||||||
#[cfg(not(feature = "egl"))]
|
#[cfg(not(feature = "egl"))]
|
||||||
let egl_buffer_reader = None;
|
let egl_buffer_reader = None;
|
||||||
|
|
||||||
|
@ -825,7 +766,6 @@ impl DrmRenderer {
|
||||||
.map_err(Into::<SwapBuffersError>::into)
|
.map_err(Into::<SwapBuffersError>::into)
|
||||||
.and_then(|x| x)
|
.and_then(|x| x)
|
||||||
.map_err(Into::<SwapBuffersError>::into)
|
.map_err(Into::<SwapBuffersError>::into)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn schedule_initial_render<Data: 'static>(
|
fn schedule_initial_render<Data: 'static>(
|
||||||
|
|
Loading…
Reference in New Issue