Get it to work...

This commit is contained in:
Drakulix 2017-12-28 15:28:15 +01:00
parent 726991367d
commit 6c6d54064d
9 changed files with 309 additions and 144 deletions

View File

@ -3,7 +3,8 @@ use glium::{Frame, Surface, GlObject};
use glium::backend::Facade; use glium::backend::Facade;
use glium::index::PrimitiveType; use glium::index::PrimitiveType;
use glium::texture::{MipmapsOption, UncompressedFloatFormat, Texture2d}; use glium::texture::{MipmapsOption, UncompressedFloatFormat, Texture2d};
use smithay::backend::graphics::egl::{EGLGraphicsBackend, EGLImage}; use smithay::backend::graphics::egl::EGLGraphicsBackend;
use smithay::backend::graphics::egl::wayland::{Format, EGLImages};
use smithay::backend::graphics::glium::GliumGraphicsBackend; use smithay::backend::graphics::glium::GliumGraphicsBackend;
use std::borrow::Borrow; use std::borrow::Borrow;
use std::ops::Deref; use std::ops::Deref;
@ -108,45 +109,52 @@ impl<T: Into<GliumGraphicsBackend<T>> + EGLGraphicsBackend + 'static> From<T> fo
} }
impl<F: EGLGraphicsBackend + 'static> GliumDrawer<F> { impl<F: EGLGraphicsBackend + 'static> GliumDrawer<F> {
pub fn texture_from_mem(&self, contents: &[u8], surface_dimensions: (u32, u32)) { pub fn texture_from_mem(&self, contents: &[u8], surface_dimensions: (u32, u32)) -> Texture2d {
let image = glium::texture::RawImage2d { let image = glium::texture::RawImage2d {
data: contents.into(), data: contents.into(),
width: surface_dimensions.0, width: surface_dimensions.0,
height: surface_dimensions.1, height: surface_dimensions.1,
format: glium::texture::ClientFormat::U8U8U8U8, format: glium::texture::ClientFormat::U8U8U8U8,
}; };
let opengl_texture = Texture2d::new(&self.display, image).unwrap(); Texture2d::new(&self.display, image).unwrap()
} }
pub fn texture_from_egl(&self, image: EGLImage, format: UncompressedFloatFormat, pub fn texture_from_egl(&self, images: &EGLImages)
surface_dimensions: (u32, u32)) -> Option<Texture2d>
-> Texture2d
{ {
let format = match images.format {
Format::RGB => UncompressedFloatFormat::U8U8U8,
Format::RGBA => UncompressedFloatFormat::U8U8U8U8,
_ => return None,
};
let opengl_texture = Texture2d::empty_with_format( let opengl_texture = Texture2d::empty_with_format(
&self.display, &self.display,
format, format,
MipmapsOption::NoMipmap, MipmapsOption::NoMipmap,
surface_dimensions.0, images.width,
surface_dimensions.1, images.height,
).unwrap(); ).unwrap();
self.display.get_context().exec_in_context(|| { if let Err(_) = unsafe { self.display.get_context().exec_in_context(|| {
self.display.borrow().egl_image_to_texture(image, opengl_texture.get_id()); images.bind_to_texture(0, opengl_texture.get_id())
}); }) } { return None };
opengl_texture Some(opengl_texture)
} }
pub fn render_texture(&self, target: &mut glium::Frame, texture: Texture2d, pub fn render_texture(&self, target: &mut glium::Frame, texture: &Texture2d,
y_inverted: bool, surface_dimensions: (u32, u32), y_inverted: bool, surface_dimensions: (u32, u32),
surface_location: (i32, i32), screen_size: (u32, u32)) surface_location: (i32, i32), screen_size: (u32, u32))
{ {
let xscale = 2.0 * (surface_dimensions.0 as f32) / (screen_size.0 as f32); let xscale = 2.0 * (surface_dimensions.0 as f32) / (screen_size.0 as f32);
let mut yscale = -2.0 * (surface_dimensions.1 as f32) / (screen_size.1 as f32); let mut yscale = -2.0 * (surface_dimensions.1 as f32) / (screen_size.1 as f32);
if y_inverted {
yscale = -yscale;
}
let x = 2.0 * (surface_location.0 as f32) / (screen_size.0 as f32) - 1.0; let x = 2.0 * (surface_location.0 as f32) / (screen_size.0 as f32) - 1.0;
let y = 1.0 - 2.0 * (surface_location.1 as f32) / (screen_size.1 as f32); let mut y = 1.0 - 2.0 * (surface_location.1 as f32) / (screen_size.1 as f32);
if y_inverted {
yscale = -yscale;
y -= surface_dimensions.1 as f32;
}
let uniforms = uniform! { let uniforms = uniform! {
matrix: [ matrix: [
@ -155,7 +163,7 @@ impl<F: EGLGraphicsBackend + 'static> GliumDrawer<F> {
[ 0.0 , 0.0 , 1.0, 0.0], [ 0.0 , 0.0 , 1.0, 0.0],
[ x , y , 0.0, 1.0] [ x , y , 0.0, 1.0]
], ],
tex: &texture, tex: texture,
}; };
target target
@ -164,10 +172,28 @@ impl<F: EGLGraphicsBackend + 'static> GliumDrawer<F> {
&self.index_buffer, &self.index_buffer,
&self.program, &self.program,
&uniforms, &uniforms,
&Default::default(), &glium::DrawParameters {
blend: 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()
},
depth: glium::Depth {
test: glium::DepthTest::IfLess,
write: false,
..Default::default()
},
.. Default::default()
},
) )
.unwrap(); .unwrap();
} }
#[inline] #[inline]
pub fn draw(&self) -> Frame { pub fn draw(&self) -> Frame {

View File

@ -1,78 +1,81 @@
use super::{GliumDrawer, WindowMap}; use super::{GliumDrawer, WindowMap};
use glium::texture::{Texture2d, UncompressedFloatFormat}; use smithay::backend::graphics::egl::wayland::{Format, BufferAccessError};
use glium::texture::Texture2d;
use rand; use rand;
use smithay::backend::graphics::egl::{EGLGraphicsBackend, EGLImage}; use smithay::backend::graphics::egl::{EGLGraphicsBackend, EGLImages};
use smithay::wayland::compositor::{compositor_init, CompositorToken, SurfaceAttributes, use smithay::wayland::compositor::{compositor_init, CompositorToken, SurfaceAttributes,
SurfaceUserImplementation}; SurfaceUserImplementation};
use smithay::wayland::shell::{shell_init, PopupConfigure, ShellState, ShellSurfaceRole, use smithay::wayland::shell::{shell_init, PopupConfigure, ShellState, ShellSurfaceRole,
ShellSurfaceUserImplementation, ToplevelConfigure}; ShellSurfaceUserImplementation, ToplevelConfigure};
use smithay::wayland::shm::with_buffer_contents as shm_buffer_contents; use smithay::wayland::shm::with_buffer_contents as shm_buffer_contents;
use smithay::wayland::drm::{with_buffer_contents as drm_buffer_contents, Attributes, Format};
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use std::borrow::Borrow;
use wayland_server::{EventLoop, StateToken}; use wayland_server::{EventLoop, StateToken};
define_roles!(Roles => [ ShellSurface, ShellSurfaceRole ] ); define_roles!(Roles => [ ShellSurface, ShellSurfaceRole ] );
#[derive(Default)] #[derive(Default)]
pub struct SurfaceData { pub struct SurfaceData {
pub texture: Option<Texture2d>,
pub buffer: Option<Buffer>, pub buffer: Option<Buffer>,
pub texture: Option<Texture2d>,
} }
pub enum Buffer { pub enum Buffer {
Egl { images: Vec<EGLImage>, attributes: Attributes }, Egl { images: EGLImages },
Shm { data: Vec<u8>, size: (u32, u32) }, Shm { data: Vec<u8>, size: (u32, u32) },
} }
unsafe impl Send for Buffer {} unsafe impl Send for Buffer {}
pub fn surface_implementation<G: EGLGraphicsBackend + 'static>() -> SurfaceUserImplementation<SurfaceData, Roles, GliumDrawer<G>> { pub fn surface_implementation<G: EGLGraphicsBackend + 'static>() -> SurfaceUserImplementation<SurfaceData, Roles, Rc<GliumDrawer<G>>> {
SurfaceUserImplementation { SurfaceUserImplementation {
commit: |_, drawer, surface, token| { commit: |_, drawer, surface, token| {
// we retrieve the contents of the associated buffer and copy it // we retrieve the contents of the associated buffer and copy it
token.with_surface_data(surface, |attributes| { token.with_surface_data(surface, |attributes| {
match attributes.buffer() { match attributes.buffer.take() {
Some(ref buffer) => { Some(Some((buffer, (_x, _y)))) => {
// we ignore hotspot coordinates in this simple example (`attributes.buffer_coordinates()`) // we ignore hotspot coordinates in this simple example
if drm_buffer_contents(&buffer, drawer.borrow(), |attributes, images| { match <GliumDrawer<G> as Borrow<G>>::borrow(&**drawer).egl_buffer_contents(buffer) {
let format = match attributes.format { Ok(images) => {
Format::RGB => UncompressedFloatFormat::U8U8U8, let format = match images.format {
Format::RGBA => UncompressedFloatFormat::U8U8U8U8, Format::RGB => {},
_ => { Format::RGBA => {},
// we don't handle the more complex formats here. _ => {
attributes.user_data.buffer = None; // we don't handle the more complex formats here.
attributes.user_data.texture = None; attributes.user_data.buffer = None;
return; attributes.user_data.texture = None;
}, return;
}; },
attributes.user_data.texture = Some(drawer.texture_from_egl( };
images[0] /*Both simple formats only have one plane*/, attributes.user_data.texture = drawer.texture_from_egl(&images);
format, attributes.user_data.buffer = Some(Buffer::Egl { images });
(attributes.width, attributes.height) },
)); Err(BufferAccessError::NotManaged(buffer)) => {
attributes.user_data.buffer = Some(Buffer::Egl { images, attributes }); shm_buffer_contents(&buffer, |slice, data| {
}).is_err() { let offset = data.offset as usize;
shm_buffer_contents(&buffer, |slice, data| { let stride = data.stride as usize;
let offset = data.offset as usize; let width = data.width as usize;
let stride = data.stride as usize; let height = data.height as usize;
let width = data.width as usize; let mut new_vec = Vec::with_capacity(width * height * 4);
let height = data.height as usize; for i in 0..height {
let mut new_vec = Vec::with_capacity(width * height * 4); new_vec
for i in 0..height { .extend(&slice[(offset + i * stride)..(offset + i * stride + width * 4)]);
new_vec }
.extend(&slice[(offset + i * stride)..(offset + i * stride + width * 4)]); attributes.user_data.texture = Some(drawer.texture_from_mem(&new_vec, (data.width as u32, data.height as u32)));
} attributes.user_data.buffer = Some(Buffer::Shm { data: new_vec, size: (data.width as u32, data.height as u32) });
attributes.user_data.texture = Some(drawer.texture_from_mem(&new_vec, data.width as u32, data.height as u32)); }).unwrap();
attributes.user_data.buffer = buffer.release();
Some(Buffer::Shm { data: new_vec, position: (data.width as u32, data.height as u32) }); },
}).unwrap(); Err(err) => panic!("EGL error: {}", err),
} }
} }
None => { Some(None) => {
// erase the contents // erase the contents
attributes.user_data.buffer = None; attributes.user_data.buffer = None;
attributes.user_data.texture = None;
} }
None => {}
} }
}); });
}, },
@ -82,14 +85,15 @@ pub fn surface_implementation<G: EGLGraphicsBackend + 'static>() -> SurfaceUserI
} }
} }
pub struct ShellIData<F> { pub struct ShellIData<F, G: EGLGraphicsBackend + 'static> {
pub token: CompositorToken<SurfaceData, Roles, ()>, pub token: CompositorToken<SurfaceData, Roles, Rc<GliumDrawer<G>>>,
pub window_map: Rc<RefCell<super::WindowMap<SurfaceData, Roles, (), (), F>>>, pub window_map: Rc<RefCell<super::WindowMap<SurfaceData, Roles, Rc<GliumDrawer<G>>, (), F>>>,
} }
pub fn shell_implementation<F>() -> ShellSurfaceUserImplementation<SurfaceData, Roles, (), ShellIData<F>, ()> pub fn shell_implementation<F, G>() -> ShellSurfaceUserImplementation<SurfaceData, Roles, Rc<GliumDrawer<G>>, ShellIData<F, G>, ()>
where where
F: Fn(&SurfaceAttributes<SurfaceData>) -> Option<(i32, i32)>, F: Fn(&SurfaceAttributes<SurfaceData>) -> Option<(i32, i32)>,
G: EGLGraphicsBackend + 'static,
{ {
ShellSurfaceUserImplementation { ShellSurfaceUserImplementation {
new_client: |_, _, _| {}, new_client: |_, _, _| {},
@ -134,23 +138,27 @@ fn get_size(attrs: &SurfaceAttributes<SurfaceData>) -> Option<(i32, i32)> {
.user_data .user_data
.buffer .buffer
.as_ref() .as_ref()
.map(|&(_, (w, h))| (w as i32, h as i32)) .map(|ref buffer| match **buffer {
Buffer::Shm { ref size, .. } => *size,
Buffer::Egl { ref images } => (images.width, images.height),
})
.map(|(x, y)| (x as i32, y as i32))
} }
pub type MyWindowMap = WindowMap< pub type MyWindowMap<G: EGLGraphicsBackend + 'static> = WindowMap<
SurfaceData, SurfaceData,
Roles, Roles,
(), Rc<GliumDrawer<G>>,
(), (),
fn(&SurfaceAttributes<SurfaceData>) -> Option<(i32, i32)>, fn(&SurfaceAttributes<SurfaceData>) -> Option<(i32, i32)>,
>; >;
pub fn init_shell<ID: 'static>( pub fn init_shell<G: EGLGraphicsBackend + 'static>(
evl: &mut EventLoop, log: ::slog::Logger, data: ID) evl: &mut EventLoop, log: ::slog::Logger, data: Rc<GliumDrawer<G>>)
-> ( -> (
CompositorToken<SurfaceData, Roles, ID>, CompositorToken<SurfaceData, Roles, Rc<GliumDrawer<G>>>,
StateToken<ShellState<SurfaceData, Roles, ID, ()>>, StateToken<ShellState<SurfaceData, Roles, Rc<GliumDrawer<G>>, ()>>,
Rc<RefCell<MyWindowMap>>, Rc<RefCell<MyWindowMap<G>>>,
) { ) {
let (compositor_token, _, _) = compositor_init(evl, surface_implementation(), data, log.clone()); let (compositor_token, _, _) = compositor_init(evl, surface_implementation(), data, log.clone());

View File

@ -27,23 +27,23 @@ use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use wayland_server::protocol::{wl_output, wl_pointer}; use wayland_server::protocol::{wl_output, wl_pointer};
struct WinitInputHandler { struct WinitInputHandler<G: EGLGraphicsBackend + 'static> {
log: Logger, log: Logger,
pointer: PointerHandle, pointer: PointerHandle,
keyboard: KeyboardHandle, keyboard: KeyboardHandle,
window_map: Rc<RefCell<MyWindowMap>>, window_map: Rc<RefCell<MyWindowMap<G>>>,
pointer_location: (f64, f64), pointer_location: (f64, f64),
serial: u32, serial: u32,
} }
impl WinitInputHandler { impl<G: EGLGraphicsBackend + 'static> WinitInputHandler<G> {
fn next_serial(&mut self) -> u32 { fn next_serial(&mut self) -> u32 {
self.serial += 1; self.serial += 1;
self.serial self.serial
} }
} }
impl InputHandler<winit::WinitInputBackend> for WinitInputHandler { impl<G: EGLGraphicsBackend + 'static> InputHandler<winit::WinitInputBackend> for WinitInputHandler<G> {
fn on_seat_created(&mut self, _: &input::Seat) { fn on_seat_created(&mut self, _: &input::Seat) {
/* never happens with winit */ /* never happens with winit */
} }
@ -140,6 +140,7 @@ fn main() {
info!(log, "EGL hardware-acceleration enabled"); info!(log, "EGL hardware-acceleration enabled");
} }
let (w, h) = renderer.get_framebuffer_dimensions();
let drawer = Rc::new(GliumDrawer::from(renderer)); let drawer = Rc::new(GliumDrawer::from(renderer));
/* /*
@ -172,7 +173,6 @@ fn main() {
log.clone(), log.clone(),
); );
let (w, h) = renderer.get_framebuffer_dimensions();
event_loop event_loop
.state() .state()
.get_mut(&output_token) .get_mut(&output_token)
@ -194,10 +194,6 @@ fn main() {
refresh: 60_000, refresh: 60_000,
}); });
/*
* Initialize glium
*/
input.set_handler(WinitInputHandler { input.set_handler(WinitInputHandler {
log: log.clone(), log: log.clone(),
pointer, pointer,
@ -217,7 +213,7 @@ fn main() {
input.dispatch_new_events().unwrap(); input.dispatch_new_events().unwrap();
let mut frame = drawer.draw(); let mut frame = drawer.draw();
frame.clear(None, Some((0.8, 0.8, 0.9, 1.0)), false, None, None); frame.clear(None, Some((0.8, 0.8, 0.9, 1.0)), false, Some(1.0), None);
// redraw the frame, in a simple but inneficient way // redraw the frame, in a simple but inneficient way
{ {
let screen_dimensions = drawer.get_framebuffer_dimensions(); let screen_dimensions = drawer.get_framebuffer_dimensions();
@ -232,7 +228,7 @@ fn main() {
initial_place, initial_place,
|_surface, attributes, role, &(mut x, mut y)| { |_surface, attributes, role, &(mut x, mut y)| {
// there is actually something to draw ! // there is actually something to draw !
if let Some(texture) = attributes.user_data.texture { if let Some(ref texture) = attributes.user_data.texture {
if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) { if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
x += subdata.x; x += subdata.x;
y += subdata.y; y += subdata.y;
@ -241,11 +237,11 @@ fn main() {
&mut frame, &mut frame,
texture, texture,
match *attributes.user_data.buffer.as_ref().unwrap() { match *attributes.user_data.buffer.as_ref().unwrap() {
Buffer::Egl { ref attributes, .. } => attributes.y_inverted, Buffer::Egl { ref images } => images.y_inverted,
Buffer::Shm { .. } => false, Buffer::Shm { .. } => false,
}, },
match *attributes.user_data.buffer.as_ref().unwrap() { match *attributes.user_data.buffer.as_ref().unwrap() {
Buffer::Egl { ref attributes, .. } => (attributes.width, attributes.height), Buffer::Egl { ref images } => (images.width, images.height),
Buffer::Shm { ref size, .. } => *size, Buffer::Shm { ref size, .. } => *size,
}, },
(x, y), (x, y),

View File

@ -132,6 +132,12 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
}; };
ffi::egl::LOAD.call_once(|| { ffi::egl::LOAD.call_once(|| {
fn constrain<F>(f: F) -> F
where
F: for<'a> Fn(&'a str) -> *const ::std::os::raw::c_void,
{
f
};
ffi::egl::load_with(|sym| { ffi::egl::load_with(|sym| {
let name = CString::new(sym).unwrap(); let name = CString::new(sym).unwrap();
let symbol = ffi::egl::LIB.get::<*mut c_void>(name.as_bytes()); let symbol = ffi::egl::LIB.get::<*mut c_void>(name.as_bytes());
@ -140,14 +146,16 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
Err(_) => ptr::null(), Err(_) => ptr::null(),
} }
}); });
ffi::gl::load_with(|sym| { let procAddress = constrain(|sym| {
let name = CString::new(sym).unwrap(); let addr = CString::new(sym).unwrap();
let symbol = ffi::egl::LIB.get::<*mut c_void>(name.as_bytes()); let addr = addr.as_ptr();
match symbol { ffi::egl::GetProcAddress(addr) as *const _
Ok(x) => *x as *const _,
Err(_) => ptr::null(),
}
}); });
ffi::egl::load_with(&procAddress);
ffi::egl::BindWaylandDisplayWL::load_with(&procAddress);
ffi::egl::UnbindWaylandDisplayWL::load_with(&procAddress);
ffi::egl::QueryWaylandBufferWL::load_with(&procAddress);
ffi::gl::load_with(&procAddress);
}); });
// the first step is to query the list of extensions without any display, if supported // the first step is to query the list of extensions without any display, if supported
@ -434,6 +442,23 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
info!(log, "EGL context created"); info!(log, "EGL context created");
// make current and get list of gl extensions
ffi::egl::MakeCurrent(
display as *const _,
ptr::null(),
ptr::null(),
context as *const _,
);
// the list of gl extensions supported by the context
let gl_extensions = {
let data = CStr::from_ptr(ffi::gl::GetString(ffi::gl::EXTENSIONS) as *const _).to_bytes().to_vec();
let list = String::from_utf8(data).unwrap();
list.split(' ').map(|e| e.to_string()).collect::<Vec<_>>()
};
info!(log, "GL Extensions: {:?}", gl_extensions);
Ok(( Ok((
Rc::new(context as *const _), Rc::new(context as *const _),
Rc::new(display as *const _), Rc::new(display as *const _),
@ -441,7 +466,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
surface_attributes, surface_attributes,
desc, desc,
extensions.iter().any(|s| *s == "EGL_WL_bind_wayland_display"), extensions.iter().any(|s| *s == "EGL_WL_bind_wayland_display"),
extensions.iter().any(|s| *s == "EGL_OES_image" || *s == "EGL_OES_image_base"), gl_extensions.iter().any(|s| *s == "GL_OES_EGL_image" || *s == "GL_OES_EGL_image_base"),
)) ))
} }
@ -530,7 +555,7 @@ pub enum GlProfile {
} }
/// Describes how the backend should choose a pixel format. /// Describes how the backend should choose a pixel format.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PixelFormatRequirements { pub struct PixelFormatRequirements {
/// If `true`, only hardware-accelerated formats will be conisdered. If `false`, only software renderers. /// If `true`, only hardware-accelerated formats will be conisdered. If `false`, only software renderers.
/// `None` means "don't care". Default is `None`. /// `None` means "don't care". Default is `None`.
@ -557,3 +582,19 @@ pub struct PixelFormatRequirements {
/// The default is `false`. /// The default is `false`.
pub stereoscopy: bool, pub stereoscopy: bool,
} }
impl Default for PixelFormatRequirements {
fn default() -> Self {
PixelFormatRequirements {
hardware_accelerated: Some(true),
color_bits: Some(24),
float_color_buffer: false,
alpha_bits: Some(8),
depth_bits: Some(24),
stencil_bits: Some(8),
double_buffer: Some(true),
multisampling: None,
stereoscopy: false,
}
}
}

View File

@ -47,11 +47,6 @@ error_chain! {
description("Failed to create a new EGLSurface") description("Failed to create a new EGLSurface")
} }
#[doc = "The OpenGL context has been lost and needs to be recreated"]
ContextLost {
description("The OpenGL context has been lost and needs to be recreated")
}
#[doc = "The required EGL extension is not supported by the underlying EGL implementation"] #[doc = "The required EGL extension is not supported by the underlying EGL implementation"]
EglExtensionNotSupported(extensions: &'static [&'static str]) { EglExtensionNotSupported(extensions: &'static [&'static str]) {
description("The required EGL extension is not supported by the underlying EGL implementation"), description("The required EGL extension is not supported by the underlying EGL implementation"),
@ -74,11 +69,6 @@ error_chain! {
description("Index of plane is out of bounds for EGLImages") description("Index of plane is out of bounds for EGLImages")
} }
#[doc = "This buffer is not mananged by EGL"]
BufferNotManaged {
description("This buffer is not mananged by EGL")
}
#[doc = "Failed to create EGLImages from the buffer"] #[doc = "Failed to create EGLImages from the buffer"]
EGLImageCreationFailed { EGLImageCreationFailed {
description("Failed to create EGLImages from the buffer") description("Failed to create EGLImages from the buffer")

View File

@ -9,8 +9,8 @@ use super::GraphicsBackend;
use nix::libc::c_void; use nix::libc::c_void;
use std::fmt; use std::fmt;
use wayland_server::Display; use wayland_server::Display;
use wayland_server::protocol::wl_buffer::WlBuffer;
pub use self::ffi::egl::types::EGLImage;
pub mod context; pub mod context;
pub use self::context::EGLContext; pub use self::context::EGLContext;
pub mod error; pub mod error;
@ -20,6 +20,7 @@ pub mod native;
pub mod surface; pub mod surface;
pub use self::surface::EGLSurface; pub use self::surface::EGLSurface;
pub mod wayland; pub mod wayland;
pub use self::wayland::{EGLImages, BufferAccessError};
/// Error that can happen when swapping buffers. /// Error that can happen when swapping buffers.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -182,5 +183,5 @@ pub trait EGLGraphicsBackend: GraphicsBackend {
/// `Display` multiple times, as only one context may be bound at any given time. /// `Display` multiple times, as only one context may be bound at any given time.
fn unbind_wl_display(&self, display: &Display) -> ::std::result::Result<(), EglExtensionNotSupportedError>; fn unbind_wl_display(&self, display: &Display) -> ::std::result::Result<(), EglExtensionNotSupportedError>;
// unsafe fn egl_image_to_texture(&self, image: ffi::egl::types::EGLImage, tex_id: c_uint) -> ::std::result::Result<(), EglExtensionNotSupportedError>; fn egl_buffer_contents(&self, buffer: WlBuffer) -> ::std::result::Result<EGLImages, wayland::BufferAccessError>;
} }

View File

@ -1,10 +1,114 @@
use backend::graphics::egl::{EGLContext, EGLImage, ffi, native}; use backend::graphics::egl::{EGLContext, EglExtensionNotSupportedError, ffi, native};
use backend::graphics::egl::error::*; use backend::graphics::egl::error::*;
use backend::graphics::egl::ffi::egl::types::EGLImage;
use nix::libc::{c_uint}; use nix::libc::{c_uint};
use std::rc::{Rc, Weak}; use std::rc::{Rc, Weak};
use std::fmt;
use wayland_server::{Display, Resource}; use wayland_server::{Display, Resource};
use wayland_server::protocol::wl_buffer::WlBuffer; use wayland_server::protocol::wl_buffer::WlBuffer;
/// Error that can occur when accessing an EGL buffer
pub enum BufferAccessError {
/// This buffer is not managed by the EGL buffer
NotManaged(WlBuffer),
/// Failed to create EGLImages from the buffer
EGLImageCreationFailed,
/// The required EGL extension is not supported by the underlying EGL implementation
EglExtensionNotSupported(EglExtensionNotSupportedError),
}
impl fmt::Debug for BufferAccessError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
match *self {
BufferAccessError::NotManaged(_) => write!(formatter, "BufferAccessError::NotManaged"),
BufferAccessError::EGLImageCreationFailed => write!(formatter, "BufferAccessError::EGLImageCreationFailed"),
BufferAccessError::EglExtensionNotSupported(ref err) => write!(formatter, "{:?}", err),
}
}
}
impl fmt::Display for BufferAccessError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
use ::std::error::Error;
match *self {
BufferAccessError::NotManaged(_) => write!(formatter, "{}", self.description()),
BufferAccessError::EGLImageCreationFailed => write!(formatter, "{}", self.description()),
BufferAccessError::EglExtensionNotSupported(ref err) => err.fmt(formatter),
}
}
}
impl ::std::error::Error for BufferAccessError {
fn description(&self) -> &str {
match *self {
BufferAccessError::NotManaged(_) => "This buffer is not mananged by EGL",
BufferAccessError::EGLImageCreationFailed => "Failed to create EGLImages from the buffer",
BufferAccessError::EglExtensionNotSupported(ref err) => err.description(),
}
}
fn cause(&self) -> Option<&::std::error::Error> {
match *self {
BufferAccessError::EglExtensionNotSupported(ref err) => Some(err),
_ => None,
}
}
}
impl From<EglExtensionNotSupportedError> for BufferAccessError {
fn from(error: EglExtensionNotSupportedError) -> Self {
BufferAccessError::EglExtensionNotSupported(error)
}
}
/// Error that might happen when binding an EGLImage to a gl texture
#[derive(Debug, Clone, PartialEq)]
pub enum TextureCreationError {
/// The given plane index is out of bounds
PlaneIndexOutOfBounds,
/// The OpenGL context has been lost and needs to be recreated.
///
/// All the objects associated to it (textures, buffers, programs, etc.)
/// need to be recreated from scratch.
///
/// Operations will have no effect. Functions that read textures, buffers, etc.
/// from OpenGL will return uninitialized data instead.
///
/// A context loss usually happens on mobile devices when the user puts the
/// application on sleep and wakes it up later. However any OpenGL implementation
/// can theoretically lose the context at any time.
ContextLost,
/// Failed to bind the EGLImage to the given texture
///
/// The given argument is the gl error code
TextureBindingFailed(u32),
}
impl fmt::Display for TextureCreationError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> ::std::result::Result<(), fmt::Error> {
use ::std::error::Error;
match *self {
TextureCreationError::ContextLost => write!(formatter, "{}", self.description()),
TextureCreationError::PlaneIndexOutOfBounds => write!(formatter, "{}", self.description()),
TextureCreationError::TextureBindingFailed(code) => write!(formatter, "{}. Gl error code: {:?}", self.description(), code),
}
}
}
impl ::std::error::Error for TextureCreationError {
fn description(&self) -> &str {
match *self {
TextureCreationError::ContextLost => "The context has been lost, it needs to be recreated",
TextureCreationError::PlaneIndexOutOfBounds => "This buffer is not mananged by EGL",
TextureCreationError::TextureBindingFailed(_) => "Failed to create EGLImages from the buffer",
}
}
fn cause(&self) -> Option<&::std::error::Error> {
None
}
}
#[repr(i32)] #[repr(i32)]
pub enum Format { pub enum Format {
RGB = ffi::egl::TEXTURE_RGB as i32, RGB = ffi::egl::TEXTURE_RGB as i32,
@ -40,15 +144,20 @@ impl EGLImages {
self.format.num_planes() self.format.num_planes()
} }
pub unsafe fn bind_to_tex(&self, plane: usize, tex_id: c_uint) -> Result<()> { pub unsafe fn bind_to_texture(&self, plane: usize, tex_id: c_uint) -> ::std::result::Result<(), TextureCreationError> {
if self.display.upgrade().is_some() { if self.display.upgrade().is_some() {
ffi::gl::EGLImageTargetTexture2DOES(tex_id, *self.images.get(plane).chain_err(|| ErrorKind::PlaneIndexOutOfBounds)?); let mut old_tex_id: i32 = 0;
match ffi::egl::GetError() as u32 { ffi::gl::GetIntegerv(ffi::gl::TEXTURE_BINDING_2D, &mut old_tex_id);
ffi::gl::NO_ERROR => Ok(()), ffi::gl::BindTexture(ffi::gl::TEXTURE_2D, tex_id);
err => bail!(ErrorKind::Unknown(err)), ffi::gl::EGLImageTargetTexture2DOES(ffi::gl::TEXTURE_2D, *self.images.get(plane).ok_or(TextureCreationError::PlaneIndexOutOfBounds)?);
} let res = match ffi::egl::GetError() as u32 {
ffi::egl::SUCCESS => Ok(()),
err => Err(TextureCreationError::TextureBindingFailed(err)),
};
ffi::gl::BindTexture(ffi::gl::TEXTURE_2D, old_tex_id as u32);
res
} else { } else {
bail!(ErrorKind::ContextLost) Err(TextureCreationError::ContextLost)
} }
} }
} }
@ -60,6 +169,7 @@ impl Drop for EGLImages {
unsafe { ffi::egl::DestroyImageKHR(*display, image); } unsafe { ffi::egl::DestroyImageKHR(*display, image); }
} }
} }
self.buffer.release();
} }
} }
@ -111,14 +221,17 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
Ok(()) Ok(())
} }
pub fn egl_buffer_contents<T: native::NativeSurface>(&self, buffer: WlBuffer) -> Result<EGLImages> { pub fn egl_buffer_contents(&self, buffer: WlBuffer) -> ::std::result::Result<EGLImages, BufferAccessError> {
if !self.wl_drm_support {
return Err(EglExtensionNotSupportedError(&["EGL_WL_bind_wayland_display"]).into());
}
if !self.egl_to_texture_support { if !self.egl_to_texture_support {
bail!(ErrorKind::EglExtensionNotSupported(&["GL_OES_EGL_image"])); return Err(EglExtensionNotSupportedError(&["GL_OES_EGL_image"]).into());
} }
let mut format: i32 = 0; let mut format: i32 = 0;
if unsafe { ffi::egl::QueryWaylandBufferWL(*self.display, buffer.ptr() as *mut _, ffi::egl::EGL_TEXTURE_FORMAT, &mut format as *mut _) == 0 } { if unsafe { ffi::egl::QueryWaylandBufferWL(*self.display, buffer.ptr() as *mut _, ffi::egl::EGL_TEXTURE_FORMAT, &mut format as *mut _) == 0 } {
bail!(ErrorKind::BufferNotManaged); return Err(BufferAccessError::NotManaged(buffer));
} }
let format = match format { let format = match format {
x if x == ffi::egl::TEXTURE_RGB as i32 => Format::RGB, x if x == ffi::egl::TEXTURE_RGB as i32 => Format::RGB,
@ -132,16 +245,16 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
let mut width: i32 = 0; let mut width: i32 = 0;
if unsafe { ffi::egl::QueryWaylandBufferWL(*self.display, buffer.ptr() as *mut _, ffi::egl::WIDTH as i32, &mut width as *mut _) == 0 } { if unsafe { ffi::egl::QueryWaylandBufferWL(*self.display, buffer.ptr() as *mut _, ffi::egl::WIDTH as i32, &mut width as *mut _) == 0 } {
bail!(ErrorKind::BufferNotManaged); return Err(BufferAccessError::NotManaged(buffer));
} }
let mut height: i32 = 0; let mut height: i32 = 0;
if unsafe { ffi::egl::QueryWaylandBufferWL(*self.display, buffer.ptr() as *mut _, ffi::egl::HEIGHT as i32, &mut height as *mut _) == 0 } { if unsafe { ffi::egl::QueryWaylandBufferWL(*self.display, buffer.ptr() as *mut _, ffi::egl::HEIGHT as i32, &mut height as *mut _) == 0 } {
bail!(ErrorKind::BufferNotManaged); return Err(BufferAccessError::NotManaged(buffer));
} }
let mut inverted: i32 = 0; let mut inverted: i32 = 0;
if unsafe { ffi::egl::QueryWaylandBufferWL(*self.display, buffer.ptr() as *mut _, ffi::egl::WAYLAND_Y_INVERTED_WL, &mut inverted as *mut _) == 0 } { if unsafe { ffi::egl::QueryWaylandBufferWL(*self.display, buffer.ptr() as *mut _, ffi::egl::WAYLAND_Y_INVERTED_WL, &mut inverted as *mut _) != 0 } {
inverted = 1; inverted = 1;
} }
@ -157,12 +270,12 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
unsafe { ffi::egl::CreateImageKHR( unsafe { ffi::egl::CreateImageKHR(
*self.display, *self.display,
ffi::egl::NO_CONTEXT, ffi::egl::NO_CONTEXT,
ffi::egl::WAYLAND_BUFFER_WL, ffi::egl::WAYLAND_BUFFER_WL,
buffer.ptr() as *mut _, buffer.ptr() as *mut _,
out.as_ptr(), out.as_ptr(),
) }; ) };
if image == ffi::egl::NO_IMAGE_KHR { if image == ffi::egl::NO_IMAGE_KHR {
bail!(ErrorKind::EGLImageCreationFailed); return Err(BufferAccessError::EGLImageCreationFailed);
} else { } else {
image image
} }

View File

@ -1,7 +1,7 @@
//! Implementation of backend traits for types provided by `winit` //! Implementation of backend traits for types provided by `winit`
use backend::graphics::GraphicsBackend; use backend::graphics::GraphicsBackend;
use backend::graphics::egl::{EGLGraphicsBackend, EGLContext, EGLSurface, PixelFormat, SwapBuffersError, EglExtensionNotSupportedError}; use backend::graphics::egl::{EGLGraphicsBackend, EGLContext, EGLSurface, BufferAccessError, PixelFormat, SwapBuffersError, EglExtensionNotSupportedError, EGLImages};
use backend::graphics::egl::error as egl_error; use backend::graphics::egl::error as egl_error;
use backend::graphics::egl::native; use backend::graphics::egl::native;
use backend::graphics::egl::context::{GlAttributes, PixelFormatRequirements}; use backend::graphics::egl::context::{GlAttributes, PixelFormatRequirements};
@ -18,6 +18,7 @@ use winit::{ElementState, Event, EventsLoop, KeyboardInput, MouseButton as Winit
MouseScrollDelta, Touch, TouchPhase, WindowBuilder, WindowEvent, Window as WinitWindow}; MouseScrollDelta, Touch, TouchPhase, WindowBuilder, WindowEvent, Window as WinitWindow};
use wayland_client::egl as wegl; use wayland_client::egl as wegl;
use wayland_server::Display; use wayland_server::Display;
use wayland_server::protocol::wl_buffer::WlBuffer;
error_chain! { error_chain! {
errors { errors {
@ -134,13 +135,7 @@ where
.chain_err(|| ErrorKind::InitFailed)?; .chain_err(|| ErrorKind::InitFailed)?;
debug!(log, "Window created"); debug!(log, "Window created");
let reqs = PixelFormatRequirements { let reqs = Default::default();
hardware_accelerated: Some(true),
color_bits: Some(24),
alpha_bits: Some(8),
..Default::default()
};
let window = Rc::new( let window = Rc::new(
if native::NativeDisplay::<native::Wayland>::is_backend(&winit_window) { if native::NativeDisplay::<native::Wayland>::is_backend(&winit_window) {
let context = EGLContext::<native::Wayland, WinitWindow>::new( let context = EGLContext::<native::Wayland, WinitWindow>::new(
@ -277,12 +272,12 @@ impl EGLGraphicsBackend for WinitGraphicsBackend {
Ok(()) Ok(())
} }
/* fn egl_buffer_contents(&self, buffer: WlBuffer) -> ::std::result::Result<EGLImages, BufferAccessError> {
unsafe fn egl_image_to_texture(&self, image: EGLImage, tex_id: c_uint) -> ::std::result::Result<(), EglExtensionNotSupportedError> { match *self.window {
self.window.rent(|egl| egl.head().egl_image_to_texture(image, tex_id))?; Window::Wayland { ref context, .. } => context.egl_buffer_contents(buffer),
Ok(()) Window::X11 { ref context, .. } => context.egl_buffer_contents(buffer),
}
} }
*/
} }
/// Errors that may happen when driving the event loop of `WinitInputBackend` /// Errors that may happen when driving the event loop of `WinitInputBackend`

View File

@ -72,9 +72,7 @@
//! //!
//! As you can see in the previous example, in the end we are retrieving a token from //! As you can see in the previous example, in the end we are retrieving a token from
//! the init function. This token is necessary to retrieve the metadata associated with //! the init function. This token is necessary to retrieve the metadata associated with
//! a surface. It can be cloned, and is sendable accross threads (as long as your //! a surface. It can be cloned. See `CompositorToken` for the details of what it enables you.
//! `Mydata` and `MyRoles` are `Send` too). See `CompositorToken` for
//! the details of what it enables you.
//! //!
//! The surface metadata is held in the `SurfaceAttributes` struct. In contains double-buffered //! The surface metadata is held in the `SurfaceAttributes` struct. In contains double-buffered
//! state pending from the client as defined by the protocol for `wl_surface`, as well as your //! state pending from the client as defined by the protocol for `wl_surface`, as well as your
@ -248,9 +246,6 @@ pub struct CompositorToken<U, R, ID> {
_idata: ::std::marker::PhantomData<*mut ID>, _idata: ::std::marker::PhantomData<*mut ID>,
} }
unsafe impl<U: Send, R: Send, ID> Send for CompositorToken<U, R, ID> {}
unsafe impl<U: Send, R: Send, ID> Sync for CompositorToken<U, R, ID> {}
// we implement them manually because #[derive(..)] would require // we implement them manually because #[derive(..)] would require
// U: Clone and R: Clone // U: Clone and R: Clone
impl<U, R, ID> Copy for CompositorToken<U, R, ID> {} impl<U, R, ID> Copy for CompositorToken<U, R, ID> {}
@ -270,7 +265,7 @@ impl<U, R, ID> CompositorToken<U, R, ID> {
} }
} }
impl<U: Send + 'static, R: Send + 'static, ID: 'static> CompositorToken<U, R, ID> { impl<U: 'static, R: 'static, ID: 'static> CompositorToken<U, R, ID> {
/// Access the data of a surface /// Access the data of a surface
/// ///
/// The closure will be called with the contents of the data associated with this surface. /// The closure will be called with the contents of the data associated with this surface.