anvil: Introduce BufferTextures

This commit is contained in:
Victor Brekenfeld 2020-06-27 18:27:47 +02:00
parent d603a9ccfb
commit bf011e8071
8 changed files with 262 additions and 302 deletions

View File

@ -1,14 +1,27 @@
use std::{cell::RefCell, rc::Rc}; use std::collections::HashMap;
#[cfg(feature = "egl")]
use std::{
cell::RefCell,
rc::Rc,
};
use glium::texture::Texture2d;
#[cfg(feature = "egl")]
use glium::{
texture::{MipmapsOption, UncompressedFloatFormat},
GlObject,
};
use slog::Logger; use slog::Logger;
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
use smithay::backend::egl::display::EGLBufferReader; use smithay::backend::egl::{display::EGLBufferReader, EGLImages, BufferAccessError as EGLBufferAccessError, Format};
use smithay::{ use smithay::{
backend::graphics::gl::GLGraphicsBackend,
reexports::wayland_server::protocol::wl_buffer::WlBuffer, reexports::wayland_server::protocol::wl_buffer::WlBuffer,
wayland::shm::with_buffer_contents as shm_buffer_contents, wayland::shm::{with_buffer_contents as shm_buffer_contents, BufferAccessError},
}; };
use crate::glium_drawer::GliumDrawer;
/// Utilities for working with `WlBuffer`s. /// Utilities for working with `WlBuffer`s.
#[derive(Clone)] #[derive(Clone)]
pub struct BufferUtils { pub struct BufferUtils {
@ -41,22 +54,172 @@ impl BufferUtils {
.borrow() .borrow()
.as_ref() .as_ref()
.and_then(|display| display.egl_buffer_dimensions(buffer)) .and_then(|display| display.egl_buffer_dimensions(buffer))
.or_else(|| self.shm_buffer_dimensions(buffer)) .or_else(|| self.shm_buffer_dimensions(buffer).ok())
} }
/// Returns the dimensions of an image stored in the buffer. /// Returns the dimensions of an image stored in the buffer.
#[cfg(not(feature = "egl"))] #[cfg(not(feature = "egl"))]
pub fn dimensions(&self, buffer: &WlBuffer) -> Option<(i32, i32)> { pub fn dimensions(&self, buffer: &WlBuffer) -> Option<(i32, i32)> {
self.shm_buffer_dimensions(buffer) self.shm_buffer_dimensions(buffer).ok()
} }
/// Returns the dimensions of an image stored in the shm buffer. /// Returns the dimensions of an image stored in the shm buffer.
fn shm_buffer_dimensions(&self, buffer: &WlBuffer) -> Option<(i32, i32)> { fn shm_buffer_dimensions(&self, buffer: &WlBuffer) -> Result<(i32, i32), BufferAccessError> {
shm_buffer_contents(buffer, |_, data| (data.width, data.height)) shm_buffer_contents(buffer, |_, data| (data.width, data.height))
.map_err(|err| { .map_err(|err| {
warn!(self.log, "Unable to load buffer contents"; "err" => format!("{:?}", err)); warn!(self.log, "Unable to load buffer contents"; "err" => format!("{:?}", err));
err err
}) })
.ok() }
#[cfg(feature = "egl")]
pub fn load_buffer(&self, buffer: WlBuffer) -> Result<BufferTextures, WlBuffer> {
// try to retrieve the egl contents of this buffer
let images = if let Some(display) = &self.egl_buffer_reader.borrow().as_ref() {
display.egl_buffer_contents(&buffer)
} else {
return Err(buffer);
};
match images {
Ok(images) => {
// we have an EGL buffer
Ok(BufferTextures {
buffer,
textures: HashMap::new(),
fragment: crate::shaders::BUFFER_RGBA,
y_inverted: images.y_inverted,
dimensions: (images.width, images.height),
images: Some(images), // I guess we need to keep this alive ?
logger: self.log.clone(),
})
}
Err(EGLBufferAccessError::NotManaged(_)) => {
// this is not an EGL buffer, try SHM
self.load_shm_buffer(buffer)
}
Err(err) => {
error!(self.log, "EGL error"; "err" => format!("{:?}", err));
Err(buffer)
}
}
}
#[cfg(not(feature = "egl"))]
pub fn load_buffer(&self, buffer: WlBuffer) -> Result<BufferTextures, WlBuffer> {
self.load_shm_buffer(buffer)
}
fn load_shm_buffer(&self, buffer: WlBuffer) -> Result<BufferTextures, WlBuffer> {
let (width, height, format) = match shm_buffer_contents(&buffer, |_, data| (data.width, data.height, data.format)) {
Ok(x) => x,
Err(err) => {
warn!(self.log, "Unable to load buffer contents"; "err" => format!("{:?}", err));
return Err(buffer);
}
};
let shader = match crate::shm_load::load_format(format) {
Ok(x) => x.1,
Err(format) => {
warn!(self.log, "Unable to load buffer format: {:?}", format);
return Err(buffer);
}
};
Ok(BufferTextures {
buffer,
textures: HashMap::new(),
fragment: shader,
y_inverted: false,
dimensions: (width as u32, height as u32),
#[cfg(feature = "egl")]
images: None,
logger: self.log.clone(),
})
}
}
pub struct BufferTextures {
buffer: WlBuffer,
pub textures: HashMap<usize, Texture2d>,
pub fragment: usize,
pub y_inverted: bool,
pub dimensions: (u32, u32),
#[cfg(feature = "egl")]
images: Option<EGLImages>,
logger: slog::Logger,
}
impl BufferTextures {
#[cfg(feature = "egl")]
pub fn load_texture<'a, F: GLGraphicsBackend + 'static>(&'a mut self, drawer: &GliumDrawer<F>) -> Result<&'a Texture2d, ()> {
if self.textures.contains_key(&drawer.id) {
return Ok(&self.textures[&drawer.id]);
}
if let Some(images) = self.images.as_ref() { //EGL buffer
let format = match images.format {
Format::RGB => UncompressedFloatFormat::U8U8U8,
Format::RGBA => UncompressedFloatFormat::U8U8U8U8,
_ => {
warn!(self.logger, "Unsupported EGL buffer format"; "format" => format!("{:?}", images.format));
return Err(());
}
};
let opengl_texture = Texture2d::empty_with_format(
&drawer.display,
format,
MipmapsOption::NoMipmap,
images.width,
images.height,
)
.unwrap();
unsafe {
images
.bind_to_texture(0, opengl_texture.get_id(), &*drawer.display.borrow())
.expect("Failed to bind to texture");
}
self.textures.insert(drawer.id, opengl_texture);
Ok(&self.textures[&drawer.id])
} else {
self.load_shm_texture(drawer)
}
}
#[cfg(not(feature = "egl"))]
pub fn load_texture<'a, F: GLGraphicsBackend + 'static>(&'a mut self, drawer: &GliumDrawer<F>) -> Result<&'a Texture2d, ()> {
if self.textures.contains_key(&drawer.id) {
return Ok(&self.textures[&drawer.id]);
}
self.load_shm_texture(drawer)
}
fn load_shm_texture<'a, F: GLGraphicsBackend + 'static>(&'a mut self, drawer: &GliumDrawer<F>) -> Result<&'a Texture2d, ()> {
match shm_buffer_contents(&self.buffer, |slice, data| {
crate::shm_load::load_shm_buffer(data, slice)
.map(|(image, _kind)| Texture2d::new(&drawer.display, image).unwrap())
}) {
Ok(Ok(texture)) => {
self.textures.insert(drawer.id, texture);
Ok(&self.textures[&drawer.id])
},
Ok(Err(format)) => {
warn!(self.logger, "Unsupported SHM buffer format"; "format" => format!("{:?}", format));
Err(())
}
Err(err) => {
warn!(self.logger, "Unable to load buffer contents"; "err" => format!("{:?}", err));
Err(())
}
}
}
}
impl Drop for BufferTextures {
fn drop(&mut self) {
self.buffer.release()
} }
} }

View File

@ -7,35 +7,30 @@ use std::{
use glium::{ use glium::{
self, self,
index::PrimitiveType, index::PrimitiveType,
texture::{MipmapsOption, Texture2d, UncompressedFloatFormat}, texture::Texture2d,
GlObject, Surface, Surface,
}; };
use slog::Logger; use slog::Logger;
#[cfg(feature = "egl")]
use smithay::backend::egl::display::EGLBufferReader;
use smithay::{ use smithay::{
backend::{ backend::graphics::{
egl::{BufferAccessError, EGLImages, Format}, gl::GLGraphicsBackend,
graphics::{ glium::{Frame, GliumGraphicsBackend},
gl::GLGraphicsBackend, SwapBuffersError,
glium::{Frame, GliumGraphicsBackend},
SwapBuffersError,
},
}, },
reexports::{ reexports::{
calloop::LoopHandle, calloop::LoopHandle,
wayland_server::protocol::{wl_buffer, wl_surface}, wayland_server::protocol::wl_surface,
}, },
utils::Rectangle, utils::Rectangle,
wayland::{ wayland::{
compositor::{roles::Role, SubsurfaceRole, TraversalAction}, compositor::{roles::Role, SubsurfaceRole, TraversalAction},
data_device::DnDIconRole, data_device::DnDIconRole,
seat::CursorImageRole, seat::CursorImageRole,
shm::with_buffer_contents as shm_buffer_contents,
}, },
}; };
use crate::buffer_utils::BufferUtils;
use crate::shaders; use crate::shaders;
use crate::shell::{MyCompositorToken, MyWindowMap, SurfaceData}; use crate::shell::{MyCompositorToken, MyWindowMap, SurfaceData};
@ -55,13 +50,12 @@ mod implement_vertex {
} }
pub struct GliumDrawer<F: GLGraphicsBackend + 'static> { pub struct GliumDrawer<F: GLGraphicsBackend + 'static> {
id: usize, pub id: usize,
display: GliumGraphicsBackend<F>, pub display: GliumGraphicsBackend<F>,
vertex_buffer: glium::VertexBuffer<Vertex>, vertex_buffer: glium::VertexBuffer<Vertex>,
index_buffer: glium::IndexBuffer<u16>, index_buffer: glium::IndexBuffer<u16>,
programs: [glium::Program; shaders::FRAGMENT_COUNT], programs: [glium::Program; shaders::FRAGMENT_COUNT],
#[cfg(feature = "egl")] buffer_loader: BufferUtils,
egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>,
log: Logger, log: Logger,
} }
@ -72,10 +66,9 @@ impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
} }
impl<T: Into<GliumGraphicsBackend<T>> + GLGraphicsBackend + 'static> GliumDrawer<T> { impl<T: Into<GliumGraphicsBackend<T>> + GLGraphicsBackend + 'static> GliumDrawer<T> {
#[cfg(feature = "egl")]
pub fn init( pub fn init(
backend: T, backend: T,
egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>, buffer_loader: BufferUtils,
log: Logger, log: Logger,
) -> GliumDrawer<T> { ) -> GliumDrawer<T> {
let display = backend.into(); let display = backend.into();
@ -116,140 +109,13 @@ impl<T: Into<GliumGraphicsBackend<T>> + GLGraphicsBackend + 'static> GliumDrawer
vertex_buffer, vertex_buffer,
index_buffer, index_buffer,
programs, programs,
egl_buffer_reader, buffer_loader,
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 {
id: BACKEND_COUNTER.fetch_add(1, Ordering::AcqRel),
display,
vertex_buffer,
index_buffer,
programs,
log, log,
} }
} }
} }
impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> { impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
#[cfg(feature = "egl")]
pub fn texture_from_buffer(&self, buffer: wl_buffer::WlBuffer) -> Result<TextureMetadata, ()> {
// try to retrieve the egl contents of this buffer
let images = if let Some(display) = &self.egl_buffer_reader.borrow().as_ref() {
display.egl_buffer_contents(buffer)
} else {
Err(BufferAccessError::NotManaged(
buffer,
smithay::backend::egl::EGLError::BadDisplay,
))
};
match images {
Ok(images) => {
// we have an EGL buffer
let format = match images.format {
Format::RGB => UncompressedFloatFormat::U8U8U8,
Format::RGBA => UncompressedFloatFormat::U8U8U8U8,
_ => {
warn!(self.log, "Unsupported EGL buffer format"; "format" => format!("{:?}", images.format));
return Err(());
}
};
let opengl_texture = Texture2d::empty_with_format(
&self.display,
format,
MipmapsOption::NoMipmap,
images.width,
images.height,
)
.unwrap();
unsafe {
images
.bind_to_texture(0, opengl_texture.get_id(), &*self.display.borrow())
.expect("Failed to bind to texture");
}
Ok(TextureMetadata {
texture: opengl_texture,
fragment: crate::shaders::BUFFER_RGBA,
y_inverted: images.y_inverted,
dimensions: (images.width, images.height),
images: Some(images), // I guess we need to keep this alive ?
})
}
Err(BufferAccessError::NotManaged(buffer, _)) => {
// this is not an EGL buffer, try SHM
self.texture_from_shm_buffer(buffer)
}
Err(err) => {
error!(self.log, "EGL error"; "err" => format!("{:?}", err));
Err(())
}
}
}
#[cfg(not(feature = "egl"))]
pub fn texture_from_buffer(&self, buffer: wl_buffer::WlBuffer) -> Result<TextureMetadata, ()> {
self.texture_from_shm_buffer(buffer)
}
fn texture_from_shm_buffer(&self, buffer: wl_buffer::WlBuffer) -> Result<TextureMetadata, ()> {
match shm_buffer_contents(&buffer, |slice, data| {
crate::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 Frame, spec: RenderTextureSpec<'_>) { pub fn render_texture(&self, target: &mut Frame, spec: RenderTextureSpec<'_>) {
let xscale = 2.0 * (spec.surface_dimensions.0 as f32) / (spec.screen_size.0 as f32); let xscale = 2.0 * (spec.surface_dimensions.0 as f32) / (spec.screen_size.0 as f32);
let mut yscale = -2.0 * (spec.surface_dimensions.1 as f32) / (spec.screen_size.1 as f32); let mut yscale = -2.0 * (spec.surface_dimensions.1 as f32) / (spec.screen_size.1 as f32);
@ -302,15 +168,6 @@ pub struct RenderTextureSpec<'a> {
blending: glium::Blend, blending: glium::Blend,
} }
pub struct TextureMetadata {
pub texture: Texture2d,
pub fragment: usize,
pub y_inverted: bool,
pub dimensions: (u32, u32),
#[cfg(feature = "egl")]
images: Option<EGLImages>,
}
impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> { impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
fn draw_surface_tree( fn draw_surface_tree(
&self, &self,
@ -327,30 +184,18 @@ impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
// Pull a new buffer if available // Pull a new buffer if available
if let Some(data) = attributes.user_data.get::<RefCell<SurfaceData>>() { if let Some(data) = attributes.user_data.get::<RefCell<SurfaceData>>() {
let mut data = data.borrow_mut(); let mut data = data.borrow_mut();
if !data.texture.contains_key(&self.id) { if data.texture.is_none() {
if let Some(buffer) = data.current_state.buffer.take() { if let Some(buffer) = data.current_state.buffer.take() {
if let Ok(m) = self.texture_from_buffer(buffer.clone()) { match self.buffer_loader.load_buffer(buffer) {
// release the buffer if it was an SHM buffer Ok(m) => data.texture = Some(m),
#[cfg(feature = "egl")]
{
if m.images.is_none() {
buffer.release();
}
}
#[cfg(not(feature = "egl"))]
{
buffer.release();
}
data.texture.insert(self.id, m);
} else {
// there was an error reading the buffer, release it, we // there was an error reading the buffer, release it, we
// already logged the error // already logged the error
buffer.release(); Err(buffer) => buffer.release(),
} };
} }
} }
// Now, should we be drawn ? // Now, should we be drawn ?
if data.texture.contains_key(&self.id) { if data.texture.is_some() {
// if yes, also process the children // if yes, also process the children
if Role::<SubsurfaceRole>::has(role) { if Role::<SubsurfaceRole>::has(role) {
x += data.current_state.sub_location.0; x += data.current_state.sub_location.0;
@ -368,36 +213,42 @@ impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
}, },
|_surface, attributes, role, &(mut x, mut y)| { |_surface, attributes, role, &(mut x, mut y)| {
if let Some(ref data) = attributes.user_data.get::<RefCell<SurfaceData>>() { if let Some(ref data) = attributes.user_data.get::<RefCell<SurfaceData>>() {
let data = data.borrow(); let mut data = data.borrow_mut();
if let Some(ref metadata) = data.texture.get(&self.id) { let (sub_x, sub_y) = data.current_state.sub_location;
// we need to re-extract the subsurface offset, as the previous closure if let Some(buffer_textures) = data.texture.as_mut() {
// only passes it to our children let texture_kind = buffer_textures.fragment;
if Role::<SubsurfaceRole>::has(role) { let y_inverted = buffer_textures.y_inverted;
x += data.current_state.sub_location.0; let surface_dimensions = buffer_textures.dimensions;
y += data.current_state.sub_location.1; if let Ok(ref texture) = buffer_textures.load_texture(&self) {
} // we need to re-extract the subsurface offset, as the previous closure
self.render_texture( // only passes it to our children
frame, if Role::<SubsurfaceRole>::has(role) {
RenderTextureSpec { x += sub_x;
texture: &metadata.texture, y += sub_y;
texture_kind: metadata.fragment, }
y_inverted: metadata.y_inverted, self.render_texture(
surface_dimensions: metadata.dimensions, frame,
surface_location: (x, y), RenderTextureSpec {
screen_size: screen_dimensions, texture: &texture,
blending: ::glium::Blend { texture_kind,
color: ::glium::BlendingFunction::Addition { y_inverted,
source: ::glium::LinearBlendingFactor::One, surface_dimensions,
destination: ::glium::LinearBlendingFactor::OneMinusSourceAlpha, surface_location: (x, y),
screen_size: screen_dimensions,
blending: ::glium::Blend {
color: ::glium::BlendingFunction::Addition {
source: ::glium::LinearBlendingFactor::One,
destination: ::glium::LinearBlendingFactor::OneMinusSourceAlpha,
},
alpha: ::glium::BlendingFunction::Addition {
source: ::glium::LinearBlendingFactor::One,
destination: ::glium::LinearBlendingFactor::OneMinusSourceAlpha,
},
..Default::default()
}, },
alpha: ::glium::BlendingFunction::Addition {
source: ::glium::LinearBlendingFactor::One,
destination: ::glium::LinearBlendingFactor::OneMinusSourceAlpha,
},
..Default::default()
}, },
}, );
); }
} }
} }
}, },

View File

@ -82,6 +82,7 @@ impl AnvilState {
); );
} }
}, },
#[cfg(feature = "udev")]
KeyAction::Screen(num) => { KeyAction::Screen(num) => {
let output_map = self.output_map let output_map = self.output_map
.as_ref().unwrap(); .as_ref().unwrap();

View File

@ -1,6 +1,5 @@
use std::{ use std::{
cell::RefCell, cell::RefCell,
collections::HashMap,
rc::Rc, rc::Rc,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
@ -655,7 +654,7 @@ pub struct CommitedState {
#[derive(Default)] #[derive(Default)]
pub struct SurfaceData { pub struct SurfaceData {
pub texture: HashMap<usize, crate::glium_drawer::TextureMetadata>, pub texture: Option<crate::buffer_utils::BufferTextures>,
pub geometry: Option<Rectangle>, pub geometry: Option<Rectangle>,
pub resize_state: ResizeState, pub resize_state: ResizeState,
/// Minimum width and height, as requested by the surface. /// Minimum width and height, as requested by the surface.
@ -674,7 +673,7 @@ impl SurfaceData {
/// Apply a next state into the surface current state /// Apply a next state into the surface current state
pub fn apply_state(&mut self, next_state: CommitedState) { pub fn apply_state(&mut self, next_state: CommitedState) {
if Self::merge_state(&mut self.current_state, next_state) { if Self::merge_state(&mut self.current_state, next_state) {
self.texture.clear(); let _ = self.texture.take();
} }
} }

View File

@ -32,13 +32,7 @@ pub fn load_shm_buffer(data: BufferData, pool: &[u8]) -> Result<(RawImage2d<'_,
}; };
// sharders format need to be reversed to account for endianness // sharders format need to be reversed to account for endianness
let (client_format, fragment) = match data.format { let (client_format, fragment) = load_format(data.format)?;
Format::Argb8888 => (ClientFormat::U8U8U8U8, crate::shaders::BUFFER_BGRA),
Format::Xrgb8888 => (ClientFormat::U8U8U8U8, crate::shaders::BUFFER_BGRX),
Format::Rgba8888 => (ClientFormat::U8U8U8U8, crate::shaders::BUFFER_ABGR),
Format::Rgbx8888 => (ClientFormat::U8U8U8U8, crate::shaders::BUFFER_XBGR),
_ => return Err(data.format),
};
Ok(( Ok((
RawImage2d { RawImage2d {
data: slice, data: slice,
@ -49,3 +43,13 @@ pub fn load_shm_buffer(data: BufferData, pool: &[u8]) -> Result<(RawImage2d<'_,
fragment, fragment,
)) ))
} }
pub fn load_format(format: Format) -> Result<(ClientFormat, usize), Format> {
Ok(match format {
Format::Argb8888 => (ClientFormat::U8U8U8U8, crate::shaders::BUFFER_BGRA),
Format::Xrgb8888 => (ClientFormat::U8U8U8U8, crate::shaders::BUFFER_BGRX),
Format::Rgba8888 => (ClientFormat::U8U8U8U8, crate::shaders::BUFFER_ABGR),
Format::Rgbx8888 => (ClientFormat::U8U8U8U8, crate::shaders::BUFFER_XBGR),
_ => return Err(format),
})
}

View File

@ -8,7 +8,6 @@ use std::{
}; };
use smithay::{ use smithay::{
backend::session::auto::AutoSession,
reexports::{ reexports::{
calloop::{ calloop::{
generic::{Fd, Generic}, generic::{Fd, Generic},
@ -25,9 +24,14 @@ use smithay::{
}; };
#[cfg(feature = "udev")] #[cfg(feature = "udev")]
use smithay::backend::session::Session; use smithay::backend::session::{
auto::AutoSession,
Session,
};
use crate::{buffer_utils::BufferUtils, shell::init_shell, udev::MyOutput}; use crate::{buffer_utils::BufferUtils, shell::init_shell};
#[cfg(feature = "udev")]
use crate::udev::MyOutput;
pub struct AnvilState { pub struct AnvilState {
pub socket_name: String, pub socket_name: String,
@ -129,7 +133,7 @@ impl AnvilState {
"anvil".into() "anvil".into()
}; };
#[cfg(not(feature = "udev"))] #[cfg(not(feature = "udev"))]
let seat_name = "anvil".into(); let seat_name: String = "anvil".into();
let (mut seat, _) = Seat::new( let (mut seat, _) = Seat::new(
&mut display.borrow_mut(), &mut display.borrow_mut(),

View File

@ -127,7 +127,7 @@ pub fn run_udev(
let mut state = AnvilState::init( let mut state = AnvilState::init(
display.clone(), display.clone(),
event_loop.handle(), event_loop.handle(),
buffer_utils, buffer_utils.clone(),
Some(session), Some(session),
Some(output_map.clone()), Some(output_map.clone()),
log.clone(), log.clone(),
@ -143,6 +143,7 @@ pub fn run_udev(
let mut udev_handler = UdevHandlerImpl { let mut udev_handler = UdevHandlerImpl {
compositor_token: state.ctoken, compositor_token: state.ctoken,
buffer_utils: buffer_utils,
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
egl_buffer_reader, egl_buffer_reader,
session: state.session.clone().unwrap(), session: state.session.clone().unwrap(),
@ -292,6 +293,7 @@ struct BackendData {
struct UdevHandlerImpl<Data: 'static> { struct UdevHandlerImpl<Data: 'static> {
compositor_token: CompositorToken<Roles>, compositor_token: CompositorToken<Roles>,
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,
@ -310,10 +312,9 @@ struct UdevHandlerImpl<Data: 'static> {
} }
impl<Data: 'static> UdevHandlerImpl<Data> { impl<Data: 'static> UdevHandlerImpl<Data> {
#[cfg(feature = "egl")]
pub fn scan_connectors( pub fn scan_connectors(
device: &mut RenderDevice, device: &mut RenderDevice,
egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>, 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,
@ -347,7 +348,7 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
device device
.create_surface(crtc, connector_info.modes()[0], &[connector_info.handle()]) .create_surface(crtc, connector_info.modes()[0], &[connector_info.handle()])
.unwrap(), .unwrap(),
egl_buffer_reader.clone(), buffer_utils.clone(),
logger.clone(), logger.clone(),
); );
output_map.push(MyOutput::new(display, device.device_id(), crtc, connector_info, logger.clone())); output_map.push(MyOutput::new(display, device.device_id(), crtc, connector_info, logger.clone()));
@ -361,52 +362,6 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
backends backends
} }
#[cfg(not(feature = "egl"))]
pub fn scan_connectors(
device: &mut RenderDevice,
display: &mut Display,
output_map: &mut Vec<MyOutput>,
logger: &::slog::Logger,
) -> HashMap<crtc::Handle, Rc<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.get_connector_info(*conn).unwrap())
.filter(|conn| conn.state() == ConnectorState::Connected)
.inspect(|conn| info!(logger, "Connected: {:?}", conn.interface()))
.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()
.filter_map(|e| *e)
.flat_map(|encoder_handle| device.get_encoder_info(encoder_handle))
.collect::<Vec<EncoderInfo>>();
'outer: for encoder_info in encoder_infos {
for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) {
if !backends.contains_key(&crtc) {
let renderer =
GliumDrawer::init(device.create_surface(crtc).unwrap(), logger.clone());
output_map.push(MyOutput::new(display, device.device_id(), crtc, connector_info, logger.clone()));
backends.insert(crtc, Rc::new(renderer));
break 'outer;
}
}
}
}
backends
}
} }
impl<Data: 'static> UdevHandlerImpl<Data> { impl<Data: 'static> UdevHandlerImpl<Data> {
@ -453,23 +408,15 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
{ {
if path.canonicalize().ok() == self.primary_gpu { if path.canonicalize().ok() == self.primary_gpu {
info!(self.logger, "Initializing EGL Hardware Acceleration via {:?}", path);
*self.egl_buffer_reader.borrow_mut() = *self.egl_buffer_reader.borrow_mut() =
device.bind_wl_display(&*self.display.borrow()).ok(); device.bind_wl_display(&*self.display.borrow()).ok();
} }
} }
#[cfg(feature = "egl")]
let backends = Rc::new(RefCell::new(UdevHandlerImpl::<Data>::scan_connectors(
&mut device,
self.egl_buffer_reader.clone(),
&mut *self.display.borrow_mut(),
&mut *self.output_map.borrow_mut(),
&self.logger,
)));
#[cfg(not(feature = "egl"))]
let backends = Rc::new(RefCell::new(UdevHandlerImpl::<Data>::scan_connectors( let backends = Rc::new(RefCell::new(UdevHandlerImpl::<Data>::scan_connectors(
&mut device, &mut device,
&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(),
&self.logger, &self.logger,
@ -528,9 +475,9 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
fn device_changed(&mut self, device: dev_t) { fn device_changed(&mut self, device: dev_t) {
//quick and dirty, just re-init all backends //quick and dirty, just re-init all backends
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;
let egl_buffer_reader = self.egl_buffer_reader.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();
@ -538,21 +485,13 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
self.loop_handle self.loop_handle
.with_source(&backend_data.event_source, |source| { .with_source(&backend_data.event_source, |source| {
let mut backends = backend_data.surfaces.borrow_mut(); let mut backends = backend_data.surfaces.borrow_mut();
#[cfg(feature = "egl")] *backends =
let new_backends =
UdevHandlerImpl::<Data>::scan_connectors( UdevHandlerImpl::<Data>::scan_connectors(
&mut source.file, &mut source.file,
egl_buffer_reader, buffer_utils,
&mut *display, &mut *display,
&mut *output_map, &mut *output_map,
logger); logger);
#[cfg(not(feature = "egl"))]
let new_backends = UdevHandlerImpl::<Data>::scan_connectors(
&mut source.file,
&mut *display,
&mut *output_map,
logger);
*backends = new_backends;
for renderer in backends.values() { for renderer in backends.values() {
// render first frame // render first frame

View File

@ -1,7 +1,7 @@
use std::{cell::RefCell, rc::Rc, sync::atomic::Ordering, time::Duration}; use std::{cell::RefCell, rc::Rc, sync::atomic::Ordering, time::Duration};
use smithay::{ use smithay::{
backend::{egl::EGLGraphicsBackend, graphics::gl::GLGraphicsBackend, input::InputBackend, winit}, backend::{graphics::gl::GLGraphicsBackend, input::InputBackend, winit},
reexports::{ reexports::{
calloop::EventLoop, calloop::EventLoop,
wayland_server::{protocol::wl_output, Display}, wayland_server::{protocol::wl_output, Display},
@ -12,6 +12,8 @@ use smithay::{
SERIAL_COUNTER as SCOUNTER, SERIAL_COUNTER as SCOUNTER,
}, },
}; };
#[cfg(feature = "egl")]
use smithay::backend::egl::EGLGraphicsBackend;
use slog::Logger; use slog::Logger;
@ -38,17 +40,14 @@ pub fn run_winit(
}, },
)); ));
let (w, h) = renderer.get_framebuffer_dimensions();
#[cfg(feature = "egl")]
let drawer = GliumDrawer::init(renderer, egl_buffer_reader.clone(), log.clone());
#[cfg(not(feature = "egl"))]
let drawer = GliumDrawer::init(renderer, log.clone());
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
let buffer_utils = BufferUtils::new(egl_buffer_reader, log.clone()); let buffer_utils = BufferUtils::new(egl_buffer_reader, 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 (w, h) = renderer.get_framebuffer_dimensions();
let drawer = GliumDrawer::init(renderer, buffer_utils.clone(), log.clone());
/* /*
* Initialize the globals * Initialize the globals
*/ */