Skip to content

Commit

Permalink
glx: 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
mbernat authored Nov 2, 2024
1 parent 9c58fbb commit ed240ab
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

- 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.

# Version 0.32.1

Expand Down
79 changes: 65 additions & 14 deletions glutin/src/api/glx/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,14 @@ impl Display {
std::ptr::null()
};

let context = if self.inner.client_extensions.contains("GLX_ARB_create_context")
&& self.inner.glx_extra.is_some()
{
self.create_context_arb(config, context_attributes, shared_context)?
} else {
self.create_context_legacy(config, shared_context)?
};
let (context, supports_surfaceless) =
if self.inner.client_extensions.contains("GLX_ARB_create_context")
&& self.inner.glx_extra.is_some()
{
self.create_context_arb(config, context_attributes, shared_context)?
} else {
(self.create_context_legacy(config, shared_context)?, false)
};

// Failed to create the context.
if context.is_null() {
Expand All @@ -56,8 +57,13 @@ impl Display {

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

Ok(NotCurrentContext::new(inner))
}
Expand All @@ -67,14 +73,14 @@ impl Display {
config: &Config,
context_attributes: &ContextAttributes,
shared_context: GLXContext,
) -> Result<GLXContext> {
) -> Result<(GLXContext, bool)> {
let extra = self.inner.glx_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 @@ -83,11 +89,16 @@ impl Display {
GlProfile::Compatibility => glx_extra::CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
};

(Some(profile), Some(version))
// Surfaceless contexts are supported with the GLX_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(glx_extra::CONTEXT_ES2_PROFILE_BIT_EXT),
Some(version.unwrap_or(Version::new(2, 0))),
false,
),
_ => {
return Err(ErrorKind::NotSupported(
Expand Down Expand Up @@ -188,7 +199,7 @@ impl Display {
// Terminate list with zero.
attrs.push(0);

super::last_glx_error(|| unsafe {
let context = super::last_glx_error(|| unsafe {
extra.CreateContextAttribsARB(
self.inner.raw.cast(),
*config.inner.raw,
Expand All @@ -197,7 +208,9 @@ impl Display {
1,
attrs.as_ptr(),
)
})
})?;

Ok((context, supports_surfaceless))
}

fn create_context_legacy(
Expand Down Expand Up @@ -228,6 +241,15 @@ pub struct NotCurrentContext {
}

impl NotCurrentContext {
/// Make a [`Self::PossiblyCurrentContext`] indicating that the context
/// could be current on the thread.
///
/// Requires the GLX_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 })
}

fn new(inner: ContextInner) -> Self {
Self { inner }
}
Expand Down Expand Up @@ -297,6 +319,15 @@ pub struct PossiblyCurrentContext {
_nosendsync: PhantomData<GLXContext>,
}

impl PossiblyCurrentContext {
/// Make this context current on the calling thread.
///
/// Requires the GLX_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 @@ -362,9 +393,29 @@ struct ContextInner {
config: Config,
raw: GlxContext,
is_gles: bool,
supports_surfaceless: bool,
}

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

// Passing zero arguments for both `draw` and `read` parameters makes
// the context current without a default framebuffer.
super::last_glx_error(|| unsafe {
self.display.inner.glx.MakeContextCurrent(
self.display.inner.raw.cast(),
0,
0,
*self.raw,
);
})
}

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

0 comments on commit ed240ab

Please sign in to comment.