From f8a5e8bfde2635b53f713fbaee115887cb66acad Mon Sep 17 00:00:00 2001 From: Victor Brekenfeld Date: Wed, 28 Nov 2018 09:29:13 +0100 Subject: [PATCH] anvil: allow for non-egl builds --- Cargo.toml | 7 +-- anvil/Cargo.toml | 5 +- anvil/src/glium_drawer.rs | 100 +++++++++++++++++++++++++++++-------- anvil/src/input_handler.rs | 2 +- anvil/src/udev.rs | 90 ++++++++++++++++++++++++++++++--- src/backend/drm/egl/mod.rs | 5 +- src/backend/egl/mod.rs | 7 +++ src/lib.rs | 1 + 8 files changed, 182 insertions(+), 35 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1cf6d0d..153f4e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,8 @@ members = [ "anvil" ] [dependencies] wayland-server = "0.21.6" -wayland-sys = "0.21.3" wayland-commons = "0.21.1" +wayland-sys = { version = "0.21.6", optional = true } nix = "0.11" xkbcommon = "0.2.1" tempfile = "2.1.5" @@ -28,7 +28,7 @@ input = { version = "0.4.0", optional = true } udev = { version = "0.2.0", optional = true } dbus = { version = "0.6.1", optional = true } systemd = { version = "^0.2.0", optional = true } -wayland-protocols = { version = "0.21.3", features = ["unstable_protocols", "native_server"] } +wayland-protocols = { version = "0.21.3", features = ["unstable_protocols", "server"] } image = "0.17.0" error-chain = "0.11.0" lazy_static = "1.0.0" @@ -38,7 +38,7 @@ gl_generator = { version = "0.9", optional = true } [features] default = ["backend_winit", "backend_drm_legacy", "backend_drm_gbm", "backend_drm_egl", "backend_libinput", "backend_udev", "backend_session", "renderer_glium", "xwayland"] -backend_winit = ["winit", "wayland-server/dlopen", "wayland-client/dlopen", "backend_egl", "renderer_gl"] +backend_winit = ["winit", "wayland-server/dlopen", "wayland-client/dlopen", "backend_egl", "renderer_gl", "native_lib"] backend_drm = ["drm"] backend_drm_legacy = ["backend_drm"] backend_drm_gbm = ["backend_drm", "gbm"] @@ -50,4 +50,5 @@ backend_udev = ["udev"] backend_session_logind = ["dbus", "systemd", "backend_session"] renderer_gl = ["gl_generator"] renderer_glium = ["renderer_gl", "glium"] +native_lib = ["wayland-sys", "wayland-server/native_lib", "wayland-protocols/native_server"] xwayland = [] \ No newline at end of file diff --git a/anvil/Cargo.toml b/anvil/Cargo.toml index d7deafe..536a207 100644 --- a/anvil/Cargo.toml +++ b/anvil/Cargo.toml @@ -23,7 +23,8 @@ features = [ "renderer_glium" ] gl_generator = "0.9" [features] -default = [ "winit", "udev" ] +default = [ "winit", "egl", "udev" ] +egl = [ "smithay/native_lib" ] winit = [ "smithay/backend_winit" ] -udev = [ "smithay/backend_libinput", "smithay/backend_drm", "smithay/backend_udev", "smithay/backend_session" ] +udev = [ "smithay/backend_libinput", "smithay/backend_drm_legacy", "smithay/backend_drm_gbm", "smithay/backend_drm_egl", "smithay/backend_udev", "smithay/backend_session" ] logind = [ "smithay/backend_session_logind" ] diff --git a/anvil/src/glium_drawer.rs b/anvil/src/glium_drawer.rs index d384ac0..b10e7e1 100644 --- a/anvil/src/glium_drawer.rs +++ b/anvil/src/glium_drawer.rs @@ -11,9 +11,11 @@ use glium::{ }; use slog::Logger; +#[cfg(feature = "egl")] +use smithay::backend::egl::EGLDisplay; use smithay::{ backend::{ - egl::{BufferAccessError, EGLDisplay, EGLImages, Format}, + egl::{BufferAccessError, EGLImages, Format}, graphics::{gl::GLGraphicsBackend, glium::GliumGraphicsBackend}, }, wayland::{ @@ -39,6 +41,7 @@ pub struct GliumDrawer { vertex_buffer: glium::VertexBuffer, index_buffer: glium::IndexBuffer, programs: [glium::Program; shaders::FRAGMENT_COUNT], + #[cfg(feature = "egl")] egl_display: Rc>>, log: Logger, } @@ -50,6 +53,7 @@ impl GliumDrawer { } impl> + GLGraphicsBackend + 'static> GliumDrawer { + #[cfg(feature = "egl")] pub fn init(backend: T, egl_display: Rc>>, log: Logger) -> GliumDrawer { let display = backend.into(); @@ -91,9 +95,52 @@ impl> + GLGraphicsBackend + 'static> GliumDrawer log, } } + + #[cfg(not(feature = "egl"))] + pub fn init(backend: T, log: Logger) -> GliumDrawer { + let display = backend.into(); + + // building the vertex buffer, which contains all the vertices that we will draw + let vertex_buffer = glium::VertexBuffer::new( + &display, + &[ + Vertex { + position: [0.0, 0.0], + tex_coords: [0.0, 0.0], + }, + Vertex { + position: [0.0, 1.0], + tex_coords: [0.0, 1.0], + }, + Vertex { + position: [1.0, 1.0], + tex_coords: [1.0, 1.0], + }, + Vertex { + position: [1.0, 0.0], + tex_coords: [1.0, 0.0], + }, + ], + ).unwrap(); + + // building the index buffer + let index_buffer = + glium::IndexBuffer::new(&display, PrimitiveType::TriangleStrip, &[1 as u16, 2, 0, 3]).unwrap(); + + let programs = opengl_programs!(&display); + + GliumDrawer { + display, + vertex_buffer, + index_buffer, + programs, + log, + } + } } impl GliumDrawer { + #[cfg(feature = "egl")] pub fn texture_from_buffer(&self, buffer: Resource) -> Result { // try to retrieve the egl contents of this buffer let images = if let Some(display) = &self.egl_display.borrow().as_ref() { @@ -134,26 +181,7 @@ impl GliumDrawer { } Err(BufferAccessError::NotManaged(buffer)) => { // this is not an EGL buffer, try SHM - match shm_buffer_contents(&buffer, |slice, data| { - ::shm_load::load_shm_buffer(data, slice) - .map(|(image, kind)| (Texture2d::new(&self.display, image).unwrap(), kind, data)) - }) { - Ok(Ok((texture, kind, data))) => Ok(TextureMetadata { - texture, - fragment: kind, - y_inverted: false, - dimensions: (data.width as u32, data.height as u32), - images: None, - }), - Ok(Err(format)) => { - warn!(self.log, "Unsupported SHM buffer format"; "format" => format!("{:?}", format)); - Err(()) - } - Err(err) => { - warn!(self.log, "Unable to load buffer contents"; "err" => format!("{:?}", err)); - Err(()) - } - } + self.texture_from_shm_buffer(buffer) } Err(err) => { error!(self.log, "EGL error"; "err" => format!("{:?}", err)); @@ -162,6 +190,35 @@ impl GliumDrawer { } } + #[cfg(not(feature = "egl"))] + pub fn texture_from_buffer(&self, buffer: Resource) -> Result { + self.texture_from_shm_buffer(buffer) + } + + fn texture_from_shm_buffer(&self, buffer: Resource) -> Result { + match shm_buffer_contents(&buffer, |slice, data| { + ::shm_load::load_shm_buffer(data, slice) + .map(|(image, kind)| (Texture2d::new(&self.display, image).unwrap(), kind, data)) + }) { + Ok(Ok((texture, kind, data))) => Ok(TextureMetadata { + texture, + fragment: kind, + y_inverted: false, + dimensions: (data.width as u32, data.height as u32), + #[cfg(feature = "egl")] + images: None, + }), + Ok(Err(format)) => { + warn!(self.log, "Unsupported SHM buffer format"; "format" => format!("{:?}", format)); + Err(()) + } + Err(err) => { + warn!(self.log, "Unable to load buffer contents"; "err" => format!("{:?}", err)); + Err(()) + } + } + } + pub fn render_texture( &self, target: &mut glium::Frame, @@ -218,6 +275,7 @@ pub struct TextureMetadata { pub fragment: usize, pub y_inverted: bool, pub dimensions: (u32, u32), + #[cfg(feature = "egl")] images: Option, } diff --git a/anvil/src/input_handler.rs b/anvil/src/input_handler.rs index f417235..689f707 100644 --- a/anvil/src/input_handler.rs +++ b/anvil/src/input_handler.rs @@ -11,7 +11,7 @@ use std::{ use slog::Logger; #[cfg(feature = "udev")] -use smithay::backend::session::{Session, auto::AutoSession}; +use smithay::backend::session::{auto::AutoSession, Session}; use smithay::{ backend::input::{ self, Event, InputBackend, InputHandler, KeyState, KeyboardKeyEvent, PointerAxisEvent, diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index a7f2f7a..3c995e1 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -14,6 +14,8 @@ use std::{ use glium::Surface as GliumSurface; use slog::Logger; +#[cfg(feature = "egl")] +use smithay::backend::egl::{EGLDisplay, EGLGraphicsBackend}; use smithay::{ backend::{ drm::{ @@ -23,7 +25,6 @@ use smithay::{ legacy::LegacyDrmDevice, DevPath, Device, DeviceHandler, Surface, }, - egl::{EGLDisplay, EGLGraphicsBackend}, graphics::CursorBackend, input::InputBackend, libinput::{libinput_bind, LibinputInputBackend, LibinputSessionInterface}, @@ -79,6 +80,7 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger info!(log, "Listening on wayland socket"; "name" => name.clone()); ::std::env::set_var("WAYLAND_DISPLAY", name); + #[cfg(feature = "egl")] let active_egl_context = Rc::new(RefCell::new(None)); let display = Rc::new(RefCell::new(display)); @@ -114,6 +116,7 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger &context, UdevHandlerImpl { compositor_token, + #[cfg(feature = "egl")] active_egl_context, session: session.clone(), backends: HashMap::new(), @@ -226,6 +229,7 @@ pub fn run_udev(mut display: Display, mut event_loop: EventLoop<()>, log: Logger struct UdevHandlerImpl { compositor_token: CompositorToken, + #[cfg(feature = "egl")] active_egl_context: Rc>>, session: AutoSession, backends: HashMap< @@ -247,6 +251,7 @@ struct UdevHandlerImpl { } impl UdevHandlerImpl { + #[cfg(feature = "egl")] pub fn scan_connectors( device: &mut RenderDevice, egl_display: Rc>>, @@ -295,6 +300,54 @@ impl UdevHandlerImpl { backends } + + #[cfg(not(feature = "egl"))] + pub fn scan_connectors( + device: &mut RenderDevice, + logger: &::slog::Logger, + ) -> HashMap> { + // Get a set of all modesetting resource handles (excluding planes): + let res_handles = device.resource_handles().unwrap(); + + // Use first connected connector + let connector_infos: Vec = res_handles + .connectors() + .iter() + .map(|conn| device.resource_info::(*conn).unwrap()) + .filter(|conn| conn.connection_state() == ConnectorState::Connected) + .inspect(|conn| info!(logger, "Connected: {:?}", conn.connector_type())) + .collect(); + + let mut backends = HashMap::new(); + + // very naive way of finding good crtc/encoder/connector combinations. This problem is np-complete + for connector_info in connector_infos { + let encoder_infos = connector_info + .encoders() + .iter() + .flat_map(|encoder_handle| device.resource_info::(*encoder_handle)) + .collect::>(); + for encoder_info in encoder_infos { + for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) { + if !backends.contains_key(&crtc) { + let mode = connector_info.modes()[0]; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.) + // create a backend + let renderer = GliumDrawer::init( + device + .create_surface(crtc, mode, vec![connector_info.handle()].into_iter()) + .unwrap(), + logger.clone(), + ); + + backends.insert(crtc, renderer); + break; + } + } + } + } + + backends + } } impl UdevHandler for UdevHandlerImpl { @@ -310,16 +363,27 @@ impl UdevHandler for UdevHandlerImpl .and_then(|gbm| EglDevice::new(gbm, self.logger.clone()).ok()) { // init hardware acceleration on the primary gpu. - if path.canonicalize().ok() == self.primary_gpu { - *self.active_egl_context.borrow_mut() = device.bind_wl_display(&*self.display.borrow()).ok(); + #[cfg(feature = "egl")] + { + if path.canonicalize().ok() == self.primary_gpu { + *self.active_egl_context.borrow_mut() = + device.bind_wl_display(&*self.display.borrow()).ok(); + } } + #[cfg(feature = "egl")] let backends = Rc::new(RefCell::new(UdevHandlerImpl::::scan_connectors( &mut device, self.active_egl_context.clone(), &self.logger, ))); + #[cfg(not(feature = "egl"))] + let backends = Rc::new(RefCell::new(UdevHandlerImpl::::scan_connectors( + &mut device, + &self.logger, + ))); + device.set_handler(DrmHandlerImpl { compositor_token: self.compositor_token, backends: backends.clone(), @@ -360,11 +424,15 @@ impl UdevHandler for UdevHandlerImpl let source = evt_source.clone_inner(); let mut evented = source.borrow_mut(); let mut backends = backends.borrow_mut(); - *backends = UdevHandlerImpl::::scan_connectors( + #[cfg(feature = "egl")] + let new_backends = UdevHandlerImpl::::scan_connectors( &mut (*evented).0, self.active_egl_context.clone(), &self.logger, ); + #[cfg(not(feature = "egl"))] + let new_backends = UdevHandlerImpl::::scan_connectors(&mut (*evented).0, &self.logger); + *backends = new_backends; for renderer in backends.values() { // create cursor @@ -391,9 +459,17 @@ impl UdevHandler for UdevHandlerImpl debug!(self.logger, "Surfaces dropped"); // don't use hardware acceleration anymore, if this was the primary gpu - let device = Rc::try_unwrap(evt_source.remove().unwrap()).map_err(|_| "This should not happend").unwrap().into_inner().0; - if device.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu { - *self.active_egl_context.borrow_mut() = None; + let device = Rc::try_unwrap(evt_source.remove().unwrap()) + .map_err(|_| "This should not happend") + .unwrap() + .into_inner() + .0; + + #[cfg(feature = "egl")] + { + if device.dev_path().and_then(|path| path.canonicalize().ok()) == self.primary_gpu { + *self.active_egl_context.borrow_mut() = None; + } } self.notifier.unregister(id); diff --git a/src/backend/drm/egl/mod.rs b/src/backend/drm/egl/mod.rs index 7cd7803..b97cfac 100644 --- a/src/backend/drm/egl/mod.rs +++ b/src/backend/drm/egl/mod.rs @@ -9,7 +9,9 @@ use super::{Device, DeviceHandler, Surface}; use backend::egl::context::GlAttributes; use backend::egl::error::Result as EGLResult; use backend::egl::native::{Backend, NativeDisplay, NativeSurface}; -use backend::egl::{EGLContext, EGLDisplay, EGLGraphicsBackend}; +use backend::egl::EGLContext; +#[cfg(feature = "native_lib")] +use backend::egl::{EGLDisplay, EGLGraphicsBackend}; pub mod error; use self::error::*; @@ -178,6 +180,7 @@ where } } +#[cfg(feature = "native_lib")] impl::Surface> + 'static, D: Device + NativeDisplay + 'static> EGLGraphicsBackend for EglDevice where diff --git a/src/backend/egl/mod.rs b/src/backend/egl/mod.rs index dfafee9..57d4f6d 100644 --- a/src/backend/egl/mod.rs +++ b/src/backend/egl/mod.rs @@ -29,6 +29,7 @@ use wayland_server::{ protocol::wl_buffer::{self, WlBuffer}, Display, Resource, }; +#[cfg(feature = "native_lib")] use wayland_sys::server::wl_display; pub mod context; @@ -303,6 +304,7 @@ impl Drop for EGLImages { /// Trait any backend type may implement that allows binding a `wayland_server::Display` /// to create an `EGLDisplay` for EGL-based `WlBuffer`s. +#[cfg(feature = "native_lib")] pub trait EGLGraphicsBackend { /// Binds this EGL context to the given Wayland display. /// @@ -323,6 +325,7 @@ pub trait EGLGraphicsBackend { /// Type to receive `EGLImages` for EGL-based `WlBuffer`s. /// /// Can be created by using `EGLGraphicsBackend::bind_wl_display`. +#[cfg(feature = "native_lib")] pub struct EGLDisplay { egl: Weak, wayland: *mut wl_display, @@ -332,6 +335,7 @@ pub struct EGLDisplay { egl_to_texture_support: bool, } +#[cfg(feature = "native_lib")] impl EGLDisplay { fn new>( context: &EGLContext, @@ -469,6 +473,7 @@ impl EGLDisplay { } } +#[cfg(feature = "native_lib")] impl Drop for EGLDisplay { fn drop(&mut self) { if let Some(display) = self.egl.upgrade() { @@ -481,12 +486,14 @@ impl Drop for EGLDisplay { } } +#[cfg(feature = "native_lib")] impl EGLGraphicsBackend for Rc { fn bind_wl_display(&self, display: &Display) -> Result { (**self).bind_wl_display(display) } } +#[cfg(feature = "native_lib")] impl> EGLGraphicsBackend for EGLContext { fn bind_wl_display(&self, display: &Display) -> Result { if !self.wl_drm_support { diff --git a/src/lib.rs b/src/lib.rs index 422b947..9e11b51 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,7 @@ extern crate tempfile; pub extern crate wayland_commons; pub extern crate wayland_protocols; pub extern crate wayland_server; +#[cfg(feature = "native_lib")] extern crate wayland_sys; extern crate xkbcommon;