anvil: Fixup udev/tty backend, so that it runs at least
This commit is contained in:
parent
243afb1030
commit
43d3e9cd14
|
@ -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" ]
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue