use super::context::Context;
use super::device::Device;
use crate::gl;
use crate::platform::generic::egl::context;
use crate::platform::generic::egl::surface::{EGLBackedSurface, EGLSurfaceTexture};
use crate::{Error, SurfaceAccess, SurfaceInfo, SurfaceType};
use euclid::default::Size2D;
use glow::Texture;
use std::marker::PhantomData;
use std::os::raw::c_void;
use wayland_sys::client::wl_proxy;
use wayland_sys::egl::{wayland_egl_handle, wl_egl_window};
const SURFACE_GL_TEXTURE_TARGET: u32 = gl::TEXTURE_2D;
#[derive(Debug)]
pub struct Surface(pub(crate) EGLBackedSurface);
#[derive(Debug)]
pub struct SurfaceTexture(pub(crate) EGLSurfaceTexture);
#[derive(Clone)]
pub struct NativeWidget {
pub(crate) wayland_surface: *mut wl_proxy,
pub(crate) size: Size2D<i32>,
}
unsafe impl Send for Surface {}
impl Device {
pub fn create_surface(
&self,
context: &Context,
_: SurfaceAccess,
surface_type: SurfaceType<NativeWidget>,
) -> Result<Surface, Error> {
match surface_type {
SurfaceType::Generic { size } => self.create_generic_surface(context, &size),
SurfaceType::Widget { native_widget } => unsafe {
self.create_window_surface(
context,
native_widget.wayland_surface,
&native_widget.size,
)
},
}
}
fn create_generic_surface(
&self,
context: &Context,
size: &Size2D<i32>,
) -> Result<Surface, Error> {
let _guard = self.temporarily_make_context_current(context)?;
let context_descriptor = self.context_descriptor(context);
let context_attributes = self.context_descriptor_attributes(&context_descriptor);
Ok(Surface(EGLBackedSurface::new_generic(
&context.1,
self.native_connection.egl_display,
context.0.egl_context,
context.0.id,
&context_attributes,
size,
)))
}
unsafe fn create_window_surface(
&self,
context: &Context,
wayland_surface: *mut wl_proxy,
size: &Size2D<i32>,
) -> Result<Surface, Error> {
let egl_window =
(wayland_egl_handle().wl_egl_window_create)(wayland_surface, size.width, size.height);
assert!(!egl_window.is_null());
let context_descriptor = self.context_descriptor(context);
let egl_config = context::egl_config_from_id(
self.native_connection.egl_display,
context_descriptor.egl_config_id,
);
Ok(Surface(EGLBackedSurface::new_window(
self.native_connection.egl_display,
egl_config,
egl_window as *mut c_void,
context.0.id,
size,
)))
}
pub fn create_surface_texture(
&self,
context: &mut Context,
surface: Surface,
) -> Result<SurfaceTexture, (Error, Surface)> {
let _guard = match self.temporarily_make_context_current(context) {
Ok(guard) => guard,
Err(err) => return Err((err, surface)),
};
match surface.0.to_surface_texture(&context.1) {
Ok(surface_texture) => Ok(SurfaceTexture(surface_texture)),
Err((err, surface)) => Err((err, Surface(surface))),
}
}
pub fn destroy_surface(
&self,
context: &mut Context,
surface: &mut Surface,
) -> Result<(), Error> {
let egl_display = self.native_connection.egl_display;
if let Some(wayland_egl_window) =
surface.0.destroy(&context.1, egl_display, context.0.id)?
{
unsafe {
let wayland_egl_window = wayland_egl_window as *mut wl_egl_window;
(wayland_egl_handle().wl_egl_window_destroy)(wayland_egl_window);
}
}
Ok(())
}
pub fn destroy_surface_texture(
&self,
context: &mut Context,
surface_texture: SurfaceTexture,
) -> Result<Surface, (Error, SurfaceTexture)> {
match self.temporarily_make_context_current(context) {
Ok(_guard) => Ok(Surface(surface_texture.0.destroy(&context.1))),
Err(err) => Err((err, surface_texture)),
}
}
pub fn present_surface(&self, context: &Context, surface: &mut Surface) -> Result<(), Error> {
surface
.0
.present(self.native_connection.egl_display, context.0.egl_context)
}
pub fn resize_surface(
&self,
_context: &Context,
surface: &mut Surface,
size: Size2D<i32>,
) -> Result<(), Error> {
let wayland_egl_window = surface.0.native_window()? as *mut c_void as *mut wl_egl_window;
unsafe {
(wayland_egl_handle().wl_egl_window_resize)(
wayland_egl_window,
size.width,
size.height,
0,
0,
)
};
surface.0.size = size;
Ok(())
}
#[inline]
pub fn lock_surface_data<'s>(&self, _: &'s mut Surface) -> Result<SurfaceDataGuard<'s>, Error> {
Err(Error::Unimplemented)
}
#[inline]
pub fn surface_gl_texture_target(&self) -> u32 {
SURFACE_GL_TEXTURE_TARGET
}
pub fn surface_info(&self, surface: &Surface) -> SurfaceInfo {
surface.0.info()
}
#[inline]
pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> Option<Texture> {
surface_texture.0.texture_object
}
}
pub struct SurfaceDataGuard<'a> {
phantom: PhantomData<&'a ()>,
}