Skip to content

Commit

Permalink
wgl: add make_current_surfaceless
Browse files Browse the repository at this point in the history
This follows the EGL api to make surfaceless platforms.
  • Loading branch information
kchibisov authored Nov 3, 2024
1 parent ed240ab commit d5edc13
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 23 deletions.
14 changes: 11 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
# Unreleased

- Add `PossiblyCurrentContext::make_not_current_in_place(&self)` for when `Send` capability of `NotCurrentContext` is not required.
- Add `NotCurrentContext::make_current_surfaceless(self)` and `PossiblyCurrentContext::make_current_surfaceless(&self)` in the `Cgl` implementation to allow the use of surfaceless contexts on MacOS.
- Add `NotCurrentContext::make_current_surfaceless(self)` and `PossiblyCurrentContext::make_current_surfaceless(&self)` in the `Glx` implementation to allow the use of surfaceless contexts with GLX.
- Added `PossiblyCurrentContext::make_not_current_in_place(&self)` for when `Send` capability of `NotCurrentContext` is not required.
- Added `NotCurrentContext::make_current_surfaceless(self)` and
`PossiblyCurrentContext::make_current_surfaceless(&self)` in the `Cgl`
implementation to allow the use of surfaceless contexts on MacOS.
- Added `NotCurrentContext::make_current_surfaceless(self)` and
`PossiblyCurrentContext::make_current_surfaceless(&self)` in the `Glx`
implementation to allow the use of surfaceless contexts with GLX.
- Added `NotCurrentContext::make_current_surfaceless(self)` and
`PossiblyCurrentContext::make_current_surfaceless(&self)` in the `Wgl`
implementation to allow the use of surfaceless contexts with WGL.


# Version 0.32.1

Expand Down
87 changes: 67 additions & 20 deletions glutin/src/api/wgl/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,27 +45,34 @@ impl Display {
_ => std::ptr::null(),
};

let context = if self.inner.client_extensions.contains("WGL_ARB_create_context") {
self.create_context_arb(hdc, share_ctx, context_attributes)?
} else {
unsafe {
let raw = wgl::CreateContext(hdc as *const _);
if raw.is_null() {
return Err(IoError::last_os_error().into());
}
let (context, supports_surfaceless) =
if self.inner.client_extensions.contains("WGL_ARB_create_context") {
self.create_context_arb(hdc, share_ctx, context_attributes)?
} else {
unsafe {
let raw = wgl::CreateContext(hdc as *const _);
if raw.is_null() {
return Err(IoError::last_os_error().into());
}

// Context sharing.
if !share_ctx.is_null() && wgl::ShareLists(share_ctx, raw) == 0 {
return Err(IoError::last_os_error().into());
}
// Context sharing.
if !share_ctx.is_null() && wgl::ShareLists(share_ctx, raw) == 0 {
return Err(IoError::last_os_error().into());
}

WglContext(raw)
}
};
(WglContext(raw), false)
}
};

let config = config.clone();
let is_gles = matches!(context_attributes.api, Some(ContextApi::Gles(_)));
let inner = ContextInner { display: self.clone(), config, raw: context, is_gles };
let inner = ContextInner {
display: self.clone(),
config,
raw: context,
is_gles,
supports_surfaceless,
};
Ok(NotCurrentContext { inner })
}

Expand All @@ -74,14 +81,14 @@ impl Display {
hdc: HDC,
share_context: HGLRC,
context_attributes: &ContextAttributes,
) -> Result<WglContext> {
) -> Result<(WglContext, bool)> {
let extra = self.inner.wgl_extra.as_ref().unwrap();
let mut attrs = Vec::<c_int>::with_capacity(16);

// Check whether the ES context creation is supported.
let supports_es = self.inner.features.contains(DisplayFeatures::CREATE_ES_CONTEXT);

let (profile, version) = match context_attributes.api {
let (profile, version, supports_surfaceless) = match context_attributes.api {
api @ Some(ContextApi::OpenGl(_)) | api @ None => {
let version = api.and_then(|api| api.version());
let (profile, version) = context::pick_profile(context_attributes.profile, version);
Expand All @@ -90,11 +97,16 @@ impl Display {
GlProfile::Compatibility => wgl_extra::CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
};

(Some(profile), Some(version))
// Surfaceless contexts are supported with the WGL_ARB_create_context extension
// when using OpenGL 3.0 or greater.
let supports_surfaceless = version >= Version::new(3, 0);

(Some(profile), Some(version), supports_surfaceless)
},
Some(ContextApi::Gles(version)) if supports_es => (
Some(wgl_extra::CONTEXT_ES2_PROFILE_BIT_EXT),
Some(version.unwrap_or(Version::new(2, 0))),
false,
),
_ => {
return Err(ErrorKind::NotSupported(
Expand Down Expand Up @@ -201,7 +213,7 @@ impl Display {
if raw.is_null() {
Err(IoError::last_os_error().into())
} else {
Ok(WglContext(raw))
Ok((WglContext(raw), supports_surfaceless))
}
}
}
Expand All @@ -220,6 +232,15 @@ impl NotCurrentContext {
fn new(inner: ContextInner) -> Self {
Self { inner }
}

/// Make a [`Self::PossiblyCurrentContext`] indicating that the context
/// could be current on the thread.
///
/// Requires the WGL_ARB_create_context extension and OpenGL 3.0 or greater.
pub fn make_current_surfaceless(self) -> Result<PossiblyCurrentContext> {
self.inner.make_current_surfaceless()?;
Ok(PossiblyCurrentContext { inner: self.inner, _nosendsync: PhantomData })
}
}

impl NotCurrentGlContext for NotCurrentContext {
Expand Down Expand Up @@ -283,6 +304,15 @@ pub struct PossiblyCurrentContext {
_nosendsync: PhantomData<HGLRC>,
}

impl PossiblyCurrentContext {
/// Make this context current on the calling thread.
///
/// Requires the WGL_ARB_create_context extension and OpenGL 3.0 or greater.
pub fn make_current_surfaceless(&self) -> Result<()> {
self.inner.make_current_surfaceless()
}
}

impl PossiblyCurrentGlContext for PossiblyCurrentContext {
type NotCurrentContext = NotCurrentContext;
type Surface<T: SurfaceTypeTrait> = Surface<T>;
Expand Down Expand Up @@ -356,6 +386,7 @@ struct ContextInner {
config: Config,
raw: WglContext,
is_gles: bool,
supports_surfaceless: bool,
}

impl fmt::Debug for ContextInner {
Expand All @@ -381,6 +412,22 @@ impl Deref for WglContext {
unsafe impl Send for WglContext {}

impl ContextInner {
fn make_current_surfaceless(&self) -> Result<()> {
if !self.supports_surfaceless {
return Err(
ErrorKind::NotSupported("the surfaceless context Api isn't supported").into()
);
}

unsafe {
if wgl::MakeCurrent(std::ptr::null(), self.raw.cast()) == 0 {
Err(IoError::last_os_error().into())
} else {
Ok(())
}
}
}

fn make_current_draw_read<T: SurfaceTypeTrait>(
&self,
_surface_draw: &Surface<T>,
Expand Down

0 comments on commit d5edc13

Please sign in to comment.