Rework egl image api
This commit is contained in:
parent
5d7e96103d
commit
726991367d
|
@ -18,7 +18,6 @@ use std::mem;
|
|||
use std::ops::{Deref, DerefMut};
|
||||
#[cfg(feature = "backend_drm")]
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
use wayland_server::Display;
|
||||
|
||||
/// EGL context for rendering
|
||||
pub struct EGLContext<B: native::Backend, N: native::NativeDisplay<B>> {
|
||||
|
@ -28,8 +27,8 @@ pub struct EGLContext<B: native::Backend, N: native::NativeDisplay<B>> {
|
|||
pub(crate) config_id: ffi::egl::types::EGLConfig,
|
||||
pub(crate) surface_attributes: Vec<c_int>,
|
||||
pixel_format: PixelFormat,
|
||||
wl_drm_support: bool,
|
||||
egl_to_texture_support: bool,
|
||||
pub(crate) wl_drm_support: bool,
|
||||
pub(crate) egl_to_texture_support: bool,
|
||||
logger: slog::Logger,
|
||||
_backend: PhantomData<B>,
|
||||
}
|
||||
|
@ -474,68 +473,6 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
|||
pub fn get_pixel_format(&self) -> PixelFormat {
|
||||
self.pixel_format
|
||||
}
|
||||
|
||||
/// Binds this EGL context to the given Wayland display.
|
||||
///
|
||||
/// This will allow clients to utilize EGL to create hardware-accelerated
|
||||
/// surfaces. The server will need to be able to handle egl-wl_buffers.
|
||||
/// See the `wayland::drm` module.
|
||||
///
|
||||
/// ## Errors
|
||||
///
|
||||
/// This might return `WlExtensionNotSupported` if binding is not supported
|
||||
/// by the EGL implementation.
|
||||
///
|
||||
/// This might return `OtherEGLDisplayAlreadyBound` if called for the same
|
||||
/// `Display` multiple times, as only one context may be bound at any given time.
|
||||
pub fn bind_wl_display(&self, display: &Display) -> Result<()> {
|
||||
if !self.wl_drm_support {
|
||||
bail!(ErrorKind::EglExtensionNotSupported(&["EGL_WL_bind_wayland_display"]));
|
||||
}
|
||||
let res = unsafe { ffi::egl::BindWaylandDisplayWL(*self.display, display.ptr() as *mut _) };
|
||||
if res == 0 {
|
||||
bail!(ErrorKind::OtherEGLDisplayAlreadyBound);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Unbinds this EGL context from the given Wayland display.
|
||||
///
|
||||
/// This will stop clients from using previously available extensions
|
||||
/// to utilize hardware-accelerated surface via EGL.
|
||||
///
|
||||
/// ## Errors
|
||||
///
|
||||
/// This might return `WlExtensionNotSupported` if binding is not supported
|
||||
/// by the EGL implementation.
|
||||
///
|
||||
/// This might return `OtherEGLDisplayAlreadyBound` if called for the same
|
||||
/// `Display` multiple times, as only one context may be bound at any given time.
|
||||
pub fn unbind_wl_display(&self, display: &Display) -> Result<()> {
|
||||
if !self.wl_drm_support {
|
||||
bail!(ErrorKind::EglExtensionNotSupported(&["EGL_WL_bind_wayland_display"]));
|
||||
}
|
||||
let res = unsafe { ffi::egl::UnbindWaylandDisplayWL(*self.display, display.ptr() as *mut _) };
|
||||
if res == 0 {
|
||||
bail!(ErrorKind::NoEGLDisplayBound);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/*
|
||||
pub unsafe fn egl_image_to_texture(&self, image: ffi::egl::types::EGLImage, tex_id: c_uint) -> Result<()> {
|
||||
if !self.egl_to_texture_support {
|
||||
bail!(ErrorKind::EglExtensionNotSupported(&["EGL_OES_image", "EGL_OES_image_base"]));
|
||||
}
|
||||
ffi::gl::EGLImageTargetTexture2DOES(tex_id, image);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub unsafe fn destroy_egl_image(&self, image: ffi::egl::types::EGLImage, tex_id: c_uint) -> Result<()> {
|
||||
ffi::gl::DestroyImageKHR(self.display, image);
|
||||
Ok(())
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
unsafe impl<B: native::Backend, N: native::NativeDisplay<B> + Send> Send for EGLContext<B, N> {}
|
||||
|
|
|
@ -47,6 +47,11 @@ 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"),
|
||||
|
@ -64,6 +69,21 @@ error_chain! {
|
|||
description("No EGLDisplay is currently bound to this WlDisplay")
|
||||
}
|
||||
|
||||
#[doc = "Index of plane is out of bounds for EGLImages"]
|
||||
PlaneIndexOutOfBounds {
|
||||
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")
|
||||
}
|
||||
|
||||
#[doc = "The reason of failure could not be determined"]
|
||||
Unknown(err_no: u32)
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ pub mod ffi;
|
|||
pub mod native;
|
||||
pub mod surface;
|
||||
pub use self::surface::EGLSurface;
|
||||
pub mod wayland;
|
||||
|
||||
/// Error that can happen when swapping buffers.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
@ -166,6 +167,7 @@ pub trait EGLGraphicsBackend: GraphicsBackend {
|
|||
/// This might return `OtherEGLDisplayAlreadyBound` if called for the same
|
||||
/// `Display` multiple times, as only one context may be bound at any given time.
|
||||
fn bind_wl_display(&self, display: &Display) -> ::std::result::Result<(), EglExtensionNotSupportedError>;
|
||||
|
||||
/// Unbinds this EGL context from the given Wayland display.
|
||||
///
|
||||
/// This will stop clients from using previously available extensions
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
use backend::graphics::egl::{EGLContext, EGLImage, ffi, native};
|
||||
use backend::graphics::egl::error::*;
|
||||
use nix::libc::{c_uint};
|
||||
use std::rc::{Rc, Weak};
|
||||
use wayland_server::{Display, Resource};
|
||||
use wayland_server::protocol::wl_buffer::WlBuffer;
|
||||
|
||||
#[repr(i32)]
|
||||
pub enum Format {
|
||||
RGB = ffi::egl::TEXTURE_RGB as i32,
|
||||
RGBA = ffi::egl::TEXTURE_RGBA as i32,
|
||||
External = ffi::egl::TEXTURE_EXTERNAL_WL,
|
||||
Y_UV = ffi::egl::TEXTURE_Y_UV_WL,
|
||||
Y_U_V = ffi::egl::TEXTURE_Y_U_V_WL,
|
||||
Y_XUXV = ffi::egl::TEXTURE_Y_XUXV_WL,
|
||||
}
|
||||
|
||||
impl Format {
|
||||
pub fn num_planes(&self) -> usize {
|
||||
match *self {
|
||||
Format::RGB | Format::RGBA | Format::External => 1,
|
||||
Format::Y_UV | Format::Y_XUXV => 2,
|
||||
Format::Y_U_V => 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EGLImages {
|
||||
display: Weak<ffi::egl::types::EGLDisplay>,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub y_inverted: bool,
|
||||
pub format: Format,
|
||||
images: Vec<EGLImage>,
|
||||
buffer: WlBuffer,
|
||||
}
|
||||
|
||||
impl EGLImages {
|
||||
pub fn num_planes(&self) -> usize {
|
||||
self.format.num_planes()
|
||||
}
|
||||
|
||||
pub unsafe fn bind_to_tex(&self, plane: usize, tex_id: c_uint) -> Result<()> {
|
||||
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)),
|
||||
}
|
||||
} else {
|
||||
bail!(ErrorKind::ContextLost)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for EGLImages {
|
||||
fn drop(&mut self) {
|
||||
if let Some(display) = self.display.upgrade() {
|
||||
for image in self.images.drain(..) {
|
||||
unsafe { ffi::egl::DestroyImageKHR(*display, image); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||
/// Binds this EGL context to the given Wayland display.
|
||||
///
|
||||
/// This will allow clients to utilize EGL to create hardware-accelerated
|
||||
/// surfaces. The server will need to be able to handle egl-wl_buffers.
|
||||
/// See the `wayland::drm` module.
|
||||
///
|
||||
/// ## Errors
|
||||
///
|
||||
/// This might return `WlExtensionNotSupported` if binding is not supported
|
||||
/// by the EGL implementation.
|
||||
///
|
||||
/// This might return `OtherEGLDisplayAlreadyBound` if called for the same
|
||||
/// `Display` multiple times, as only one context may be bound at any given time.
|
||||
pub fn bind_wl_display(&self, display: &Display) -> Result<()> {
|
||||
if !self.wl_drm_support {
|
||||
bail!(ErrorKind::EglExtensionNotSupported(&["EGL_WL_bind_wayland_display"]));
|
||||
}
|
||||
let res = unsafe { ffi::egl::BindWaylandDisplayWL(*self.display, display.ptr() as *mut _) };
|
||||
if res == 0 {
|
||||
bail!(ErrorKind::OtherEGLDisplayAlreadyBound);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Unbinds this EGL context from the given Wayland display.
|
||||
///
|
||||
/// This will stop clients from using previously available extensions
|
||||
/// to utilize hardware-accelerated surface via EGL.
|
||||
///
|
||||
/// ## Errors
|
||||
///
|
||||
/// This might return `WlExtensionNotSupported` if binding is not supported
|
||||
/// by the EGL implementation.
|
||||
///
|
||||
/// This might return `OtherEGLDisplayAlreadyBound` if called for the same
|
||||
/// `Display` multiple times, as only one context may be bound at any given time.
|
||||
pub fn unbind_wl_display(&self, display: &Display) -> Result<()> {
|
||||
if !self.wl_drm_support {
|
||||
bail!(ErrorKind::EglExtensionNotSupported(&["EGL_WL_bind_wayland_display"]));
|
||||
}
|
||||
let res = unsafe { ffi::egl::UnbindWaylandDisplayWL(*self.display, display.ptr() as *mut _) };
|
||||
if res == 0 {
|
||||
bail!(ErrorKind::NoEGLDisplayBound);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn egl_buffer_contents<T: native::NativeSurface>(&self, buffer: WlBuffer) -> Result<EGLImages> {
|
||||
if !self.egl_to_texture_support {
|
||||
bail!(ErrorKind::EglExtensionNotSupported(&["GL_OES_EGL_image"]));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
let format = match format {
|
||||
x if x == ffi::egl::TEXTURE_RGB as i32 => Format::RGB,
|
||||
x if x == ffi::egl::TEXTURE_RGBA as i32 => Format::RGBA,
|
||||
ffi::egl::TEXTURE_EXTERNAL_WL => Format::External,
|
||||
ffi::egl::TEXTURE_Y_UV_WL => Format::Y_UV,
|
||||
ffi::egl::TEXTURE_Y_U_V_WL => Format::Y_U_V,
|
||||
ffi::egl::TEXTURE_Y_XUXV_WL => Format::Y_XUXV,
|
||||
_ => panic!("EGL returned invalid texture type"),
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 } {
|
||||
inverted = 1;
|
||||
}
|
||||
|
||||
let mut images = Vec::with_capacity(format.num_planes());
|
||||
for i in 0..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 =
|
||||
unsafe { ffi::egl::CreateImageKHR(
|
||||
*self.display,
|
||||
ffi::egl::NO_CONTEXT,
|
||||
ffi::egl::WAYLAND_BUFFER_WL,
|
||||
buffer.ptr() as *mut _,
|
||||
out.as_ptr(),
|
||||
) };
|
||||
if image == ffi::egl::NO_IMAGE_KHR {
|
||||
bail!(ErrorKind::EGLImageCreationFailed);
|
||||
} else {
|
||||
image
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Ok(EGLImages {
|
||||
display: Rc::downgrade(&self.display),
|
||||
width: width as u32,
|
||||
height: height as u32,
|
||||
y_inverted: inverted != 0,
|
||||
format,
|
||||
images,
|
||||
buffer,
|
||||
})
|
||||
}
|
||||
}
|
|
@ -87,7 +87,7 @@ impl<
|
|||
.into_iter()
|
||||
// Create devices
|
||||
.flat_map(|path| {
|
||||
match unsafe { DrmDevice::new(
|
||||
match DrmDevice::new(
|
||||
{
|
||||
match session.open(&path, fcntl::O_RDWR | fcntl::O_CLOEXEC | fcntl::O_NOCTTY | fcntl::O_NONBLOCK) {
|
||||
Ok(fd) => SessionFdDrmDevice(fd),
|
||||
|
@ -97,7 +97,7 @@ impl<
|
|||
}
|
||||
}
|
||||
}, logger.clone()
|
||||
) } {
|
||||
) {
|
||||
// Call the handler, which might add it to the runloop
|
||||
Ok(mut device) => match handler.device_added(&mut evlh.state().as_proxy(), &mut device) {
|
||||
// fstat them
|
||||
|
@ -253,25 +253,23 @@ where
|
|||
info!(evlh.state().get(token).logger, "Device Added");
|
||||
if let (Some(path), Some(devnum)) = (event.devnode(), event.devnum()) {
|
||||
let mut device = {
|
||||
match unsafe {
|
||||
DrmDevice::new(
|
||||
{
|
||||
let logger = evlh.state().get(token).logger.clone();
|
||||
match evlh.state().get_mut(token).session.open(
|
||||
path,
|
||||
fcntl::O_RDWR | fcntl::O_CLOEXEC | fcntl::O_NOCTTY
|
||||
| fcntl::O_NONBLOCK,
|
||||
) {
|
||||
Ok(fd) => SessionFdDrmDevice(fd),
|
||||
Err(err) => {
|
||||
warn!(logger, "Unable to open drm device {:?}, Error: {:?}. Skipping", path, err);
|
||||
continue;
|
||||
}
|
||||
match DrmDevice::new(
|
||||
{
|
||||
let logger = evlh.state().get(token).logger.clone();
|
||||
match evlh.state().get_mut(token).session.open(
|
||||
path,
|
||||
fcntl::O_RDWR | fcntl::O_CLOEXEC | fcntl::O_NOCTTY
|
||||
| fcntl::O_NONBLOCK,
|
||||
) {
|
||||
Ok(fd) => SessionFdDrmDevice(fd),
|
||||
Err(err) => {
|
||||
warn!(logger, "Unable to open drm device {:?}, Error: {:?}. Skipping", path, err);
|
||||
continue;
|
||||
}
|
||||
},
|
||||
evlh.state().get(token).logger.clone(),
|
||||
)
|
||||
} {
|
||||
}
|
||||
},
|
||||
evlh.state().get(token).logger.clone(),
|
||||
) {
|
||||
Ok(dev) => dev,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
use ::backend::graphics::egl::ffi;
|
||||
use ::backend::graphics::egl::{EGLContext, NativeSurface};
|
||||
use ::backend::graphics::egl::EGLImage;
|
||||
use wayland_server::protocol::wl_buffer::WlBuffer;
|
||||
use wayland_server::Resource;
|
||||
|
||||
/// 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(i32)]
|
||||
pub enum Format {
|
||||
RGB = ffi::egl::TEXTURE_RGB as i32,
|
||||
RGBA = ffi::egl::TEXTURE_RGBA as i32,
|
||||
External = ffi::egl::TEXTURE_EXTERNAL_WL,
|
||||
Y_UV = ffi::egl::TEXTURE_Y_UV_WL,
|
||||
Y_U_V = ffi::egl::TEXTURE_Y_U_V_WL,
|
||||
Y_XUXV = ffi::egl::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 EGLImages {
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub y_inverted: bool,
|
||||
pub format: Format,
|
||||
images: Vec<EGLImage>,
|
||||
buffer: WlBuffer,
|
||||
}
|
||||
|
||||
pub fn buffer_contents<T: NativeSurface>(buffer: WlBuffer, context: &EGLContext<T>) -> Result<(Vec<EGLImages>, attributes: Attributes), BufferAccessError>
|
||||
where
|
||||
{
|
||||
let mut format: i32 = 0;
|
||||
if unsafe { ffi::egl::QueryWaylandBufferWL(context.display, buffer.ptr() as *mut _, ffi::egl::EGL_TEXTURE_FORMAT, &mut format as *mut _) == 0 } {
|
||||
return Err(BufferAccessError::NotManaged);
|
||||
}
|
||||
|
||||
let mut width: i32 = 0;
|
||||
if unsafe { ffi::egl::QueryWaylandBufferWL(context.display, buffer.ptr() as *mut _, ffi::egl::WIDTH as i32, &mut width as *mut _) == 0 } {
|
||||
return Err(BufferAccessError::NotManaged);
|
||||
}
|
||||
|
||||
let mut height: i32 = 0;
|
||||
if unsafe { ffi::egl::QueryWaylandBufferWL(context.display, buffer.ptr() as *mut _, ffi::egl::HEIGHT as i32, &mut height as *mut _) == 0 } {
|
||||
return Err(BufferAccessError::NotManaged);
|
||||
}
|
||||
|
||||
let mut inverted: i32 = 0;
|
||||
if unsafe { ffi::egl::QueryWaylandBufferWL(context.display, buffer.ptr() as *mut _, ffi::egl::WAYLAND_Y_INVERTED_WL, &mut inverted as *mut _) == 0 } {
|
||||
inverted = 1;
|
||||
}
|
||||
|
||||
let mut images = Vec::with_capacity(attributes.format.num_planes() as usize);
|
||||
for i 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 =
|
||||
unsafe { ffi::egl::CreateImageKHR(
|
||||
context.display,
|
||||
ffi::egl::NO_CONTEXT,
|
||||
ffi::egl::WAYLAND_BUFFER_WL,
|
||||
buffer.ptr() as *mut _,
|
||||
out.as_ptr(),
|
||||
) };
|
||||
if image == ffi::egl::NO_IMAGE_KHR {
|
||||
return Err(BufferAccessError::FailedToCreateEGLImage);
|
||||
} else {
|
||||
image
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let result = EGLImages {
|
||||
width: width as u32,
|
||||
height: height as u32,
|
||||
y_inverted: inverted != 0,
|
||||
format: match format {
|
||||
x if x == ffi::egl::TEXTURE_RGB as i32 => Format::RGB,
|
||||
x if x == ffi::egl::TEXTURE_RGBA as i32 => Format::RGBA,
|
||||
ffi::egl::TEXTURE_EXTERNAL_WL => Format::External,
|
||||
ffi::egl::TEXTURE_Y_UV_WL => Format::Y_UV,
|
||||
ffi::egl::TEXTURE_Y_U_V_WL => Format::Y_U_V,
|
||||
ffi::egl::TEXTURE_Y_XUXV_WL => Format::Y_XUXV,
|
||||
_ => panic!("EGL returned invalid texture type"),
|
||||
},
|
||||
images,
|
||||
buffer,
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
|
@ -19,7 +19,6 @@
|
|||
//! quickly encounter a panic.
|
||||
|
||||
pub mod compositor;
|
||||
//pub mod drm;
|
||||
pub mod output;
|
||||
pub mod seat;
|
||||
pub mod shm;
|
||||
|
|
Loading…
Reference in New Issue