#![allow(unreachable_patterns)]
use std::marker::PhantomData;
use std::num::NonZeroU32;
use raw_window_handle::RawWindowHandle;
use crate::context::{PossiblyCurrentContext, PossiblyCurrentGlContext};
use crate::display::{Display, GetGlDisplay};
use crate::error::Result;
use crate::private::{gl_api_dispatch, Sealed};
#[cfg(cgl_backend)]
use crate::api::cgl::surface::Surface as CglSurface;
#[cfg(egl_backend)]
use crate::api::egl::surface::Surface as EglSurface;
#[cfg(glx_backend)]
use crate::api::glx::surface::Surface as GlxSurface;
#[cfg(wgl_backend)]
use crate::api::wgl::surface::Surface as WglSurface;
pub trait GlSurface<T: SurfaceTypeTrait>: Sealed {
type SurfaceType: SurfaceTypeTrait;
type Context: PossiblyCurrentGlContext;
fn buffer_age(&self) -> u32;
fn width(&self) -> Option<u32>;
fn height(&self) -> Option<u32>;
fn is_single_buffered(&self) -> bool;
fn swap_buffers(&self, context: &Self::Context) -> Result<()>;
fn is_current(&self, context: &Self::Context) -> bool;
fn is_current_draw(&self, context: &Self::Context) -> bool;
fn is_current_read(&self, context: &Self::Context) -> bool;
fn set_swap_interval(&self, context: &Self::Context, interval: SwapInterval) -> Result<()>;
fn resize(&self, context: &Self::Context, width: NonZeroU32, height: NonZeroU32)
where
Self::SurfaceType: ResizeableSurface;
}
pub trait SurfaceTypeTrait: Sealed {
fn surface_type() -> SurfaceType;
}
pub trait ResizeableSurface: Sealed {}
pub trait AsRawSurface {
fn raw_surface(&self) -> RawSurface;
}
#[derive(Default, Debug, Clone)]
pub struct SurfaceAttributesBuilder<T: SurfaceTypeTrait + Default> {
attributes: SurfaceAttributes<T>,
}
impl<T: SurfaceTypeTrait + Default> SurfaceAttributesBuilder<T> {
pub fn new() -> Self {
Default::default()
}
pub fn with_srgb(mut self, srgb: Option<bool>) -> Self {
self.attributes.srgb = srgb;
self
}
}
impl SurfaceAttributesBuilder<WindowSurface> {
pub fn with_single_buffer(mut self, single_buffer: bool) -> Self {
self.attributes.single_buffer = single_buffer;
self
}
pub fn build(
mut self,
raw_window_handle: RawWindowHandle,
width: NonZeroU32,
height: NonZeroU32,
) -> SurfaceAttributes<WindowSurface> {
self.attributes.raw_window_handle = Some(raw_window_handle);
self.attributes.width = Some(width);
self.attributes.height = Some(height);
self.attributes
}
}
impl SurfaceAttributesBuilder<PbufferSurface> {
pub fn with_largest_pbuffer(mut self, largest_pbuffer: bool) -> Self {
self.attributes.largest_pbuffer = largest_pbuffer;
self
}
pub fn with_single_buffer(mut self, single_buffer: bool) -> Self {
self.attributes.single_buffer = single_buffer;
self
}
pub fn build(
mut self,
width: NonZeroU32,
height: NonZeroU32,
) -> SurfaceAttributes<PbufferSurface> {
self.attributes.width = Some(width);
self.attributes.height = Some(height);
self.attributes
}
}
impl SurfaceAttributesBuilder<PixmapSurface> {
pub fn build(mut self, native_pixmap: NativePixmap) -> SurfaceAttributes<PixmapSurface> {
self.attributes.native_pixmap = Some(native_pixmap);
self.attributes
}
}
#[derive(Default, Debug, Clone)]
pub struct SurfaceAttributes<T: SurfaceTypeTrait> {
pub(crate) srgb: Option<bool>,
pub(crate) single_buffer: bool,
pub(crate) width: Option<NonZeroU32>,
pub(crate) height: Option<NonZeroU32>,
pub(crate) largest_pbuffer: bool,
pub(crate) raw_window_handle: Option<RawWindowHandle>,
pub(crate) native_pixmap: Option<NativePixmap>,
_ty: PhantomData<T>,
}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub struct WindowSurface;
impl SurfaceTypeTrait for WindowSurface {
fn surface_type() -> SurfaceType {
SurfaceType::Window
}
}
impl ResizeableSurface for WindowSurface {}
impl Sealed for WindowSurface {}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub struct PbufferSurface;
impl SurfaceTypeTrait for PbufferSurface {
fn surface_type() -> SurfaceType {
SurfaceType::Pbuffer
}
}
impl Sealed for PbufferSurface {}
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub struct PixmapSurface;
impl SurfaceTypeTrait for PixmapSurface {
fn surface_type() -> SurfaceType {
SurfaceType::Pixmap
}
}
impl Sealed for PixmapSurface {}
#[derive(Debug, Clone, Copy)]
pub enum SurfaceType {
Window,
Pixmap,
Pbuffer,
}
#[derive(Debug)]
pub enum Surface<T: SurfaceTypeTrait> {
#[cfg(egl_backend)]
Egl(EglSurface<T>),
#[cfg(glx_backend)]
Glx(GlxSurface<T>),
#[cfg(wgl_backend)]
Wgl(WglSurface<T>),
#[cfg(cgl_backend)]
Cgl(CglSurface<T>),
}
impl<T: SurfaceTypeTrait> GlSurface<T> for Surface<T> {
type Context = PossiblyCurrentContext;
type SurfaceType = T;
fn buffer_age(&self) -> u32 {
gl_api_dispatch!(self; Self(surface) => surface.buffer_age())
}
fn width(&self) -> Option<u32> {
gl_api_dispatch!(self; Self(surface) => surface.width())
}
fn height(&self) -> Option<u32> {
gl_api_dispatch!(self; Self(surface) => surface.height())
}
fn is_single_buffered(&self) -> bool {
gl_api_dispatch!(self; Self(surface) => surface.is_single_buffered())
}
fn swap_buffers(&self, context: &Self::Context) -> Result<()> {
match (self, context) {
#[cfg(egl_backend)]
(Self::Egl(surface), PossiblyCurrentContext::Egl(context)) => {
surface.swap_buffers(context)
},
#[cfg(glx_backend)]
(Self::Glx(surface), PossiblyCurrentContext::Glx(context)) => {
surface.swap_buffers(context)
},
#[cfg(cgl_backend)]
(Self::Cgl(surface), PossiblyCurrentContext::Cgl(context)) => {
surface.swap_buffers(context)
},
#[cfg(wgl_backend)]
(Self::Wgl(surface), PossiblyCurrentContext::Wgl(context)) => {
surface.swap_buffers(context)
},
_ => unreachable!(),
}
}
fn set_swap_interval(&self, context: &Self::Context, interval: SwapInterval) -> Result<()> {
match (self, context) {
#[cfg(egl_backend)]
(Self::Egl(surface), PossiblyCurrentContext::Egl(context)) => {
surface.set_swap_interval(context, interval)
},
#[cfg(glx_backend)]
(Self::Glx(surface), PossiblyCurrentContext::Glx(context)) => {
surface.set_swap_interval(context, interval)
},
#[cfg(cgl_backend)]
(Self::Cgl(surface), PossiblyCurrentContext::Cgl(context)) => {
surface.set_swap_interval(context, interval)
},
#[cfg(wgl_backend)]
(Self::Wgl(surface), PossiblyCurrentContext::Wgl(context)) => {
surface.set_swap_interval(context, interval)
},
_ => unreachable!(),
}
}
fn is_current(&self, context: &Self::Context) -> bool {
match (self, context) {
#[cfg(egl_backend)]
(Self::Egl(surface), PossiblyCurrentContext::Egl(context)) => {
surface.is_current(context)
},
#[cfg(glx_backend)]
(Self::Glx(surface), PossiblyCurrentContext::Glx(context)) => {
surface.is_current(context)
},
#[cfg(cgl_backend)]
(Self::Cgl(surface), PossiblyCurrentContext::Cgl(context)) => {
surface.is_current(context)
},
#[cfg(wgl_backend)]
(Self::Wgl(surface), PossiblyCurrentContext::Wgl(context)) => {
surface.is_current(context)
},
_ => unreachable!(),
}
}
fn is_current_draw(&self, context: &Self::Context) -> bool {
match (self, context) {
#[cfg(egl_backend)]
(Self::Egl(surface), PossiblyCurrentContext::Egl(context)) => {
surface.is_current_draw(context)
},
#[cfg(glx_backend)]
(Self::Glx(surface), PossiblyCurrentContext::Glx(context)) => {
surface.is_current_draw(context)
},
#[cfg(cgl_backend)]
(Self::Cgl(surface), PossiblyCurrentContext::Cgl(context)) => {
surface.is_current_draw(context)
},
#[cfg(wgl_backend)]
(Self::Wgl(surface), PossiblyCurrentContext::Wgl(context)) => {
surface.is_current_draw(context)
},
_ => unreachable!(),
}
}
fn is_current_read(&self, context: &Self::Context) -> bool {
match (self, context) {
#[cfg(egl_backend)]
(Self::Egl(surface), PossiblyCurrentContext::Egl(context)) => {
surface.is_current_read(context)
},
#[cfg(glx_backend)]
(Self::Glx(surface), PossiblyCurrentContext::Glx(context)) => {
surface.is_current_read(context)
},
#[cfg(cgl_backend)]
(Self::Cgl(surface), PossiblyCurrentContext::Cgl(context)) => {
surface.is_current_read(context)
},
#[cfg(wgl_backend)]
(Self::Wgl(surface), PossiblyCurrentContext::Wgl(context)) => {
surface.is_current_read(context)
},
_ => unreachable!(),
}
}
fn resize(&self, context: &Self::Context, width: NonZeroU32, height: NonZeroU32)
where
Self::SurfaceType: ResizeableSurface,
{
match (self, context) {
#[cfg(egl_backend)]
(Self::Egl(surface), PossiblyCurrentContext::Egl(context)) => {
surface.resize(context, width, height)
},
#[cfg(glx_backend)]
(Self::Glx(surface), PossiblyCurrentContext::Glx(context)) => {
surface.resize(context, width, height)
},
#[cfg(cgl_backend)]
(Self::Cgl(surface), PossiblyCurrentContext::Cgl(context)) => {
surface.resize(context, width, height)
},
#[cfg(wgl_backend)]
(Self::Wgl(surface), PossiblyCurrentContext::Wgl(context)) => {
surface.resize(context, width, height)
},
_ => unreachable!(),
}
}
}
impl<T: SurfaceTypeTrait> GetGlDisplay for Surface<T> {
type Target = Display;
fn display(&self) -> Self::Target {
gl_api_dispatch!(self; Self(surface) => surface.display(); as Display)
}
}
impl<T: SurfaceTypeTrait> AsRawSurface for Surface<T> {
fn raw_surface(&self) -> RawSurface {
gl_api_dispatch!(self; Self(surface) => surface.raw_surface())
}
}
impl<T: SurfaceTypeTrait> Sealed for Surface<T> {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SwapInterval {
DontWait,
Wait(NonZeroU32),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NativePixmap {
XlibPixmap(std::os::raw::c_ulong),
XcbPixmap(u32),
WindowsPixmap(isize),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RawSurface {
#[cfg(egl_backend)]
Egl(*const std::ffi::c_void),
#[cfg(glx_backend)]
Glx(u64),
#[cfg(wgl_backend)]
Wgl(*const std::ffi::c_void),
#[cfg(cgl_backend)]
Cgl(*const std::ffi::c_void),
}
#[repr(C)]
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct Rect {
pub x: i32,
pub y: i32,
pub width: i32,
pub height: i32,
}
impl Rect {
pub fn new(x: i32, y: i32, width: i32, height: i32) -> Self {
Self { x, y, width, height }
}
}