anvil: Introduce BufferTextures
This commit is contained in:
parent
d603a9ccfb
commit
bf011e8071
|
@ -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;
|
||||
|
||||
#[cfg(feature = "egl")]
|
||||
use smithay::backend::egl::display::EGLBufferReader;
|
||||
use smithay::backend::egl::{display::EGLBufferReader, EGLImages, BufferAccessError as EGLBufferAccessError, Format};
|
||||
use smithay::{
|
||||
backend::graphics::gl::GLGraphicsBackend,
|
||||
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.
|
||||
#[derive(Clone)]
|
||||
pub struct BufferUtils {
|
||||
|
@ -41,22 +54,172 @@ impl BufferUtils {
|
|||
.borrow()
|
||||
.as_ref()
|
||||
.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.
|
||||
#[cfg(not(feature = "egl"))]
|
||||
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.
|
||||
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))
|
||||
.map_err(|err| {
|
||||
warn!(self.log, "Unable to load buffer contents"; "err" => format!("{:?}", 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()
|
||||
}
|
||||
}
|
|
@ -7,35 +7,30 @@ use std::{
|
|||
use glium::{
|
||||
self,
|
||||
index::PrimitiveType,
|
||||
texture::{MipmapsOption, Texture2d, UncompressedFloatFormat},
|
||||
GlObject, Surface,
|
||||
texture::Texture2d,
|
||||
Surface,
|
||||
};
|
||||
use slog::Logger;
|
||||
|
||||
#[cfg(feature = "egl")]
|
||||
use smithay::backend::egl::display::EGLBufferReader;
|
||||
use smithay::{
|
||||
backend::{
|
||||
egl::{BufferAccessError, EGLImages, Format},
|
||||
graphics::{
|
||||
gl::GLGraphicsBackend,
|
||||
glium::{Frame, GliumGraphicsBackend},
|
||||
SwapBuffersError,
|
||||
},
|
||||
backend::graphics::{
|
||||
gl::GLGraphicsBackend,
|
||||
glium::{Frame, GliumGraphicsBackend},
|
||||
SwapBuffersError,
|
||||
},
|
||||
reexports::{
|
||||
calloop::LoopHandle,
|
||||
wayland_server::protocol::{wl_buffer, wl_surface},
|
||||
wayland_server::protocol::wl_surface,
|
||||
},
|
||||
utils::Rectangle,
|
||||
wayland::{
|
||||
compositor::{roles::Role, SubsurfaceRole, TraversalAction},
|
||||
data_device::DnDIconRole,
|
||||
seat::CursorImageRole,
|
||||
shm::with_buffer_contents as shm_buffer_contents,
|
||||
},
|
||||
};
|
||||
|
||||
use crate::buffer_utils::BufferUtils;
|
||||
use crate::shaders;
|
||||
use crate::shell::{MyCompositorToken, MyWindowMap, SurfaceData};
|
||||
|
||||
|
@ -55,13 +50,12 @@ mod implement_vertex {
|
|||
}
|
||||
|
||||
pub struct GliumDrawer<F: GLGraphicsBackend + 'static> {
|
||||
id: usize,
|
||||
display: GliumGraphicsBackend<F>,
|
||||
pub id: usize,
|
||||
pub display: GliumGraphicsBackend<F>,
|
||||
vertex_buffer: glium::VertexBuffer<Vertex>,
|
||||
index_buffer: glium::IndexBuffer<u16>,
|
||||
programs: [glium::Program; shaders::FRAGMENT_COUNT],
|
||||
#[cfg(feature = "egl")]
|
||||
egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>,
|
||||
buffer_loader: BufferUtils,
|
||||
log: Logger,
|
||||
}
|
||||
|
||||
|
@ -72,10 +66,9 @@ impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
|
|||
}
|
||||
|
||||
impl<T: Into<GliumGraphicsBackend<T>> + GLGraphicsBackend + 'static> GliumDrawer<T> {
|
||||
#[cfg(feature = "egl")]
|
||||
pub fn init(
|
||||
backend: T,
|
||||
egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>,
|
||||
buffer_loader: BufferUtils,
|
||||
log: Logger,
|
||||
) -> GliumDrawer<T> {
|
||||
let display = backend.into();
|
||||
|
@ -116,140 +109,13 @@ impl<T: Into<GliumGraphicsBackend<T>> + GLGraphicsBackend + 'static> GliumDrawer
|
|||
vertex_buffer,
|
||||
index_buffer,
|
||||
programs,
|
||||
egl_buffer_reader,
|
||||
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,
|
||||
buffer_loader,
|
||||
log,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<'_>) {
|
||||
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);
|
||||
|
@ -302,15 +168,6 @@ pub struct RenderTextureSpec<'a> {
|
|||
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> {
|
||||
fn draw_surface_tree(
|
||||
&self,
|
||||
|
@ -327,30 +184,18 @@ impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
|
|||
// Pull a new buffer if available
|
||||
if let Some(data) = attributes.user_data.get::<RefCell<SurfaceData>>() {
|
||||
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 Ok(m) = self.texture_from_buffer(buffer.clone()) {
|
||||
// release the buffer if it was an SHM buffer
|
||||
#[cfg(feature = "egl")]
|
||||
{
|
||||
if m.images.is_none() {
|
||||
buffer.release();
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "egl"))]
|
||||
{
|
||||
buffer.release();
|
||||
}
|
||||
data.texture.insert(self.id, m);
|
||||
} else {
|
||||
match self.buffer_loader.load_buffer(buffer) {
|
||||
Ok(m) => data.texture = Some(m),
|
||||
// there was an error reading the buffer, release it, we
|
||||
// already logged the error
|
||||
buffer.release();
|
||||
}
|
||||
Err(buffer) => buffer.release(),
|
||||
};
|
||||
}
|
||||
}
|
||||
// Now, should we be drawn ?
|
||||
if data.texture.contains_key(&self.id) {
|
||||
if data.texture.is_some() {
|
||||
// if yes, also process the children
|
||||
if Role::<SubsurfaceRole>::has(role) {
|
||||
x += data.current_state.sub_location.0;
|
||||
|
@ -368,36 +213,42 @@ impl<F: GLGraphicsBackend + 'static> GliumDrawer<F> {
|
|||
},
|
||||
|_surface, attributes, role, &(mut x, mut y)| {
|
||||
if let Some(ref data) = attributes.user_data.get::<RefCell<SurfaceData>>() {
|
||||
let data = data.borrow();
|
||||
if let Some(ref metadata) = data.texture.get(&self.id) {
|
||||
// we need to re-extract the subsurface offset, as the previous closure
|
||||
// only passes it to our children
|
||||
if Role::<SubsurfaceRole>::has(role) {
|
||||
x += data.current_state.sub_location.0;
|
||||
y += data.current_state.sub_location.1;
|
||||
}
|
||||
self.render_texture(
|
||||
frame,
|
||||
RenderTextureSpec {
|
||||
texture: &metadata.texture,
|
||||
texture_kind: metadata.fragment,
|
||||
y_inverted: metadata.y_inverted,
|
||||
surface_dimensions: metadata.dimensions,
|
||||
surface_location: (x, y),
|
||||
screen_size: screen_dimensions,
|
||||
blending: ::glium::Blend {
|
||||
color: ::glium::BlendingFunction::Addition {
|
||||
source: ::glium::LinearBlendingFactor::One,
|
||||
destination: ::glium::LinearBlendingFactor::OneMinusSourceAlpha,
|
||||
let mut data = data.borrow_mut();
|
||||
let (sub_x, sub_y) = data.current_state.sub_location;
|
||||
if let Some(buffer_textures) = data.texture.as_mut() {
|
||||
let texture_kind = buffer_textures.fragment;
|
||||
let y_inverted = buffer_textures.y_inverted;
|
||||
let surface_dimensions = buffer_textures.dimensions;
|
||||
if let Ok(ref texture) = buffer_textures.load_texture(&self) {
|
||||
// we need to re-extract the subsurface offset, as the previous closure
|
||||
// only passes it to our children
|
||||
if Role::<SubsurfaceRole>::has(role) {
|
||||
x += sub_x;
|
||||
y += sub_y;
|
||||
}
|
||||
self.render_texture(
|
||||
frame,
|
||||
RenderTextureSpec {
|
||||
texture: &texture,
|
||||
texture_kind,
|
||||
y_inverted,
|
||||
surface_dimensions,
|
||||
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()
|
||||
},
|
||||
},
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -82,6 +82,7 @@ impl AnvilState {
|
|||
);
|
||||
}
|
||||
},
|
||||
#[cfg(feature = "udev")]
|
||||
KeyAction::Screen(num) => {
|
||||
let output_map = self.output_map
|
||||
.as_ref().unwrap();
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use std::{
|
||||
cell::RefCell,
|
||||
collections::HashMap,
|
||||
rc::Rc,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
@ -655,7 +654,7 @@ pub struct CommitedState {
|
|||
|
||||
#[derive(Default)]
|
||||
pub struct SurfaceData {
|
||||
pub texture: HashMap<usize, crate::glium_drawer::TextureMetadata>,
|
||||
pub texture: Option<crate::buffer_utils::BufferTextures>,
|
||||
pub geometry: Option<Rectangle>,
|
||||
pub resize_state: ResizeState,
|
||||
/// Minimum width and height, as requested by the surface.
|
||||
|
@ -674,7 +673,7 @@ impl SurfaceData {
|
|||
/// Apply a next state into the surface current state
|
||||
pub fn apply_state(&mut self, next_state: CommitedState) {
|
||||
if Self::merge_state(&mut self.current_state, next_state) {
|
||||
self.texture.clear();
|
||||
let _ = self.texture.take();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
let (client_format, fragment) = match 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),
|
||||
};
|
||||
let (client_format, fragment) = load_format(data.format)?;
|
||||
Ok((
|
||||
RawImage2d {
|
||||
data: slice,
|
||||
|
@ -49,3 +43,13 @@ pub fn load_shm_buffer(data: BufferData, pool: &[u8]) -> Result<(RawImage2d<'_,
|
|||
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),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ use std::{
|
|||
};
|
||||
|
||||
use smithay::{
|
||||
backend::session::auto::AutoSession,
|
||||
reexports::{
|
||||
calloop::{
|
||||
generic::{Fd, Generic},
|
||||
|
@ -25,9 +24,14 @@ use smithay::{
|
|||
};
|
||||
|
||||
#[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 socket_name: String,
|
||||
|
@ -129,7 +133,7 @@ impl AnvilState {
|
|||
"anvil".into()
|
||||
};
|
||||
#[cfg(not(feature = "udev"))]
|
||||
let seat_name = "anvil".into();
|
||||
let seat_name: String = "anvil".into();
|
||||
|
||||
let (mut seat, _) = Seat::new(
|
||||
&mut display.borrow_mut(),
|
||||
|
|
|
@ -127,7 +127,7 @@ pub fn run_udev(
|
|||
let mut state = AnvilState::init(
|
||||
display.clone(),
|
||||
event_loop.handle(),
|
||||
buffer_utils,
|
||||
buffer_utils.clone(),
|
||||
Some(session),
|
||||
Some(output_map.clone()),
|
||||
log.clone(),
|
||||
|
@ -143,6 +143,7 @@ pub fn run_udev(
|
|||
|
||||
let mut udev_handler = UdevHandlerImpl {
|
||||
compositor_token: state.ctoken,
|
||||
buffer_utils: buffer_utils,
|
||||
#[cfg(feature = "egl")]
|
||||
egl_buffer_reader,
|
||||
session: state.session.clone().unwrap(),
|
||||
|
@ -292,6 +293,7 @@ struct BackendData {
|
|||
|
||||
struct UdevHandlerImpl<Data: 'static> {
|
||||
compositor_token: CompositorToken<Roles>,
|
||||
buffer_utils: BufferUtils,
|
||||
#[cfg(feature = "egl")]
|
||||
egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>,
|
||||
session: AutoSession,
|
||||
|
@ -310,10 +312,9 @@ struct UdevHandlerImpl<Data: 'static> {
|
|||
}
|
||||
|
||||
impl<Data: 'static> UdevHandlerImpl<Data> {
|
||||
#[cfg(feature = "egl")]
|
||||
pub fn scan_connectors(
|
||||
device: &mut RenderDevice,
|
||||
egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>,
|
||||
buffer_utils: &BufferUtils,
|
||||
display: &mut Display,
|
||||
output_map: &mut Vec<MyOutput>,
|
||||
logger: &::slog::Logger,
|
||||
|
@ -347,7 +348,7 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
|
|||
device
|
||||
.create_surface(crtc, connector_info.modes()[0], &[connector_info.handle()])
|
||||
.unwrap(),
|
||||
egl_buffer_reader.clone(),
|
||||
buffer_utils.clone(),
|
||||
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
|
||||
}
|
||||
|
||||
#[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> {
|
||||
|
@ -453,23 +408,15 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
|
|||
#[cfg(feature = "egl")]
|
||||
{
|
||||
if path.canonicalize().ok() == self.primary_gpu {
|
||||
info!(self.logger, "Initializing EGL Hardware Acceleration via {:?}", path);
|
||||
*self.egl_buffer_reader.borrow_mut() =
|
||||
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(
|
||||
&mut device,
|
||||
&self.buffer_utils,
|
||||
&mut *self.display.borrow_mut(),
|
||||
&mut *self.output_map.borrow_mut(),
|
||||
&self.logger,
|
||||
|
@ -528,9 +475,9 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
|
|||
|
||||
fn device_changed(&mut self, device: dev_t) {
|
||||
//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) {
|
||||
let logger = &self.logger;
|
||||
let egl_buffer_reader = self.egl_buffer_reader.clone();
|
||||
let loop_handle = self.loop_handle.clone();
|
||||
let mut display = self.display.borrow_mut();
|
||||
let mut output_map = self.output_map.borrow_mut();
|
||||
|
@ -538,21 +485,13 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
|
|||
self.loop_handle
|
||||
.with_source(&backend_data.event_source, |source| {
|
||||
let mut backends = backend_data.surfaces.borrow_mut();
|
||||
#[cfg(feature = "egl")]
|
||||
let new_backends =
|
||||
*backends =
|
||||
UdevHandlerImpl::<Data>::scan_connectors(
|
||||
&mut source.file,
|
||||
egl_buffer_reader,
|
||||
buffer_utils,
|
||||
&mut *display,
|
||||
&mut *output_map,
|
||||
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() {
|
||||
// render first frame
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::{cell::RefCell, rc::Rc, sync::atomic::Ordering, time::Duration};
|
||||
|
||||
use smithay::{
|
||||
backend::{egl::EGLGraphicsBackend, graphics::gl::GLGraphicsBackend, input::InputBackend, winit},
|
||||
backend::{graphics::gl::GLGraphicsBackend, input::InputBackend, winit},
|
||||
reexports::{
|
||||
calloop::EventLoop,
|
||||
wayland_server::{protocol::wl_output, Display},
|
||||
|
@ -12,6 +12,8 @@ use smithay::{
|
|||
SERIAL_COUNTER as SCOUNTER,
|
||||
},
|
||||
};
|
||||
#[cfg(feature = "egl")]
|
||||
use smithay::backend::egl::EGLGraphicsBackend;
|
||||
|
||||
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")]
|
||||
let buffer_utils = BufferUtils::new(egl_buffer_reader, log.clone());
|
||||
#[cfg(not(feature = "egl"))]
|
||||
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
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue