Start EGL wl_buffer image retrieval
This commit is contained in:
parent
14fc36bf54
commit
5c846d550c
12
build.rs
12
build.rs
|
@ -33,4 +33,16 @@ fn main() {
|
|||
],
|
||||
).write_bindings(gl_generator::GlobalGenerator, &mut file)
|
||||
.unwrap();
|
||||
|
||||
let mut file = File::create(&dest.join("gl_bindings.rs")).unwrap();
|
||||
Registry::new(
|
||||
Api::Gles2,
|
||||
(3, 2),
|
||||
Profile::Compatibility,
|
||||
Fallbacks::None,
|
||||
[
|
||||
"GL_OES_EGL_image",
|
||||
],
|
||||
).write_bindings(gl_generator::GlobalGenerator, &mut file)
|
||||
.unwrap();
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ impl<T: Into<GliumGraphicsBackend<T>> + EGLGraphicsBackend + 'static> From<T> fo
|
|||
}
|
||||
|
||||
impl<F: EGLGraphicsBackend + 'static> GliumDrawer<F> {
|
||||
pub fn render(&self, target: &mut glium::Frame, contents: &[u8], surface_dimensions: (u32, u32),
|
||||
pub fn render_shm(&self, target: &mut glium::Frame, contents: &[u8], surface_dimensions: (u32, u32),
|
||||
surface_location: (i32, i32), screen_size: (u32, u32)) {
|
||||
let image = glium::texture::RawImage2d {
|
||||
data: contents.into(),
|
||||
|
@ -143,6 +143,51 @@ impl<F: EGLGraphicsBackend + 'static> GliumDrawer<F> {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
pub fn render_egl(&self, target: &mut glium::Frame, images: Vec<EGLImage>,
|
||||
format: UncompressedFloatFormat, y_inverted: bool, surface_dimensions: (u32, u32),
|
||||
surface_location: (i32, i32), screen_size: (u32, u32))
|
||||
{
|
||||
let opengl_texture = glium::texture::Texture2d::empty_with_format(
|
||||
&self.display,
|
||||
MipmapsOption::NoMipmap,
|
||||
format,
|
||||
surface_dimensions.0,
|
||||
surface_dimensions.1,
|
||||
).unwrap();
|
||||
self.display.exec_in_context(|| {
|
||||
self.display.borrow().egl_image_to_texture(images[0], opengl_texture.get_id());
|
||||
});
|
||||
|
||||
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 uniforms = uniform! {
|
||||
matrix: [
|
||||
[xscale, 0.0 , 0.0, 0.0],
|
||||
[ 0.0 , yscale , 0.0, 0.0],
|
||||
[ 0.0 , 0.0 , 1.0, 0.0],
|
||||
[ x , y , 0.0, 1.0]
|
||||
],
|
||||
tex: &opengl_texture
|
||||
};
|
||||
|
||||
target
|
||||
.draw(
|
||||
&self.vertex_buffer,
|
||||
&self.index_buffer,
|
||||
&self.program,
|
||||
&uniforms,
|
||||
&Default::default(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn draw(&self) -> Frame {
|
||||
self.display.draw()
|
||||
|
|
|
@ -4,7 +4,8 @@ use smithay::wayland::compositor::{compositor_init, CompositorToken, SurfaceAttr
|
|||
SurfaceUserImplementation};
|
||||
use smithay::wayland::shell::{shell_init, PopupConfigure, ShellState, ShellSurfaceRole,
|
||||
ShellSurfaceUserImplementation, ToplevelConfigure};
|
||||
use smithay::wayland::shm::with_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, EGLImage};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use wayland_server::{EventLoop, StateToken};
|
||||
|
@ -16,6 +17,11 @@ pub struct SurfaceData {
|
|||
pub buffer: Option<(Vec<u8>, (u32, u32))>,
|
||||
}
|
||||
|
||||
pub enum Buffer {
|
||||
Egl { images: Vec<EGLImage>, attributes: Attributes },
|
||||
Shm { data: Vec<u8>, size: (u32, u32) },
|
||||
}
|
||||
|
||||
pub fn surface_implementation() -> SurfaceUserImplementation<SurfaceData, Roles, ()> {
|
||||
SurfaceUserImplementation {
|
||||
commit: |_, _, surface, token| {
|
||||
|
@ -24,19 +30,23 @@ pub fn surface_implementation() -> SurfaceUserImplementation<SurfaceData, Roles,
|
|||
match attributes.buffer.take() {
|
||||
Some(Some((buffer, (_x, _y)))) => {
|
||||
// we ignore hotspot coordinates in this simple example
|
||||
with_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.buffer =
|
||||
Some((new_vec, (data.width as u32, data.height as u32)));
|
||||
}).unwrap();
|
||||
if let Ok(_) = drm_buffer_contents(&buffer, |attributes, images| {
|
||||
attributes.user_data.buffer = Some(Buffer::Egl { images, attributes });
|
||||
}) {} else {
|
||||
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.buffer =
|
||||
Some(Buffer::Shm { data: new_vec, position: (data.width as u32, data.height as u32) });
|
||||
}).unwrap();
|
||||
}
|
||||
buffer.release();
|
||||
}
|
||||
Some(None) => {
|
||||
|
|
|
@ -12,7 +12,8 @@ extern crate wayland_server;
|
|||
mod helpers;
|
||||
|
||||
use glium::Surface;
|
||||
use helpers::{init_shell, GliumDrawer, MyWindowMap};
|
||||
use glium::texture::UncompressedFloatFormat;
|
||||
use helpers::{init_shell, GliumDrawer, MyWindowMap, Buffer};
|
||||
use slog::{Drain, Logger};
|
||||
use smithay::backend::graphics::egl::EGLGraphicsBackend;
|
||||
use smithay::backend::input::{self, Event, InputBackend, InputHandler, KeyboardKeyEvent, PointerAxisEvent,
|
||||
|
@ -226,15 +227,35 @@ fn main() {
|
|||
wl_surface,
|
||||
initial_place,
|
||||
|_surface, attributes, role, &(mut x, mut y)| {
|
||||
if let Some((ref contents, (w, h))) = attributes.user_data.buffer {
|
||||
if let Some(Buffer::Egl { images, attributes }) = attributes.user_data.buffer {
|
||||
// there is actually something to draw !
|
||||
if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
|
||||
x += subdata.x;
|
||||
y += subdata.y;
|
||||
}
|
||||
drawer.render(
|
||||
drawer.render_egl(
|
||||
&mut frame,
|
||||
contents,
|
||||
images,
|
||||
format: match attributes.format {
|
||||
Format::RGB => UncompressedFloatFormat::U8U8U8,
|
||||
Format::RGBA => UncompressedFloatFormat::U8U8U8U8,
|
||||
_ => unimplemented!(),
|
||||
},
|
||||
attributes.y_inverted,
|
||||
(attributes.width, attributes.height),
|
||||
(x, y),
|
||||
screen_dimensions,
|
||||
);
|
||||
TraversalAction::DoChildren((x, y))
|
||||
} else if let Some(Buffer::Shm { data, size: (w, h))) = attributes.user_data.buffer {
|
||||
// there is actually something to draw !
|
||||
if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
|
||||
x += subdata.x;
|
||||
y += subdata.y;
|
||||
}
|
||||
drawer.render_shm(
|
||||
&mut frame,
|
||||
data,
|
||||
(w, h),
|
||||
(x, y),
|
||||
screen_dimensions,
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
use super::GraphicsBackend;
|
||||
#[cfg(feature = "backend_drm")]
|
||||
use gbm::{AsRaw, Device as GbmDevice, Surface as GbmSurface};
|
||||
use nix::libc::{c_int, c_void};
|
||||
use nix::libc::{c_int, c_uint, c_void};
|
||||
use rental::TryNewError;
|
||||
use slog;
|
||||
use std::error;
|
||||
|
@ -27,7 +27,7 @@ use winit::os::unix::WindowExt;
|
|||
use wayland_server::Display;
|
||||
|
||||
#[allow(non_camel_case_types, dead_code, unused_mut)]
|
||||
mod ffi {
|
||||
pub(crate) mod ffi {
|
||||
use nix::libc::{c_long, c_void, int32_t, uint64_t};
|
||||
|
||||
pub type khronos_utime_nanoseconds_t = khronos_uint64_t;
|
||||
|
@ -41,6 +41,10 @@ mod ffi {
|
|||
pub type NativePixmapType = *const c_void;
|
||||
pub type NativeWindowType = *const c_void;
|
||||
|
||||
pub mod gl {
|
||||
include!(concat!(env!("OUT_DIR"), "/egl_bindings.rs"));
|
||||
}
|
||||
|
||||
pub mod egl {
|
||||
use super::*;
|
||||
use libloading::Library;
|
||||
|
@ -358,12 +362,12 @@ unsafe impl NativeSurface for () {
|
|||
/// EGL context for rendering
|
||||
pub struct EGLContext<'a, T: NativeSurface> {
|
||||
context: ffi::egl::types::EGLContext,
|
||||
display: ffi::egl::types::EGLDisplay,
|
||||
pub(crate) display: ffi::egl::types::EGLDisplay,
|
||||
config_id: ffi::egl::types::EGLConfig,
|
||||
surface_attributes: Vec<c_int>,
|
||||
pixel_format: PixelFormat,
|
||||
backend_type: NativeType,
|
||||
wl_drm_support: bool,
|
||||
pub(crate) wl_drm_support: bool,
|
||||
logger: slog::Logger,
|
||||
_lifetime: PhantomData<&'a ()>,
|
||||
_type: PhantomData<T>,
|
||||
|
@ -472,6 +476,14 @@ impl<'a, T: NativeSurface> EGLContext<'a, T> {
|
|||
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(),
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// the first step is to query the list of extensions without any display, if supported
|
||||
|
@ -947,6 +959,10 @@ impl<'a, T: NativeSurface> EGLContext<'a, T> {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn egl_image_to_texture(&self, image: ffi::EGLImage, tex_id: c_uint) {
|
||||
ffi::gl::EGLImageTargetTexture2DOES(tex_id, image);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<'a, T: NativeSurface> Send for EGLContext<'a, T> {}
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
use ::backend::graphics::egl::ffi;
|
||||
use ::backend::graphics::egl::EGLContext;
|
||||
pub use ::backend::graphics::egl::ffi::EGLImage;
|
||||
use nix::libc::c_int;
|
||||
use wayland_server::protocol::wl_buffer::WlBuffer;
|
||||
|
||||
/// Error that can occur when accessing an EGL buffer
|
||||
#[derive(Debug)]
|
||||
pub enum BufferAccessError {
|
||||
/// This buffer is not managed by EGL
|
||||
NotManaged,
|
||||
/// Failed to create EGLImages from the buffer
|
||||
FailedToCreateEGLImage,
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
pub enum Format {
|
||||
RGB = ffi::TEXTURE_RGB,
|
||||
RGBA = ffi::TEXTURE_RGBA,
|
||||
External = ffi::TEXTURE_EXTERNAL_WL,
|
||||
Y_UV = ffi::TEXTURE_Y_UV_WL,
|
||||
Y_U_V = ffi::TEXTURE_Y_U_V_WL,
|
||||
Y_XUXV = ffi::TEXTURE_Y_XUXV_WL,
|
||||
}
|
||||
|
||||
impl Format {
|
||||
pub fn num_planes(&self) -> u32 {
|
||||
match *self {
|
||||
Format::RGB | Format::RGBA | Format::External => 1,
|
||||
Format::Y_UV | Format::Y_XUXV => 2,
|
||||
Format::Y_U_V => 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Attributes {
|
||||
width: u32,
|
||||
height: u32,
|
||||
y_inverted: bool,
|
||||
format: Format,
|
||||
}
|
||||
|
||||
pub fn with_buffer_contents<F>(buffer: &WlBuffer, context: &EGLContext, f: F) -> Result<(), BufferAccessError>
|
||||
where
|
||||
F: FnOnce(Attributes, Vec<EGLImage>)
|
||||
{
|
||||
let mut format: u32 = 0;
|
||||
if context.egl.QueryWaylandBufferWL(context.display, buffer.ptr(), ffi::egl::TEXTURE_FORMAT, &mut format as *mut _) == 0 {
|
||||
return Err(BufferAccessError::NotManaged);
|
||||
}
|
||||
|
||||
let mut width: u32 = 0;
|
||||
if context.egl.QueryWaylandBufferWL(context.display, buffer.ptr(), ffi::egl::WIDTH, &mut width as *mut _) == 0 {
|
||||
return Err(BufferAccessError::NotManaged);
|
||||
}
|
||||
|
||||
let mut height: u32 = 0;
|
||||
if context.egl.QueryWaylandBufferWL(context.display, buffer.ptr(), ffi::egl::HEIGHT, &mut height as *mut _) == 0 {
|
||||
return Err(BufferAccessError::NotManaged);
|
||||
}
|
||||
|
||||
let mut inverted: u32 = 0;
|
||||
if context.egl.QueryWaylandBufferWL(context.display, buffer.ptr(), ffi::egl::WAYLAND_Y_INVERTED_WL, &mut inverted as *mut _) == 0 {
|
||||
inverted = 1;
|
||||
}
|
||||
|
||||
let attributes = Attributes {
|
||||
width,
|
||||
height,
|
||||
y_inverted = inverted != 0,
|
||||
format: format as Format,
|
||||
};
|
||||
|
||||
let mut images = Vec::with_capacity(attributes.format.num_planes());
|
||||
for _ in 0..attributes.format.num_planes() {
|
||||
let mut out = Vec::with_capacity(3);
|
||||
out.push(ffi::egl::WAYLAND_PLANE_WL as i32);
|
||||
out.push(i as i32);
|
||||
out.push(ffi::egl::NONE as i32);
|
||||
|
||||
images.push({
|
||||
let image =
|
||||
ffi::egl::CreateImageKHR(
|
||||
context.display,
|
||||
ffi::egl::NO_CONTEXT,
|
||||
ffi::egl::WAYLAND_BUFFER_WL,
|
||||
buffer.ptr(),
|
||||
out.as_ptr(),
|
||||
);
|
||||
if image == ffi::egl::NO_IMAGE_KHR {
|
||||
return Err(BufferAccessError::FailedToCreateEGLImage);
|
||||
} else {
|
||||
image
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
f(attributes, images)
|
||||
}
|
Loading…
Reference in New Issue