anvil: Fixup udev/tty backend, so that it runs at least

This commit is contained in:
Victor Brekenfeld 2021-04-25 23:44:02 +02:00
parent 243afb1030
commit 43d3e9cd14
3 changed files with 281 additions and 175 deletions

View File

@ -9,7 +9,8 @@ edition = "2018"
[dependencies] [dependencies]
bitflags = "1.2.1" bitflags = "1.2.1"
input = { version = "0.5.0", features = ["udev"], optional = true } input = { version = "0.5.0", features = ["udev"], optional = true }
rand = "0.8" image = { version = "0.23.0", optional = true, default-features = false }
rand = "0.7"
slog = { version = "2.1.1" } slog = { version = "2.1.1" }
slog-term = "2.8" slog-term = "2.8"
slog-async = "2.2" slog-async = "2.2"
@ -30,10 +31,10 @@ features = [ "composite" ]
gl_generator = "0.14" gl_generator = "0.14"
[features] [features]
default = [ "winit", "egl", "udev", "logind", "xwayland" ] default = [ "winit", "udev", "logind", "xwayland" ]
egl = [ "smithay/use_system_lib" ] egl = [ "smithay/use_system_lib" ]
winit = [ "smithay/backend_winit" ] winit = [ "smithay/backend_winit" ]
udev = [ "smithay/backend_libinput", "smithay/backend_udev", "smithay/backend_drm", "smithay/backend_gbm", "smithay/backend_egl", "smithay/backend_session", "input" ] udev = [ "smithay/backend_libinput", "smithay/backend_udev", "smithay/backend_drm", "smithay/backend_gbm", "smithay/backend_egl", "smithay/backend_session", "input", "image"]
logind = [ "smithay/backend_session_logind" ] logind = [ "smithay/backend_session_logind" ]
elogind = ["logind", "smithay/backend_session_elogind" ] elogind = ["logind", "smithay/backend_session_elogind" ]
xwayland = [ "smithay/xwayland", "x11rb" ] xwayland = [ "smithay/xwayland", "x11rb" ]

View File

@ -1,9 +1,16 @@
use std::cell::RefCell; use std::{
cell::RefCell,
rc::Rc,
};
use slog::Logger; use slog::Logger;
use smithay::{ use smithay::{
backend::renderer::{Renderer, Frame, Transform, Texture}, backend::SwapBuffersError,
reexports::{wayland_server::protocol::wl_surface}, backend::renderer::{Renderer, Transform, Texture},
reexports::{
calloop::LoopHandle,
wayland_server::protocol::wl_surface,
},
utils::Rectangle, utils::Rectangle,
wayland::{ wayland::{
compositor::{roles::Role, SubsurfaceRole, TraversalAction}, compositor::{roles::Role, SubsurfaceRole, TraversalAction},
@ -190,24 +197,31 @@ pub fn draw_dnd_icon<R, E, T>(
draw_surface_tree(renderer, surface, (x, y), token, log); draw_surface_tree(renderer, surface, (x, y), token, log);
} }
/* pub fn schedule_initial_render<R: Renderer + 'static, Data: 'static>(
pub fn schedule_initial_render<F: GLGraphicsBackend + 'static, Data: 'static>( renderer: Rc<RefCell<R>>,
renderer: Rc<GliumDrawer<F>>,
evt_handle: &LoopHandle<Data>, evt_handle: &LoopHandle<Data>,
) { logger: ::slog::Logger,
let mut frame = renderer.draw(); )
frame.clear_color(0.8, 0.8, 0.9, 1.0); where
if let Err(err) = frame.set_finish() { <R as Renderer>::Error: Into<SwapBuffersError>
{
let result = {
let mut renderer = renderer.borrow_mut();
// Does not matter if we render an empty frame
renderer.begin(1, 1, Transform::Normal).map_err(Into::<SwapBuffersError>::into)
.and_then(|_| renderer.clear([0.8, 0.8, 0.9, 1.0]).map_err(Into::<SwapBuffersError>::into))
.and_then(|_| renderer.finish())
};
if let Err(err) = result {
match err { match err {
SwapBuffersError::AlreadySwapped => {} SwapBuffersError::AlreadySwapped => {}
SwapBuffersError::TemporaryFailure(err) => { SwapBuffersError::TemporaryFailure(err) => {
// TODO dont reschedule after 3(?) retries // TODO dont reschedule after 3(?) retries
warn!(renderer.log, "Failed to submit page_flip: {}", err); warn!(logger, "Failed to submit page_flip: {}", err);
let handle = evt_handle.clone(); let handle = evt_handle.clone();
evt_handle.insert_idle(move |_| schedule_initial_render(renderer, &handle)); evt_handle.insert_idle(move |_| schedule_initial_render(renderer, &handle, logger));
} }
SwapBuffersError::ContextLost(err) => panic!("Rendering loop lost: {}", err), SwapBuffersError::ContextLost(err) => panic!("Rendering loop lost: {}", err),
} }
} }
} }
*/

View File

@ -9,24 +9,26 @@ use std::{
time::Duration, time::Duration,
}; };
use glium::Surface as GliumSurface; use image::{ImageBuffer, Rgba};
use slog::Logger; use slog::Logger;
#[cfg(feature = "egl")]
use smithay::backend::egl::{display::EGLBufferReader, EGLGraphicsBackend};
use smithay::{ use smithay::{
backend::{ backend::{
drm_old::{ SwapBuffersError,
atomic::{AtomicDrmDevice, AtomicDrmSurface}, drm::{
common::fallback::{FallbackDevice, FallbackSurface}, DrmDevice,
DeviceHandler,
device_bind, device_bind,
egl::{EglDevice, EglSurface}, DrmRenderSurface,
eglstream::{egl::EglStreamDeviceBackend, EglStreamDevice, EglStreamSurface}, DrmError,
gbm::{egl::Gbm as EglGbmBackend, GbmDevice, GbmSurface}, DrmRenderError,
legacy::{LegacyDrmDevice, LegacyDrmSurface}, },
DevPath, Device, DeviceHandler, Surface, egl::{EGLDisplay, EGLContext},
renderer::{
Renderer,
gles2::Gles2Renderer,
Transform,
}, },
graphics::{CursorBackend, SwapBuffersError},
libinput::{LibinputInputBackend, LibinputSessionInterface}, libinput::{LibinputInputBackend, LibinputSessionInterface},
session::{auto::AutoSession, Session, Signal as SessionSignal}, session::{auto::AutoSession, Session, Signal as SessionSignal},
udev::{primary_gpu, UdevBackend, UdevEvent}, udev::{primary_gpu, UdevBackend, UdevEvent},
@ -40,12 +42,16 @@ use smithay::{
drm::{ drm::{
self, self,
control::{ control::{
Device as ControlDevice,
connector::{Info as ConnectorInfo, State as ConnectorState}, connector::{Info as ConnectorInfo, State as ConnectorState},
crtc, crtc,
encoder::Info as EncoderInfo, encoder::Info as EncoderInfo,
}, },
}, },
image::{ImageBuffer, Rgba}, gbm::{
BufferObject as GbmBuffer,
Device as GbmDevice,
},
input::Libinput, input::Libinput,
nix::{fcntl::OFlag, sys::stat::dev_t}, nix::{fcntl::OFlag, sys::stat::dev_t},
wayland_server::{ wayland_server::{
@ -63,9 +69,9 @@ use smithay::{
}; };
use crate::buffer_utils::BufferUtils; use crate::buffer_utils::BufferUtils;
use crate::glium_drawer::{schedule_initial_render, GliumDrawer};
use crate::shell::{MyWindowMap, Roles}; use crate::shell::{MyWindowMap, Roles};
use crate::state::AnvilState; use crate::state::AnvilState;
use crate::drawing::*;
#[derive(Clone)] #[derive(Clone)]
pub struct SessionFd(RawFd); pub struct SessionFd(RawFd);
@ -75,21 +81,6 @@ impl AsRawFd for SessionFd {
} }
} }
type RenderDevice = FallbackDevice<
EglDevice<
EglGbmBackend<FallbackDevice<AtomicDrmDevice<SessionFd>, LegacyDrmDevice<SessionFd>>>,
GbmDevice<FallbackDevice<AtomicDrmDevice<SessionFd>, LegacyDrmDevice<SessionFd>>>,
>,
EglDevice<
EglStreamDeviceBackend<FallbackDevice<AtomicDrmDevice<SessionFd>, LegacyDrmDevice<SessionFd>>>,
EglStreamDevice<FallbackDevice<AtomicDrmDevice<SessionFd>, LegacyDrmDevice<SessionFd>>>,
>,
>;
type RenderSurface = FallbackSurface<
EglSurface<GbmSurface<FallbackSurface<AtomicDrmSurface<SessionFd>, LegacyDrmSurface<SessionFd>>>>,
EglSurface<EglStreamSurface<FallbackSurface<AtomicDrmSurface<SessionFd>, LegacyDrmSurface<SessionFd>>>>,
>;
pub fn run_udev( pub fn run_udev(
display: Rc<RefCell<Display>>, display: Rc<RefCell<Display>>,
event_loop: &mut EventLoop<AnvilState>, event_loop: &mut EventLoop<AnvilState>,
@ -104,12 +95,14 @@ pub fn run_udev(
info!(log, "Listening on wayland socket"; "name" => name.clone()); info!(log, "Listening on wayland socket"; "name" => name.clone());
::std::env::set_var("WAYLAND_DISPLAY", name); ::std::env::set_var("WAYLAND_DISPLAY", name);
/*
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
let egl_buffer_reader = Rc::new(RefCell::new(None)); let egl_buffer_reader = Rc::new(RefCell::new(None));
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
let buffer_utils = BufferUtils::new(egl_buffer_reader.clone(), log.clone()); let buffer_utils = BufferUtils::new(egl_buffer_reader.clone(), log.clone());
#[cfg(not(feature = "egl"))] #[cfg(not(feature = "egl"))]
*/
let buffer_utils = BufferUtils::new(log.clone()); let buffer_utils = BufferUtils::new(log.clone());
let output_map = Rc::new(RefCell::new(Vec::new())); let output_map = Rc::new(RefCell::new(Vec::new()));
@ -289,17 +282,22 @@ impl Drop for MyOutput {
} }
} }
type RenderSurface = DrmRenderSurface<SessionFd, GbmDevice<SessionFd>, Gles2Renderer, GbmBuffer<()>>;
struct BackendData { struct BackendData {
_restart_token: SignalToken, _restart_token: SignalToken,
event_source: Source<Generic<RenderDevice>>, surfaces: Rc<RefCell<HashMap<crtc::Handle, Rc<RefCell<RenderSurface>>>>>,
surfaces: Rc<RefCell<HashMap<crtc::Handle, Rc<GliumDrawer<RenderSurface>>>>>, context: EGLContext,
egl: EGLDisplay,
gbm: GbmDevice<SessionFd>,
event_source: Source<Generic<DrmDevice<SessionFd>>>,
} }
struct UdevHandlerImpl<Data: 'static> { struct UdevHandlerImpl<Data: 'static> {
compositor_token: CompositorToken<Roles>, compositor_token: CompositorToken<Roles>,
buffer_utils: BufferUtils, buffer_utils: BufferUtils,
#[cfg(feature = "egl")] //#[cfg(feature = "egl")]
egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>, //egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>,
session: AutoSession, session: AutoSession,
backends: HashMap<dev_t, BackendData>, backends: HashMap<dev_t, BackendData>,
display: Rc<RefCell<Display>>, display: Rc<RefCell<Display>>,
@ -317,12 +315,15 @@ struct UdevHandlerImpl<Data: 'static> {
impl<Data: 'static> UdevHandlerImpl<Data> { impl<Data: 'static> UdevHandlerImpl<Data> {
pub fn scan_connectors( pub fn scan_connectors(
device: &mut RenderDevice, device: &mut DrmDevice<SessionFd>,
gbm: &GbmDevice<SessionFd>,
egl: &EGLDisplay,
context: &EGLContext,
buffer_utils: &BufferUtils, buffer_utils: &BufferUtils,
display: &mut Display, display: &mut Display,
output_map: &mut Vec<MyOutput>, output_map: &mut Vec<MyOutput>,
logger: &::slog::Logger, logger: &::slog::Logger,
) -> HashMap<crtc::Handle, Rc<GliumDrawer<RenderSurface>>> { ) -> HashMap<crtc::Handle, Rc<RefCell<RenderSurface>>> {
// Get a set of all modesetting resource handles (excluding planes): // Get a set of all modesetting resource handles (excluding planes):
let res_handles = device.resource_handles().unwrap(); let res_handles = device.resource_handles().unwrap();
@ -330,7 +331,7 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
let connector_infos: Vec<ConnectorInfo> = res_handles let connector_infos: Vec<ConnectorInfo> = res_handles
.connectors() .connectors()
.iter() .iter()
.map(|conn| device.get_connector_info(*conn).unwrap()) .map(|conn| device.get_connector(*conn).unwrap())
.filter(|conn| conn.state() == ConnectorState::Connected) .filter(|conn| conn.state() == ConnectorState::Connected)
.inspect(|conn| info!(logger, "Connected: {:?}", conn.interface())) .inspect(|conn| info!(logger, "Connected: {:?}", conn.interface()))
.collect(); .collect();
@ -343,18 +344,59 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
.encoders() .encoders()
.iter() .iter()
.filter_map(|e| *e) .filter_map(|e| *e)
.flat_map(|encoder_handle| device.get_encoder_info(encoder_handle)) .flat_map(|encoder_handle| device.get_encoder(encoder_handle))
.collect::<Vec<EncoderInfo>>(); .collect::<Vec<EncoderInfo>>();
'outer: for encoder_info in encoder_infos { 'outer: for encoder_info in encoder_infos {
for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) { for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) {
// TODO cursor
let primary = match device.planes(&crtc) {
Ok(planes) => planes.primary,
Err(err) => {
warn!(logger, "Failed to enumerate planes: {}", err);
continue;
}
};
if let Entry::Vacant(entry) = backends.entry(crtc) { if let Entry::Vacant(entry) = backends.entry(crtc) {
let renderer = GliumDrawer::init( info!(logger, "Trying to setup connector {:?}-{} with crtc {:?}",
device connector_info.interface(),
.create_surface(crtc, connector_info.modes()[0], &[connector_info.handle()]) connector_info.interface_id(),
.unwrap(), crtc,
buffer_utils.clone(),
logger.clone(),
); );
let context = match EGLContext::new_shared(egl, context, logger.clone()) {
Ok(context) => context,
Err(err) => {
warn!(logger, "Failed to create EGLContext: {}", err);
continue;
}
};
let renderer = match unsafe { Gles2Renderer::new(context, logger.clone()) } {
Ok(renderer) => renderer,
Err(err) => {
warn!(logger, "Failed to create Gles2 Renderer: {}", err);
continue;
}
};
let surface = match device.create_surface(crtc, primary, connector_info.modes()[0], &[connector_info.handle()]) {
Ok(surface) => surface,
Err(err) => {
warn!(logger, "Failed to create drm surface: {}", err);
continue;
}
};
let renderer = match DrmRenderSurface::new(
surface,
gbm.clone(),
renderer,
logger.clone()
) {
Ok(renderer) => renderer,
Err(err) => {
warn!(logger, "Failed to create rendering surface: {}", err);
continue;
}
};
output_map.push(MyOutput::new( output_map.push(MyOutput::new(
display, display,
device.device_id(), device.device_id(),
@ -363,7 +405,7 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
logger.clone(), logger.clone(),
)); ));
entry.insert(Rc::new(renderer)); entry.insert(Rc::new(RefCell::new(renderer)));
break 'outer; break 'outer;
} }
} }
@ -377,7 +419,7 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
impl<Data: 'static> UdevHandlerImpl<Data> { impl<Data: 'static> UdevHandlerImpl<Data> {
fn device_added(&mut self, device_id: dev_t, path: PathBuf) { fn device_added(&mut self, device_id: dev_t, path: PathBuf) {
// Try to open the device // Try to open the device
if let Some(mut device) = self if let Some((mut device, gbm)) = self
.session .session
.open( .open(
&path, &path,
@ -385,36 +427,35 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
) )
.ok() .ok()
.and_then(|fd| { .and_then(|fd| {
match FallbackDevice::<AtomicDrmDevice<_>, LegacyDrmDevice<_>>::new( match {
SessionFd(fd), let fd = SessionFd(fd);
(
DrmDevice::new(
fd.clone(),
true, true,
self.logger.clone(), self.logger.clone(),
) { ),
Ok(drm) => Some(drm), GbmDevice::new(
Err(err) => { fd.clone()
warn!(self.logger, "Skipping drm device, because of error: {}", err); ),
)
}
{
(Ok(drm), Ok(gbm)) => Some((drm, gbm)),
(Err(err), _) => {
warn!(self.logger, "Skipping device {:?}, because of drm error: {}", device_id, err);
None None
} },
} (_, Err(err)) => {
}) // TODO try DumbBuffer allocator in this case
.and_then(|drm| { warn!(self.logger, "Skipping device {:?}, because of gbm error: {}", device_id, err);
match FallbackDevice::<GbmDevice<_>, EglStreamDevice<_>>::new(drm, self.logger.clone()) {
Ok(dev) => Some(dev),
Err(err) => {
warn!(self.logger, "Skipping device, because of error: {}", err);
None
}
}
})
.and_then(|dev| match FallbackDevice::new_egl(dev, self.logger.clone()) {
Ok(egl) => Some(egl),
Err(err) => {
warn!(self.logger, "Skipping egl device, because of error: {}", err);
None None
},
} }
}) })
{ {
// init hardware acceleration on the primary gpu. // init hardware acceleration on the primary gpu.
/*
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
{ {
if path.canonicalize().ok() == self.primary_gpu { if path.canonicalize().ok() == self.primary_gpu {
@ -426,9 +467,28 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
device.bind_wl_display(&*self.display.borrow()).ok(); device.bind_wl_display(&*self.display.borrow()).ok();
} }
} }
*/
let egl = match EGLDisplay::new(&gbm, self.logger.clone()) {
Ok(display) => display,
Err(err) => {
warn!(self.logger, "Skipping device {:?}, because of egl display error: {}", device_id, err);
return;
}
};
let context = match EGLContext::new(&egl, self.logger.clone()) {
Ok(context) => context,
Err(err) => {
warn!(self.logger, "Skipping device {:?}, because of egl context error: {}", device_id, err);
return;
}
};
let backends = Rc::new(RefCell::new(UdevHandlerImpl::<Data>::scan_connectors( let backends = Rc::new(RefCell::new(UdevHandlerImpl::<Data>::scan_connectors(
&mut device, &mut device,
&gbm,
&egl,
&context,
&self.buffer_utils, &self.buffer_utils,
&mut *self.display.borrow_mut(), &mut *self.display.borrow_mut(),
&mut *self.output_map.borrow_mut(), &mut *self.output_map.borrow_mut(),
@ -470,9 +530,11 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
.map_err(|e| -> IoError { e.into() }) .map_err(|e| -> IoError { e.into() })
.unwrap(); .unwrap();
trace!(self.logger, "Backends: {:?}", backends.borrow().keys());
for renderer in backends.borrow_mut().values() { for renderer in backends.borrow_mut().values() {
// render first frame // render first frame
schedule_initial_render(renderer.clone(), &self.loop_handle); trace!(self.logger, "Scheduling frame");
schedule_initial_render(renderer.clone(), &self.loop_handle, self.logger.clone());
} }
self.backends.insert( self.backends.insert(
@ -481,6 +543,9 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
_restart_token: restart_token, _restart_token: restart_token,
event_source, event_source,
surfaces: backends, surfaces: backends,
egl,
context,
gbm,
}, },
); );
} }
@ -490,7 +555,7 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
//quick and dirty, just re-init all backends //quick and dirty, just re-init all backends
let buffer_utils = &self.buffer_utils; let buffer_utils = &self.buffer_utils;
if let Some(ref mut backend_data) = self.backends.get_mut(&device) { if let Some(ref mut backend_data) = self.backends.get_mut(&device) {
let logger = &self.logger; let logger = self.logger.clone();
let loop_handle = self.loop_handle.clone(); let loop_handle = self.loop_handle.clone();
let mut display = self.display.borrow_mut(); let mut display = self.display.borrow_mut();
let mut output_map = self.output_map.borrow_mut(); let mut output_map = self.output_map.borrow_mut();
@ -500,15 +565,19 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
let mut backends = backend_data.surfaces.borrow_mut(); let mut backends = backend_data.surfaces.borrow_mut();
*backends = UdevHandlerImpl::<Data>::scan_connectors( *backends = UdevHandlerImpl::<Data>::scan_connectors(
&mut source.file, &mut source.file,
&backend_data.gbm,
&backend_data.egl,
&backend_data.context,
buffer_utils, buffer_utils,
&mut *display, &mut *display,
&mut *output_map, &mut *output_map,
logger, &logger,
); );
for renderer in backends.values() { for renderer in backends.values() {
let logger = logger.clone();
// render first frame // render first frame
schedule_initial_render(renderer.clone(), &loop_handle); schedule_initial_render(renderer.clone(), &loop_handle, logger);
} }
}); });
} }
@ -545,13 +614,11 @@ pub struct DrmHandlerImpl<Data: 'static> {
} }
impl<Data: 'static> DeviceHandler for DrmHandlerImpl<Data> { impl<Data: 'static> DeviceHandler for DrmHandlerImpl<Data> {
type Device = RenderDevice;
fn vblank(&mut self, crtc: crtc::Handle) { fn vblank(&mut self, crtc: crtc::Handle) {
self.renderer.clone().render(crtc, None, Some(&self.loop_handle)) self.renderer.clone().render(crtc, None, Some(&self.loop_handle))
} }
fn error(&mut self, error: <RenderSurface as Surface>::Error) { fn error(&mut self, error: DrmError) {
error!(self.renderer.logger, "{:?}", error); error!(self.renderer.logger, "{:?}", error);
} }
} }
@ -574,7 +641,7 @@ impl<Data: 'static> DrmRendererSessionListener<Data> {
pub struct DrmRenderer { pub struct DrmRenderer {
device_id: dev_t, device_id: dev_t,
compositor_token: CompositorToken<Roles>, compositor_token: CompositorToken<Roles>,
backends: Rc<RefCell<HashMap<crtc::Handle, Rc<GliumDrawer<RenderSurface>>>>>, backends: Rc<RefCell<HashMap<crtc::Handle, Rc<RefCell<RenderSurface>>>>>,
window_map: Rc<RefCell<MyWindowMap>>, window_map: Rc<RefCell<MyWindowMap>>,
output_map: Rc<RefCell<Vec<MyOutput>>>, output_map: Rc<RefCell<Vec<MyOutput>>>,
pointer_location: Rc<RefCell<(f64, f64)>>, pointer_location: Rc<RefCell<(f64, f64)>>,
@ -597,93 +664,29 @@ impl DrmRenderer {
timer: Option<TimerHandle<(std::rc::Weak<DrmRenderer>, crtc::Handle)>>, timer: Option<TimerHandle<(std::rc::Weak<DrmRenderer>, crtc::Handle)>>,
evt_handle: Option<&LoopHandle<Data>>, evt_handle: Option<&LoopHandle<Data>>,
) { ) {
if let Some(drawer) = self.backends.borrow().get(&crtc) { if let Some(surface) = self.backends.borrow().get(&crtc) {
// get output coordinates let result = DrmRenderer::render_surface(
let (x, y) = self &mut *surface.borrow_mut(),
.output_map self.device_id,
.borrow() crtc,
.iter() &mut *self.window_map.borrow_mut(),
.take_while(|output| output.device_id != self.device_id || output.crtc != crtc) &mut *self.output_map.borrow_mut(),
.fold((0u32, 0u32), |pos, output| (pos.0 + output.size.0, pos.1)); &self.compositor_token,
let (width, height) = self &*self.pointer_location.borrow(),
.output_map &self.logger
.borrow()
.iter()
.find(|output| output.device_id == self.device_id && output.crtc == crtc)
.map(|output| output.size)
.unwrap_or((0, 0)); // in this case the output will be removed.
// and draw in sync with our monitor
let mut frame = drawer.draw();
frame.clear(None, Some((0.8, 0.8, 0.9, 1.0)), false, Some(1.0), None);
// draw the surfaces
drawer.draw_windows(
&mut frame,
&*self.window_map.borrow(),
Some(Rectangle {
x: x as i32,
y: y as i32,
width: width as i32,
height: height as i32,
}),
self.compositor_token,
); );
if let Err(err) = result {
// get pointer coordinates
let (ptr_x, ptr_y) = *self.pointer_location.borrow();
let ptr_x = ptr_x.trunc().abs() as i32 - x as i32;
let ptr_y = ptr_y.trunc().abs() as i32 - y as i32;
// set cursor
if ptr_x >= 0 && ptr_x < width as i32 && ptr_y >= 0 && ptr_y < height as i32 {
let _ = drawer.borrow().set_cursor_position(ptr_x as u32, ptr_y as u32);
// draw the dnd icon if applicable
{
let guard = self.dnd_icon.lock().unwrap();
if let Some(ref surface) = *guard {
if surface.as_ref().is_alive() {
drawer.draw_dnd_icon(&mut frame, surface, (ptr_x, ptr_y), self.compositor_token);
}
}
}
// draw the cursor as relevant
{
let mut guard = self.cursor_status.lock().unwrap();
// reset the cursor if the surface is no longer alive
let mut reset = false;
if let CursorImageStatus::Image(ref surface) = *guard {
reset = !surface.as_ref().is_alive();
}
if reset {
*guard = CursorImageStatus::Default;
}
if let CursorImageStatus::Image(ref surface) = *guard {
drawer.draw_software_cursor(
&mut frame,
surface,
(ptr_x, ptr_y),
self.compositor_token,
);
} else {
drawer.draw_hardware_cursor(&self.pointer_image, (2, 2), (ptr_x, ptr_y));
}
}
} else {
drawer.clear_cursor();
}
if let Err(err) = frame.finish() {
warn!(self.logger, "Error during rendering: {:?}", err); warn!(self.logger, "Error during rendering: {:?}", err);
let reschedule = let reschedule =
match err { match err {
SwapBuffersError::AlreadySwapped => false, SwapBuffersError::AlreadySwapped => false,
SwapBuffersError::TemporaryFailure(err) => { SwapBuffersError::TemporaryFailure(err) => {
match err.downcast_ref::<smithay::backend::drm_old::common::Error>() { match err.downcast_ref::<DrmError>() {
Some(&smithay::backend::drm_old::common::Error::DeviceInactive) => false, Some(&DrmError::DeviceInactive) => false,
Some(&smithay::backend::drm_old::common::Error::Access { Some(&DrmError::Access {
ref source, .. source: drm::SystemError::PermissionDenied,
}) if matches!(source.get_ref(), drm::SystemError::PermissionDenied) => false, ..
}) => false,
_ => true, _ => true,
} }
} }
@ -730,4 +733,92 @@ impl DrmRenderer {
} }
} }
} }
fn render_surface(
surface: &mut RenderSurface,
device_id: dev_t,
crtc: crtc::Handle,
window_map: &mut MyWindowMap,
output_map: &mut Vec<MyOutput>,
compositor_token: &CompositorToken<Roles>,
pointer_location: &(f64, f64),
logger: &slog::Logger,
) -> Result<(), SwapBuffersError> {
surface.frame_submitted()?;
// get output coordinates
let (x, y) = output_map
.iter()
.take_while(|output| output.device_id != device_id || output.crtc != crtc)
.fold((0u32, 0u32), |pos, output| (pos.0 + output.size.0, pos.1));
let (width, height) = output_map
.iter()
.find(|output| output.device_id == device_id && output.crtc == crtc)
.map(|output| output.size)
.unwrap_or((0, 0)); // in this case the output will be removed.
// and draw in sync with our monitor
surface.queue_frame().unwrap();
surface.clear([0.8, 0.8, 0.9, 1.0]).unwrap();
// draw the surfaces
draw_windows(
surface,
window_map,
Some(Rectangle {
x: x as i32,
y: y as i32,
width: width as i32,
height: height as i32,
}),
compositor_token.clone(),
logger,
);
// get pointer coordinates
let (ptr_x, ptr_y) = *pointer_location;
let ptr_x = ptr_x.trunc().abs() as i32 - x as i32;
let ptr_y = ptr_y.trunc().abs() as i32 - y as i32;
// set cursor
/*
if ptr_x >= 0 && ptr_x < width as i32 && ptr_y >= 0 && ptr_y < height as i32 {
let _ = drawer.borrow().set_cursor_position(ptr_x as u32, ptr_y as u32);
// draw the dnd icon if applicable
{
let guard = self.dnd_icon.lock().unwrap();
if let Some(ref surface) = *guard {
if surface.as_ref().is_alive() {
drawer.draw_dnd_icon(&mut frame, surface, (ptr_x, ptr_y), self.compositor_token);
}
}
}
// draw the cursor as relevant
{
let mut guard = self.cursor_status.lock().unwrap();
// reset the cursor if the surface is no longer alive
let mut reset = false;
if let CursorImageStatus::Image(ref surface) = *guard {
reset = !surface.as_ref().is_alive();
}
if reset {
*guard = CursorImageStatus::Default;
}
if let CursorImageStatus::Image(ref surface) = *guard {
drawer.draw_software_cursor(
&mut frame,
surface,
(ptr_x, ptr_y),
self.compositor_token,
);
} else {
drawer.draw_hardware_cursor(&self.pointer_image, (2, 2), (ptr_x, ptr_y));
}
}
} else {
drawer.clear_cursor();
}
*/
surface.finish()
}
} }