use super::context::Context;
use super::device::Device;
use crate::egl;
use crate::egl::types::EGLint;
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 x11_dl::xlib::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) window: Window,
}
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.window)
},
}
}
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,
mut x11_window: Window,
) -> Result<Surface, Error> {
let egl_config_id = context::get_context_attr(
self.native_connection.egl_display,
context.0.egl_context,
egl::CONFIG_ID as EGLint,
);
let egl_config =
context::egl_config_from_id(self.native_connection.egl_display, egl_config_id);
let display_guard = self.native_connection.lock_display();
let (mut root_window, mut x, mut y, mut width, mut height) = (0, 0, 0, 0, 0);
let (mut border_width, mut depth) = (0, 0);
(self.native_connection.xlib.XGetGeometry)(
display_guard.display(),
x11_window,
&mut root_window,
&mut x,
&mut y,
&mut width,
&mut height,
&mut border_width,
&mut depth,
);
let size = Size2D::new(width as i32, height as i32);
Ok(Surface(EGLBackedSurface::new_window(
self.native_connection.egl_display,
egl_config,
&mut x11_window as *mut 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;
surface.0.destroy(&context.1, egl_display, context.0.id)?;
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> {
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 ()>,
}