#![cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
))]
#[cfg(not(any(feature = "x11", feature = "wayland")))]
compile_error!("at least one of the 'x11' or 'wayland' features must be enabled");
mod wayland;
mod x11;
#[cfg(feature = "x11")]
use self::x11::X11Context;
use crate::api::osmesa;
use crate::{
Api, ContextCurrentState, ContextError, CreationError, GlAttributes, NotCurrent, PixelFormat,
PixelFormatRequirements, Rect,
};
#[cfg(feature = "x11")]
pub use x11::utils as x11_utils;
#[cfg(feature = "x11")]
use crate::platform::unix::x11::XConnection;
use crate::platform::unix::EventLoopWindowTargetExtUnix;
use winit::dpi;
use winit::event_loop::EventLoopWindowTarget;
use winit::window::{Window, WindowBuilder};
use std::marker::PhantomData;
use std::os::raw;
#[cfg(feature = "x11")]
use std::sync::Arc;
#[derive(Clone, Debug)]
pub enum RawHandle {
#[cfg(feature = "x11")]
Glx(glutin_glx_sys::GLXContext),
Egl(glutin_egl_sys::EGLContext),
}
#[derive(Debug)]
pub enum ContextType {
#[cfg(feature = "x11")]
X11,
#[cfg(feature = "wayland")]
Wayland,
OsMesa,
}
#[derive(Debug)]
pub enum Context {
#[cfg(feature = "x11")]
X11(x11::Context),
#[cfg(feature = "wayland")]
Wayland(wayland::Context),
OsMesa(osmesa::OsMesaContext),
}
impl Context {
fn is_compatible(c: &Option<&Context>, ct: ContextType) -> Result<(), CreationError> {
if let Some(c) = *c {
match ct {
ContextType::OsMesa => match *c {
Context::OsMesa(_) => Ok(()),
_ => {
let msg = "Cannot share an OSMesa context with a non-OSMesa context";
return Err(CreationError::PlatformSpecific(msg.into()));
}
},
#[cfg(feature = "x11")]
ContextType::X11 => match *c {
Context::X11(_) => Ok(()),
_ => {
let msg = "Cannot share an X11 context with a non-X11 context";
return Err(CreationError::PlatformSpecific(msg.into()));
}
},
#[cfg(feature = "wayland")]
ContextType::Wayland => match *c {
Context::Wayland(_) => Ok(()),
_ => {
let msg = "Cannot share a Wayland context with a non-Wayland context";
return Err(CreationError::PlatformSpecific(msg.into()));
}
},
}
} else {
Ok(())
}
}
#[inline]
pub fn new_windowed<T>(
wb: WindowBuilder,
el: &EventLoopWindowTarget<T>,
pf_reqs: &PixelFormatRequirements,
gl_attr: &GlAttributes<&Context>,
) -> Result<(Window, Self), CreationError> {
#[cfg(feature = "wayland")]
if el.is_wayland() {
Context::is_compatible(&gl_attr.sharing, ContextType::Wayland)?;
let gl_attr = gl_attr.clone().map_sharing(|ctx| match *ctx {
Context::Wayland(ref ctx) => ctx,
_ => unreachable!(),
});
return wayland::Context::new(wb, el, pf_reqs, &gl_attr)
.map(|(win, context)| (win, Context::Wayland(context)));
}
#[cfg(feature = "x11")]
if el.is_x11() {
Context::is_compatible(&gl_attr.sharing, ContextType::X11)?;
let gl_attr = gl_attr.clone().map_sharing(|ctx| match *ctx {
Context::X11(ref ctx) => ctx,
_ => unreachable!(),
});
return x11::Context::new(wb, el, pf_reqs, &gl_attr)
.map(|(win, context)| (win, Context::X11(context)));
}
panic!("glutin was not compiled with support for this display server")
}
#[inline]
pub fn new_headless<T>(
el: &EventLoopWindowTarget<T>,
pf_reqs: &PixelFormatRequirements,
gl_attr: &GlAttributes<&Context>,
size: dpi::PhysicalSize<u32>,
) -> Result<Self, CreationError> {
Self::new_headless_impl(el, pf_reqs, gl_attr, Some(size))
}
pub fn new_headless_impl<T>(
el: &EventLoopWindowTarget<T>,
pf_reqs: &PixelFormatRequirements,
gl_attr: &GlAttributes<&Context>,
size: Option<dpi::PhysicalSize<u32>>,
) -> Result<Self, CreationError> {
#[cfg(feature = "wayland")]
if el.is_wayland() {
Context::is_compatible(&gl_attr.sharing, ContextType::Wayland)?;
let gl_attr = gl_attr.clone().map_sharing(|ctx| match *ctx {
Context::Wayland(ref ctx) => ctx,
_ => unreachable!(),
});
return wayland::Context::new_headless(&el, pf_reqs, &gl_attr, size)
.map(|ctx| Context::Wayland(ctx));
}
#[cfg(feature = "x11")]
if el.is_x11() {
Context::is_compatible(&gl_attr.sharing, ContextType::X11)?;
let gl_attr = gl_attr.clone().map_sharing(|ctx| match *ctx {
Context::X11(ref ctx) => ctx,
_ => unreachable!(),
});
return x11::Context::new_headless(&el, pf_reqs, &gl_attr, size)
.map(|ctx| Context::X11(ctx));
}
panic!("glutin was not compiled with support for this display server")
}
#[inline]
pub unsafe fn make_current(&self) -> Result<(), ContextError> {
match *self {
#[cfg(feature = "x11")]
Context::X11(ref ctx) => ctx.make_current(),
#[cfg(feature = "wayland")]
Context::Wayland(ref ctx) => ctx.make_current(),
Context::OsMesa(ref ctx) => ctx.make_current(),
}
}
#[inline]
pub unsafe fn make_not_current(&self) -> Result<(), ContextError> {
match *self {
#[cfg(feature = "x11")]
Context::X11(ref ctx) => ctx.make_not_current(),
#[cfg(feature = "wayland")]
Context::Wayland(ref ctx) => ctx.make_not_current(),
Context::OsMesa(ref ctx) => ctx.make_not_current(),
}
}
#[inline]
pub fn is_current(&self) -> bool {
match *self {
#[cfg(feature = "x11")]
Context::X11(ref ctx) => ctx.is_current(),
#[cfg(feature = "wayland")]
Context::Wayland(ref ctx) => ctx.is_current(),
Context::OsMesa(ref ctx) => ctx.is_current(),
}
}
#[inline]
pub fn get_api(&self) -> Api {
match *self {
#[cfg(feature = "x11")]
Context::X11(ref ctx) => ctx.get_api(),
#[cfg(feature = "wayland")]
Context::Wayland(ref ctx) => ctx.get_api(),
Context::OsMesa(ref ctx) => ctx.get_api(),
}
}
#[inline]
pub unsafe fn raw_handle(&self) -> RawHandle {
match *self {
#[cfg(feature = "x11")]
Context::X11(ref ctx) => match *ctx.raw_handle() {
X11Context::Glx(ref ctx) => RawHandle::Glx(ctx.raw_handle()),
X11Context::Egl(ref ctx) => RawHandle::Egl(ctx.raw_handle()),
},
#[cfg(feature = "wayland")]
Context::Wayland(ref ctx) => RawHandle::Egl(ctx.raw_handle()),
Context::OsMesa(ref ctx) => RawHandle::Egl(ctx.raw_handle()),
}
}
#[inline]
pub unsafe fn get_egl_display(&self) -> Option<*const raw::c_void> {
match *self {
#[cfg(feature = "x11")]
Context::X11(ref ctx) => ctx.get_egl_display(),
#[cfg(feature = "wayland")]
Context::Wayland(ref ctx) => ctx.get_egl_display(),
_ => None,
}
}
#[inline]
pub fn resize(&self, width: u32, height: u32) {
#![allow(unused)]
match *self {
#[cfg(feature = "x11")]
Context::X11(_) => (),
#[cfg(feature = "wayland")]
Context::Wayland(ref ctx) => ctx.resize(width, height),
_ => unreachable!(),
}
}
#[inline]
pub fn get_proc_address(&self, addr: &str) -> *const core::ffi::c_void {
match *self {
#[cfg(feature = "x11")]
Context::X11(ref ctx) => ctx.get_proc_address(addr),
#[cfg(feature = "wayland")]
Context::Wayland(ref ctx) => ctx.get_proc_address(addr),
Context::OsMesa(ref ctx) => ctx.get_proc_address(addr),
}
}
#[inline]
pub fn swap_buffers(&self) -> Result<(), ContextError> {
match *self {
#[cfg(feature = "x11")]
Context::X11(ref ctx) => ctx.swap_buffers(),
#[cfg(feature = "wayland")]
Context::Wayland(ref ctx) => ctx.swap_buffers(),
_ => unreachable!(),
}
}
#[inline]
pub fn swap_buffers_with_damage(&self, rects: &[Rect]) -> Result<(), ContextError> {
match *self {
#[cfg(feature = "x11")]
Context::X11(ref ctx) => ctx.swap_buffers_with_damage(rects),
#[cfg(feature = "wayland")]
Context::Wayland(ref ctx) => ctx.swap_buffers_with_damage(rects),
_ => unreachable!(),
}
}
#[inline]
pub fn swap_buffers_with_damage_supported(&self) -> bool {
match *self {
#[cfg(feature = "x11")]
Context::X11(ref ctx) => ctx.swap_buffers_with_damage_supported(),
#[cfg(feature = "wayland")]
Context::Wayland(ref ctx) => ctx.swap_buffers_with_damage_supported(),
_ => unreachable!(),
}
}
#[inline]
pub fn get_pixel_format(&self) -> PixelFormat {
match *self {
#[cfg(feature = "x11")]
Context::X11(ref ctx) => ctx.get_pixel_format(),
#[cfg(feature = "wayland")]
Context::Wayland(ref ctx) => ctx.get_pixel_format(),
_ => unreachable!(),
}
}
}
pub trait HeadlessContextExt {
fn build_osmesa(
self,
size: dpi::PhysicalSize<u32>,
) -> Result<crate::Context<NotCurrent>, CreationError>
where
Self: Sized;
fn build_surfaceless<TE>(
self,
el: &EventLoopWindowTarget<TE>,
) -> Result<crate::Context<NotCurrent>, CreationError>
where
Self: Sized;
}
impl<'a, T: ContextCurrentState> HeadlessContextExt for crate::ContextBuilder<'a, T> {
#[inline]
fn build_osmesa(
self,
size: dpi::PhysicalSize<u32>,
) -> Result<crate::Context<NotCurrent>, CreationError>
where
Self: Sized,
{
let crate::ContextBuilder { pf_reqs, gl_attr } = self;
let gl_attr = gl_attr.map_sharing(|ctx| &ctx.context);
Context::is_compatible(&gl_attr.sharing, ContextType::OsMesa)?;
let gl_attr = gl_attr.clone().map_sharing(|ctx| match *ctx {
Context::OsMesa(ref ctx) => ctx,
_ => unreachable!(),
});
osmesa::OsMesaContext::new(&pf_reqs, &gl_attr, size)
.map(|context| Context::OsMesa(context))
.map(|context| crate::Context { context, phantom: PhantomData })
}
#[inline]
fn build_surfaceless<TE>(
self,
el: &EventLoopWindowTarget<TE>,
) -> Result<crate::Context<NotCurrent>, CreationError>
where
Self: Sized,
{
let crate::ContextBuilder { pf_reqs, gl_attr } = self;
let gl_attr = gl_attr.map_sharing(|ctx| &ctx.context);
Context::new_headless_impl(el, &pf_reqs, &gl_attr, None)
.map(|context| crate::Context { context, phantom: PhantomData })
}
}
pub trait RawContextExt {
#[cfg(feature = "wayland")]
unsafe fn build_raw_wayland_context(
self,
display_ptr: *const wayland::wl_display,
surface: *mut raw::c_void,
width: u32,
height: u32,
) -> Result<crate::RawContext<NotCurrent>, CreationError>
where
Self: Sized;
#[cfg(feature = "x11")]
unsafe fn build_raw_x11_context(
self,
xconn: Arc<XConnection>,
xwin: raw::c_ulong,
) -> Result<crate::RawContext<NotCurrent>, CreationError>
where
Self: Sized;
}
impl<'a, T: ContextCurrentState> RawContextExt for crate::ContextBuilder<'a, T> {
#[inline]
#[cfg(feature = "wayland")]
unsafe fn build_raw_wayland_context(
self,
display_ptr: *const wayland::wl_display,
surface: *mut raw::c_void,
width: u32,
height: u32,
) -> Result<crate::RawContext<NotCurrent>, CreationError>
where
Self: Sized,
{
let crate::ContextBuilder { pf_reqs, gl_attr } = self;
let gl_attr = gl_attr.map_sharing(|ctx| &ctx.context);
Context::is_compatible(&gl_attr.sharing, ContextType::Wayland)?;
let gl_attr = gl_attr.clone().map_sharing(|ctx| match *ctx {
Context::Wayland(ref ctx) => ctx,
_ => unreachable!(),
});
wayland::Context::new_raw_context(display_ptr, surface, width, height, &pf_reqs, &gl_attr)
.map(|context| Context::Wayland(context))
.map(|context| crate::Context { context, phantom: PhantomData })
.map(|context| crate::RawContext { context, window: () })
}
#[inline]
#[cfg(feature = "x11")]
unsafe fn build_raw_x11_context(
self,
xconn: Arc<XConnection>,
xwin: raw::c_ulong,
) -> Result<crate::RawContext<NotCurrent>, CreationError>
where
Self: Sized,
{
let crate::ContextBuilder { pf_reqs, gl_attr } = self;
let gl_attr = gl_attr.map_sharing(|ctx| &ctx.context);
Context::is_compatible(&gl_attr.sharing, ContextType::X11)?;
let gl_attr = gl_attr.clone().map_sharing(|ctx| match *ctx {
Context::X11(ref ctx) => ctx,
_ => unreachable!(),
});
x11::Context::new_raw_context(xconn, xwin, &pf_reqs, &gl_attr)
.map(|context| Context::X11(context))
.map(|context| crate::Context { context, phantom: PhantomData })
.map(|context| crate::RawContext { context, window: () })
}
}