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::index::PrimitiveType;
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 std::borrow::Borrow;
use std::ops::Deref;
@ -108,45 +109,52 @@ impl<T: Into<GliumGraphicsBackend<T>> + EGLGraphicsBackend + 'static> From<T> fo
}
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 {
data: contents.into(),
width: surface_dimensions.0,
height: surface_dimensions.1,
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,
surface_dimensions: (u32, u32))
-> Texture2d
pub fn texture_from_egl(&self, images: &EGLImages)
-> Option<Texture2d>
{
let format = match images.format {
Format::RGB => UncompressedFloatFormat::U8U8U8,
Format::RGBA => UncompressedFloatFormat::U8U8U8U8,
_ => return None,
};
let opengl_texture = Texture2d::empty_with_format(
&self.display,
format,
MipmapsOption::NoMipmap,
surface_dimensions.0,
surface_dimensions.1,
images.width,
images.height,
).unwrap();
self.display.get_context().exec_in_context(|| {
self.display.borrow().egl_image_to_texture(image, opengl_texture.get_id());
});
opengl_texture
if let Err(_) = unsafe { self.display.get_context().exec_in_context(|| {
images.bind_to_texture(0, opengl_texture.get_id())
}) } { return None };
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),
surface_location: (i32, i32), screen_size: (u32, u32))
{
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);
if y_inverted {
yscale = -yscale;
}
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! {
matrix: [
@ -155,7 +163,7 @@ impl<F: EGLGraphicsBackend + 'static> GliumDrawer<F> {
[ 0.0 , 0.0 , 1.0, 0.0],
[ x , y , 0.0, 1.0]
],
tex: &texture,
tex: texture,
};
target
@ -164,10 +172,28 @@ impl<F: EGLGraphicsBackend + 'static> GliumDrawer<F> {
&self.index_buffer,
&self.program,
&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();
}
}
#[inline]
pub fn draw(&self) -> Frame {

View File

@ -1,78 +1,81 @@
use super::{GliumDrawer, WindowMap};
use glium::texture::{Texture2d, UncompressedFloatFormat};
use smithay::backend::graphics::egl::wayland::{Format, BufferAccessError};
use glium::texture::Texture2d;
use rand;
use smithay::backend::graphics::egl::{EGLGraphicsBackend, EGLImage};
use smithay::backend::graphics::egl::{EGLGraphicsBackend, EGLImages};
use smithay::wayland::compositor::{compositor_init, CompositorToken, SurfaceAttributes,
SurfaceUserImplementation};
use smithay::wayland::shell::{shell_init, PopupConfigure, ShellState, ShellSurfaceRole,
ShellSurfaceUserImplementation, ToplevelConfigure};
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::rc::Rc;
use std::borrow::Borrow;
use wayland_server::{EventLoop, StateToken};
define_roles!(Roles => [ ShellSurface, ShellSurfaceRole ] );
#[derive(Default)]
pub struct SurfaceData {
pub texture: Option<Texture2d>,
pub buffer: Option<Buffer>,
pub texture: Option<Texture2d>,
}
pub enum Buffer {
Egl { images: Vec<EGLImage>, attributes: Attributes },
Egl { images: EGLImages },
Shm { data: Vec<u8>, size: (u32, u32) },
}
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 {
commit: |_, drawer, surface, token| {
// we retrieve the contents of the associated buffer and copy it
token.with_surface_data(surface, |attributes| {
match attributes.buffer() {
Some(ref buffer) => {
// we ignore hotspot coordinates in this simple example (`attributes.buffer_coordinates()`)
if drm_buffer_contents(&buffer, drawer.borrow(), |attributes, images| {
let format = match attributes.format {
Format::RGB => UncompressedFloatFormat::U8U8U8,
Format::RGBA => UncompressedFloatFormat::U8U8U8U8,
_ => {
// we don't handle the more complex formats here.
attributes.user_data.buffer = None;
attributes.user_data.texture = None;
return;
},
};
attributes.user_data.texture = Some(drawer.texture_from_egl(
images[0] /*Both simple formats only have one plane*/,
format,
(attributes.width, attributes.height)
));
attributes.user_data.buffer = Some(Buffer::Egl { images, attributes });
}).is_err() {
shm_buffer_contents(&buffer, |slice, data| {
let offset = data.offset as usize;
let stride = data.stride as usize;
let width = data.width as usize;
let height = data.height as usize;
let mut new_vec = Vec::with_capacity(width * height * 4);
for i in 0..height {
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, position: (data.width as u32, data.height as u32) });
}).unwrap();
match attributes.buffer.take() {
Some(Some((buffer, (_x, _y)))) => {
// we ignore hotspot coordinates in this simple example
match <GliumDrawer<G> as Borrow<G>>::borrow(&**drawer).egl_buffer_contents(buffer) {
Ok(images) => {
let format = match images.format {
Format::RGB => {},
Format::RGBA => {},
_ => {
// we don't handle the more complex formats here.
attributes.user_data.buffer = None;
attributes.user_data.texture = None;
return;
},
};
attributes.user_data.texture = drawer.texture_from_egl(&images);
attributes.user_data.buffer = Some(Buffer::Egl { images });
},
Err(BufferAccessError::NotManaged(buffer)) => {
shm_buffer_contents(&buffer, |slice, data| {
let offset = data.offset as usize;
let stride = data.stride as usize;
let width = data.width as usize;
let height = data.height as usize;
let mut new_vec = Vec::with_capacity(width * height * 4);
for i in 0..height {
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) });
}).unwrap();
buffer.release();
},
Err(err) => panic!("EGL error: {}", err),
}
}
None => {
Some(None) => {
// erase the contents
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 token: CompositorToken<SurfaceData, Roles, ()>,
pub window_map: Rc<RefCell<super::WindowMap<SurfaceData, Roles, (), (), F>>>,
pub struct ShellIData<F, G: EGLGraphicsBackend + 'static> {
pub token: CompositorToken<SurfaceData, Roles, Rc<GliumDrawer<G>>>,
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
F: Fn(&SurfaceAttributes<SurfaceData>) -> Option<(i32, i32)>,
G: EGLGraphicsBackend + 'static,
{
ShellSurfaceUserImplementation {
new_client: |_, _, _| {},
@ -134,23 +138,27 @@ fn get_size(attrs: &SurfaceAttributes<SurfaceData>) -> Option<(i32, i32)> {
.user_data
.buffer
.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,
Roles,
(),
Rc<GliumDrawer<G>>,
(),
fn(&SurfaceAttributes<SurfaceData>) -> Option<(i32, i32)>,
>;
pub fn init_shell<ID: 'static>(
evl: &mut EventLoop, log: ::slog::Logger, data: ID)
pub fn init_shell<G: EGLGraphicsBackend + 'static>(
evl: &mut EventLoop, log: ::slog::Logger, data: Rc<GliumDrawer<G>>)
-> (
CompositorToken<SurfaceData, Roles, ID>,
StateToken<ShellState<SurfaceData, Roles, ID, ()>>,
Rc<RefCell<MyWindowMap>>,
CompositorToken<SurfaceData, Roles, Rc<GliumDrawer<G>>>,
StateToken<ShellState<SurfaceData, Roles, Rc<GliumDrawer<G>>, ()>>,
Rc<RefCell<MyWindowMap<G>>>,
) {
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 wayland_server::protocol::{wl_output, wl_pointer};
struct WinitInputHandler {
struct WinitInputHandler<G: EGLGraphicsBackend + 'static> {
log: Logger,
pointer: PointerHandle,
keyboard: KeyboardHandle,
window_map: Rc<RefCell<MyWindowMap>>,
window_map: Rc<RefCell<MyWindowMap<G>>>,
pointer_location: (f64, f64),
serial: u32,
}
impl WinitInputHandler {
impl<G: EGLGraphicsBackend + 'static> WinitInputHandler<G> {
fn next_serial(&mut self) -> u32 {
self.serial += 1;
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) {
/* never happens with winit */
}
@ -140,6 +140,7 @@ fn main() {
info!(log, "EGL hardware-acceleration enabled");
}
let (w, h) = renderer.get_framebuffer_dimensions();
let drawer = Rc::new(GliumDrawer::from(renderer));
/*
@ -172,7 +173,6 @@ fn main() {
log.clone(),
);
let (w, h) = renderer.get_framebuffer_dimensions();
event_loop
.state()
.get_mut(&output_token)
@ -194,10 +194,6 @@ fn main() {
refresh: 60_000,
});
/*
* Initialize glium
*/
input.set_handler(WinitInputHandler {
log: log.clone(),
pointer,
@ -217,7 +213,7 @@ fn main() {
input.dispatch_new_events().unwrap();
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
{
let screen_dimensions = drawer.get_framebuffer_dimensions();
@ -232,7 +228,7 @@ fn main() {
initial_place,
|_surface, attributes, role, &(mut x, mut y)| {
// 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) {
x += subdata.x;
y += subdata.y;
@ -241,11 +237,11 @@ fn main() {
&mut frame,
texture,
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,
},
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,
},
(x, y),

View File

@ -132,6 +132,12 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
};
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| {
let name = CString::new(sym).unwrap();
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(),
}
});
ffi::gl::load_with(|sym| {
let name = CString::new(sym).unwrap();
let symbol = ffi::egl::LIB.get::<*mut c_void>(name.as_bytes());
match symbol {
Ok(x) => *x as *const _,
Err(_) => ptr::null(),
}
let procAddress = constrain(|sym| {
let addr = CString::new(sym).unwrap();
let addr = addr.as_ptr();
ffi::egl::GetProcAddress(addr) as *const _
});
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
@ -434,6 +442,23 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
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((
Rc::new(context as *const _),
Rc::new(display as *const _),
@ -441,7 +466,7 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
surface_attributes,
desc,
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.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PixelFormatRequirements {
/// If `true`, only hardware-accelerated formats will be conisdered. If `false`, only software renderers.
/// `None` means "don't care". Default is `None`.
@ -557,3 +582,19 @@ pub struct PixelFormatRequirements {
/// The default is `false`.
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")
}
#[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"]
EglExtensionNotSupported(extensions: &'static [&'static str]) {
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")
}
#[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"]
EGLImageCreationFailed {
description("Failed to create EGLImages from the buffer")

View File

@ -9,8 +9,8 @@ use super::GraphicsBackend;
use nix::libc::c_void;
use std::fmt;
use wayland_server::Display;
use wayland_server::protocol::wl_buffer::WlBuffer;
pub use self::ffi::egl::types::EGLImage;
pub mod context;
pub use self::context::EGLContext;
pub mod error;
@ -20,6 +20,7 @@ pub mod native;
pub mod surface;
pub use self::surface::EGLSurface;
pub mod wayland;
pub use self::wayland::{EGLImages, BufferAccessError};
/// Error that can happen when swapping buffers.
#[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.
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::ffi::egl::types::EGLImage;
use nix::libc::{c_uint};
use std::rc::{Rc, Weak};
use std::fmt;
use wayland_server::{Display, Resource};
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)]
pub enum Format {
RGB = ffi::egl::TEXTURE_RGB as i32,
@ -40,15 +144,20 @@ impl EGLImages {
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() {
ffi::gl::EGLImageTargetTexture2DOES(tex_id, *self.images.get(plane).chain_err(|| ErrorKind::PlaneIndexOutOfBounds)?);
match ffi::egl::GetError() as u32 {
ffi::gl::NO_ERROR => Ok(()),
err => bail!(ErrorKind::Unknown(err)),
}
let mut old_tex_id: i32 = 0;
ffi::gl::GetIntegerv(ffi::gl::TEXTURE_BINDING_2D, &mut old_tex_id);
ffi::gl::BindTexture(ffi::gl::TEXTURE_2D, tex_id);
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 {
bail!(ErrorKind::ContextLost)
Err(TextureCreationError::ContextLost)
}
}
}
@ -60,6 +169,7 @@ impl Drop for EGLImages {
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(())
}
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 {
bail!(ErrorKind::EglExtensionNotSupported(&["GL_OES_EGL_image"]));
return Err(EglExtensionNotSupportedError(&["GL_OES_EGL_image"]).into());
}
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 } {
bail!(ErrorKind::BufferNotManaged);
return Err(BufferAccessError::NotManaged(buffer));
}
let format = match format {
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;
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;
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;
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;
}
@ -157,12 +270,12 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
unsafe { ffi::egl::CreateImageKHR(
*self.display,
ffi::egl::NO_CONTEXT,
ffi::egl::WAYLAND_BUFFER_WL,
ffi::egl::WAYLAND_BUFFER_WL,
buffer.ptr() as *mut _,
out.as_ptr(),
) };
if image == ffi::egl::NO_IMAGE_KHR {
bail!(ErrorKind::EGLImageCreationFailed);
return Err(BufferAccessError::EGLImageCreationFailed);
} else {
image
}

View File

@ -1,7 +1,7 @@
//! Implementation of backend traits for types provided by `winit`
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::native;
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};
use wayland_client::egl as wegl;
use wayland_server::Display;
use wayland_server::protocol::wl_buffer::WlBuffer;
error_chain! {
errors {
@ -134,13 +135,7 @@ where
.chain_err(|| ErrorKind::InitFailed)?;
debug!(log, "Window created");
let reqs = PixelFormatRequirements {
hardware_accelerated: Some(true),
color_bits: Some(24),
alpha_bits: Some(8),
..Default::default()
};
let reqs = Default::default();
let window = Rc::new(
if native::NativeDisplay::<native::Wayland>::is_backend(&winit_window) {
let context = EGLContext::<native::Wayland, WinitWindow>::new(
@ -277,12 +272,12 @@ impl EGLGraphicsBackend for WinitGraphicsBackend {
Ok(())
}
/*
unsafe fn egl_image_to_texture(&self, image: EGLImage, tex_id: c_uint) -> ::std::result::Result<(), EglExtensionNotSupportedError> {
self.window.rent(|egl| egl.head().egl_image_to_texture(image, tex_id))?;
Ok(())
fn egl_buffer_contents(&self, buffer: WlBuffer) -> ::std::result::Result<EGLImages, BufferAccessError> {
match *self.window {
Window::Wayland { ref context, .. } => context.egl_buffer_contents(buffer),
Window::X11 { ref context, .. } => context.egl_buffer_contents(buffer),
}
}
*/
}
/// 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
//! 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
//! `Mydata` and `MyRoles` are `Send` too). See `CompositorToken` for
//! the details of what it enables you.
//! a surface. It can be cloned. See `CompositorToken` for the details of what it enables you.
//!
//! 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
@ -248,9 +246,6 @@ pub struct CompositorToken<U, R, 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
// U: Clone and R: Clone
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
///
/// The closure will be called with the contents of the data associated with this surface.