#![cfg(target_os = "windows")]
use crate::{
Api, ContextError, CreationError, GlAttributes, GlRequest, PixelFormat,
PixelFormatRequirements,
};
use crate::api::egl::{Context as EglContext, NativeDisplay, EGL};
use crate::api::wgl::Context as WglContext;
use crate::os::windows::WindowExt;
use glutin_egl_sys as ffi;
use winapi::shared::windef::{HGLRC, HWND};
use winit;
use winit::dpi;
use std::os::raw;
#[derive(Clone, Debug)]
pub enum RawHandle {
Egl(ffi::EGLContext),
Wgl(HGLRC),
}
pub enum Context {
Egl(EglContext),
Wgl(WglContext),
HiddenWindowEgl(winit::Window, EglContext),
HiddenWindowWgl(winit::Window, WglContext),
EglPbuffer(EglContext),
}
unsafe impl Send for Context {}
unsafe impl Sync for Context {}
impl Context {
#[inline]
pub fn new_windowed(
wb: winit::WindowBuilder,
el: &winit::EventsLoop,
pf_reqs: &PixelFormatRequirements,
gl_attr: &GlAttributes<&Self>,
) -> Result<(winit::Window, Self), CreationError> {
let win = wb.build(el)?;
let hwnd = win.get_hwnd() as HWND;
let ctx = Self::new_raw_context(hwnd, pf_reqs, gl_attr)?;
Ok((win, ctx))
}
#[inline]
pub fn new_raw_context(
hwnd: HWND,
pf_reqs: &PixelFormatRequirements,
gl_attr: &GlAttributes<&Self>,
) -> Result<Self, CreationError> {
match gl_attr.version {
GlRequest::Specific(Api::OpenGlEs, (_major, _minor)) => {
match (gl_attr.sharing, &*EGL) {
(Some(&Context::HiddenWindowWgl(_, _)), _)
| (Some(&Context::Wgl(_)), _)
| (None, None) => {
let gl_attr_wgl =
gl_attr.clone().map_sharing(|ctx| match *ctx {
Context::HiddenWindowWgl(_, ref c)
| Context::Wgl(ref c) => c.get_hglrc(),
_ => unreachable!(),
});
unsafe {
WglContext::new(&pf_reqs, &gl_attr_wgl, hwnd)
.map(Context::Wgl)
}
}
(Some(_), Some(_)) => {
let gl_attr_egl =
gl_attr.clone().map_sharing(|ctx| match *ctx {
Context::Egl(ref c)
| Context::EglPbuffer(ref c)
| Context::HiddenWindowEgl(_, ref c) => c,
_ => unreachable!(),
});
EglContext::new(
&pf_reqs,
&gl_attr_egl,
NativeDisplay::Other(Some(std::ptr::null())),
)
.and_then(|p| p.finish(hwnd))
.map(|c| Context::Egl(c))
}
(None, Some(_)) => {
let gl_attr_egl =
gl_attr.clone().map_sharing(|_| unreachable!());
let gl_attr_wgl =
gl_attr.clone().map_sharing(|_| unreachable!());
if let Ok(c) = EglContext::new(
&pf_reqs,
&gl_attr_egl,
NativeDisplay::Other(Some(std::ptr::null())),
)
.and_then(|p| p.finish(hwnd))
{
Ok(Context::Egl(c))
} else {
unsafe {
WglContext::new(&pf_reqs, &gl_attr_wgl, hwnd)
.map(Context::Wgl)
}
}
}
_ => panic!(),
}
}
_ => {
let gl_attr_wgl =
gl_attr.clone().map_sharing(|ctx| match *ctx {
Context::HiddenWindowWgl(_, ref c)
| Context::Wgl(ref c) => c.get_hglrc(),
_ => panic!(),
});
unsafe {
WglContext::new(&pf_reqs, &gl_attr_wgl, hwnd).map(Context::Wgl)
}
}
}
}
#[inline]
pub fn new_headless(
el: &winit::EventsLoop,
pf_reqs: &PixelFormatRequirements,
gl_attr: &GlAttributes<&Context>,
dims: dpi::PhysicalSize,
) -> Result<Self, CreationError> {
match (gl_attr.sharing, &*EGL) {
(None, Some(_))
| (Some(&Context::Egl(_)), Some(_))
| (Some(&Context::HiddenWindowEgl(_, _)), Some(_))
| (Some(&Context::EglPbuffer(_)), Some(_)) => {
let gl_attr_egl =
gl_attr.clone().map_sharing(|ctx| match *ctx {
Context::Egl(ref c)
| Context::EglPbuffer(ref c)
| Context::HiddenWindowEgl(_, ref c) => c,
_ => unreachable!(),
});
let native_display = NativeDisplay::Other(None);
let context =
EglContext::new(pf_reqs, &gl_attr_egl, native_display)
.and_then(|prototype| prototype.finish_pbuffer(dims))
.map(|ctx| Context::EglPbuffer(ctx));
if let Ok(context) = context {
return Ok(context);
}
}
_ => (),
}
let wb = winit::WindowBuilder::new()
.with_visibility(false)
.with_dimensions(dims.to_logical(1.));
Self::new_windowed(wb, &el, pf_reqs, gl_attr).map(|(win, context)| {
match context {
Context::Egl(context) => Context::HiddenWindowEgl(win, context),
Context::Wgl(context) => Context::HiddenWindowWgl(win, context),
_ => unreachable!(),
}
})
}
#[inline]
pub fn resize(&self, _width: u32, _height: u32) {
}
#[inline]
pub unsafe fn make_current(&self) -> Result<(), ContextError> {
match *self {
Context::Wgl(ref c) | Context::HiddenWindowWgl(_, ref c) => {
c.make_current()
}
Context::Egl(ref c)
| Context::HiddenWindowEgl(_, ref c)
| Context::EglPbuffer(ref c) => c.make_current(),
}
}
#[inline]
pub fn is_current(&self) -> bool {
match *self {
Context::Wgl(ref c) | Context::HiddenWindowWgl(_, ref c) => {
c.is_current()
}
Context::Egl(ref c)
| Context::HiddenWindowEgl(_, ref c)
| Context::EglPbuffer(ref c) => c.is_current(),
}
}
#[inline]
pub fn get_proc_address(&self, addr: &str) -> *const () {
match *self {
Context::Wgl(ref c) | Context::HiddenWindowWgl(_, ref c) => {
c.get_proc_address(addr)
}
Context::Egl(ref c)
| Context::HiddenWindowEgl(_, ref c)
| Context::EglPbuffer(ref c) => c.get_proc_address(addr),
}
}
#[inline]
pub fn swap_buffers(&self) -> Result<(), ContextError> {
match *self {
Context::Wgl(ref c) => c.swap_buffers(),
Context::Egl(ref c) => c.swap_buffers(),
_ => unreachable!(),
}
}
#[inline]
pub fn get_api(&self) -> Api {
match *self {
Context::Wgl(ref c) | Context::HiddenWindowWgl(_, ref c) => {
c.get_api()
}
Context::Egl(ref c)
| Context::HiddenWindowEgl(_, ref c)
| Context::EglPbuffer(ref c) => c.get_api(),
}
}
#[inline]
pub fn get_pixel_format(&self) -> PixelFormat {
match *self {
Context::Wgl(ref c) => c.get_pixel_format(),
Context::Egl(ref c) => c.get_pixel_format(),
_ => unreachable!(),
}
}
#[inline]
pub unsafe fn raw_handle(&self) -> RawHandle {
match *self {
Context::Wgl(ref c) | Context::HiddenWindowWgl(_, ref c) => {
RawHandle::Wgl(c.get_hglrc())
}
Context::Egl(ref c)
| Context::HiddenWindowEgl(_, ref c)
| Context::EglPbuffer(ref c) => RawHandle::Egl(c.raw_handle()),
}
}
#[inline]
pub unsafe fn get_egl_display(&self) -> Option<*const raw::c_void> {
match *self {
Context::Egl(ref c)
| Context::HiddenWindowEgl(_, ref c)
| Context::EglPbuffer(ref c) => Some(c.get_egl_display()),
_ => None,
}
}
}
pub trait RawContextExt {
unsafe fn new_raw_context(
hwnd: *mut raw::c_void,
cb: crate::ContextBuilder,
) -> Result<crate::RawContext, CreationError>
where
Self: Sized;
}
impl RawContextExt for crate::Context {
#[inline]
unsafe fn new_raw_context(
hwnd: *mut raw::c_void,
cb: crate::ContextBuilder,
) -> Result<crate::RawContext, CreationError>
where
Self: Sized,
{
let crate::ContextBuilder { pf_reqs, gl_attr } = cb;
let gl_attr = gl_attr.map_sharing(|ctx| &ctx.context);
Context::new_raw_context(hwnd as *mut _, &pf_reqs, &gl_attr)
.map(|context| crate::Context { context })
.map(|context| crate::RawContext { context })
}
}