anvil: allow for non-egl builds

This commit is contained in:
Victor Brekenfeld 2018-11-28 09:29:13 +01:00
parent f2466c5c50
commit f8a5e8bfde
8 changed files with 182 additions and 35 deletions

View File

@ -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 = []

View File

@ -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" ]

View File

@ -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<F: GLGraphicsBackend + 'static> {
vertex_buffer: glium::VertexBuffer<Vertex>,
index_buffer: glium::IndexBuffer<u16>,
programs: [glium::Program; shaders::FRAGMENT_COUNT],
#[cfg(feature = "egl")]
egl_display: Rc<RefCell<Option<EGLDisplay>>>,
log: Logger,
}
@ -50,6 +53,7 @@ impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
}
impl<T: Into<GliumGraphicsBackend<T>> + GLGraphicsBackend + 'static> GliumDrawer<T> {
#[cfg(feature = "egl")]
pub fn init(backend: T, egl_display: Rc<RefCell<Option<EGLDisplay>>>, log: Logger) -> GliumDrawer<T> {
let display = backend.into();
@ -91,9 +95,52 @@ impl<T: Into<GliumGraphicsBackend<T>> + GLGraphicsBackend + 'static> GliumDrawer
log,
}
}
#[cfg(not(feature = "egl"))]
pub fn init(backend: T, log: Logger) -> GliumDrawer<T> {
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<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
#[cfg(feature = "egl")]
pub fn texture_from_buffer(&self, buffer: Resource<wl_buffer::WlBuffer>) -> Result<TextureMetadata, ()> {
// 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<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
}
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<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
}
}
#[cfg(not(feature = "egl"))]
pub fn texture_from_buffer(&self, buffer: Resource<wl_buffer::WlBuffer>) -> Result<TextureMetadata, ()> {
self.texture_from_shm_buffer(buffer)
}
fn texture_from_shm_buffer(&self, buffer: Resource<wl_buffer::WlBuffer>) -> Result<TextureMetadata, ()> {
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<EGLImages>,
}

View File

@ -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,

View File

@ -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<S: SessionNotifier, Data: 'static> {
compositor_token: CompositorToken<SurfaceData, Roles>,
#[cfg(feature = "egl")]
active_egl_context: Rc<RefCell<Option<EGLDisplay>>>,
session: AutoSession,
backends: HashMap<
@ -247,6 +251,7 @@ struct UdevHandlerImpl<S: SessionNotifier, Data: 'static> {
}
impl<S: SessionNotifier, Data: 'static> UdevHandlerImpl<S, Data> {
#[cfg(feature = "egl")]
pub fn scan_connectors(
device: &mut RenderDevice,
egl_display: Rc<RefCell<Option<EGLDisplay>>>,
@ -295,6 +300,54 @@ impl<S: SessionNotifier, Data: 'static> UdevHandlerImpl<S, Data> {
backends
}
#[cfg(not(feature = "egl"))]
pub fn scan_connectors(
device: &mut RenderDevice,
logger: &::slog::Logger,
) -> HashMap<crtc::Handle, GliumDrawer<RenderSurface>> {
// 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<ConnectorInfo> = res_handles
.connectors()
.iter()
.map(|conn| device.resource_info::<ConnectorInfo>(*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::<EncoderInfo>(*encoder_handle))
.collect::<Vec<EncoderInfo>>();
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<S: SessionNotifier, Data: 'static> UdevHandler for UdevHandlerImpl<S, Data> {
@ -310,16 +363,27 @@ impl<S: SessionNotifier, Data: 'static> UdevHandler for UdevHandlerImpl<S, Data>
.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::<S, Data>::scan_connectors(
&mut device,
self.active_egl_context.clone(),
&self.logger,
)));
#[cfg(not(feature = "egl"))]
let backends = Rc::new(RefCell::new(UdevHandlerImpl::<S, Data>::scan_connectors(
&mut device,
&self.logger,
)));
device.set_handler(DrmHandlerImpl {
compositor_token: self.compositor_token,
backends: backends.clone(),
@ -360,11 +424,15 @@ impl<S: SessionNotifier, Data: 'static> UdevHandler for UdevHandlerImpl<S, Data>
let source = evt_source.clone_inner();
let mut evented = source.borrow_mut();
let mut backends = backends.borrow_mut();
*backends = UdevHandlerImpl::<S, Data>::scan_connectors(
#[cfg(feature = "egl")]
let new_backends = UdevHandlerImpl::<S, Data>::scan_connectors(
&mut (*evented).0,
self.active_egl_context.clone(),
&self.logger,
);
#[cfg(not(feature = "egl"))]
let new_backends = UdevHandlerImpl::<S, Data>::scan_connectors(&mut (*evented).0, &self.logger);
*backends = new_backends;
for renderer in backends.values() {
// create cursor
@ -391,9 +459,17 @@ impl<S: SessionNotifier, Data: 'static> UdevHandler for UdevHandlerImpl<S, Data>
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);

View File

@ -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<B: Backend<Surface = <D as Device>::Surface> + 'static, D: Device + NativeDisplay<B> + 'static>
EGLGraphicsBackend for EglDevice<B, D>
where

View File

@ -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<ffi::egl::types::EGLDisplay>,
wayland: *mut wl_display,
@ -332,6 +335,7 @@ pub struct EGLDisplay {
egl_to_texture_support: bool,
}
#[cfg(feature = "native_lib")]
impl EGLDisplay {
fn new<B: native::Backend, N: native::NativeDisplay<B>>(
context: &EGLContext<B, N>,
@ -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<E: EGLGraphicsBackend> EGLGraphicsBackend for Rc<E> {
fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay> {
(**self).bind_wl_display(display)
}
}
#[cfg(feature = "native_lib")]
impl<B: native::Backend, N: native::NativeDisplay<B>> EGLGraphicsBackend for EGLContext<B, N> {
fn bind_wl_display(&self, display: &Display) -> Result<EGLDisplay> {
if !self.wl_drm_support {

View File

@ -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;