diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c2865336d..b64ceee90a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/glutin/src/api/glx/context.rs b/glutin/src/api/glx/context.rs index 2fd8124343..3c6df4f6c8 100644 --- a/glutin/src/api/glx/context.rs +++ b/glutin/src/api/glx/context.rs @@ -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() { @@ -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)) } @@ -67,14 +73,14 @@ impl Display { config: &Config, context_attributes: &ContextAttributes, shared_context: GLXContext, - ) -> Result { + ) -> Result<(GLXContext, bool)> { let extra = self.inner.glx_extra.as_ref().unwrap(); let mut attrs = Vec::::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); @@ -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( @@ -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, @@ -197,7 +208,9 @@ impl Display { 1, attrs.as_ptr(), ) - }) + })?; + + Ok((context, supports_surfaceless)) } fn create_context_legacy( @@ -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 { + self.inner.make_current_surfaceless()?; + Ok(PossiblyCurrentContext { inner: self.inner, _nosendsync: PhantomData }) + } + fn new(inner: ContextInner) -> Self { Self { inner } } @@ -297,6 +319,15 @@ pub struct PossiblyCurrentContext { _nosendsync: PhantomData, } +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 = Surface; @@ -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( &self, surface_draw: &Surface,