Get it to work...
This commit is contained in:
parent
726991367d
commit
6c6d54064d
|
@ -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 {
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue