diff --git a/CHANGELOG.md b/CHANGELOG.md index e83b252dcb..3b08ad7c76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - Added `PossiblyCurrentContext::make_not_current_in_place(&self)` for when `Send` capability of `NotCurrentContext` is not required. - Added workaround for EGL drivers reporting `EGL_KHR_platform_gbm` without EGL 1.5 client. - **Breaking:** Added `make_current_surfaceless(self)` for `{Possibly,Not}CurrentGlContext`. +- Added `GlContext::priority`/`ContextAttributesBuilder::with_priority` to get/set context priority. # Version 0.32.1 diff --git a/glutin/src/api/cgl/context.rs b/glutin/src/api/cgl/context.rs index 2d6f3516e7..568df49349 100644 --- a/glutin/src/api/cgl/context.rs +++ b/glutin/src/api/cgl/context.rs @@ -10,7 +10,9 @@ use objc2_app_kit::{NSOpenGLCPSwapInterval, NSView}; use objc2_foundation::{run_on_main, MainThreadBound}; use crate::config::GetGlConfig; -use crate::context::{AsRawContext, ContextApi, ContextAttributes, RawContext, Robustness}; +use crate::context::{ + AsRawContext, ContextApi, ContextAttributes, Priority, RawContext, Robustness, +}; use crate::display::GetGlDisplay; use crate::error::{ErrorKind, Result}; use crate::prelude::*; @@ -113,6 +115,10 @@ impl GlContext for NotCurrentContext { fn context_api(&self) -> ContextApi { self.inner.context_api() } + + fn priority(&self) -> Priority { + Priority::Medium + } } impl GetGlConfig for NotCurrentContext { @@ -190,6 +196,10 @@ impl GlContext for PossiblyCurrentContext { fn context_api(&self) -> ContextApi { self.inner.context_api() } + + fn priority(&self) -> Priority { + Priority::Medium + } } impl GetGlConfig for PossiblyCurrentContext { diff --git a/glutin/src/api/egl/context.rs b/glutin/src/api/egl/context.rs index b58b1cbf9e..d4421b36d7 100644 --- a/glutin/src/api/egl/context.rs +++ b/glutin/src/api/egl/context.rs @@ -9,7 +9,8 @@ use glutin_egl_sys::{egl, EGLContext}; use crate::config::{Api, GetGlConfig}; use crate::context::{ - self, AsRawContext, ContextApi, ContextAttributes, GlProfile, RawContext, Robustness, Version, + self, AsRawContext, ContextApi, ContextAttributes, GlProfile, Priority, RawContext, Robustness, + Version, }; use crate::display::{DisplayFeatures, GetGlDisplay}; use crate::error::{ErrorKind, Result}; @@ -126,6 +127,38 @@ impl Display { } } + if let Some(priority) = context_attributes.priority.filter(|_| { + let extensions = &self.inner.display_extensions; + + // Some android versions don't report support for this extension, even though + // it's supported. + // + // https://github.com/googlevr/gvr-android-sdk/issues/330 + #[cfg(android_platform)] + let android = extensions.contains("EGL_ANDROID_front_buffer_auto_refresh") + && extensions.contains("EGL_ANDROID_create_native_client_buffer"); + #[cfg(not(android_platform))] + let android = false; + + extensions.contains("EGL_IMG_context_priority") || android + }) { + let priority = match priority { + Priority::Low => egl::CONTEXT_PRIORITY_LOW_IMG, + Priority::Medium => egl::CONTEXT_PRIORITY_MEDIUM_IMG, + Priority::High => egl::CONTEXT_PRIORITY_HIGH_IMG, + Priority::Realtime => { + if self.inner.display_extensions.contains("EGL_NV_context_priority_realtime") { + egl::CONTEXT_PRIORITY_REALTIME_NV + } else { + egl::CONTEXT_PRIORITY_HIGH_IMG + } + }, + }; + + attrs.push(egl::CONTEXT_PRIORITY_LEVEL_IMG as EGLint); + attrs.push(priority as EGLint); + } + attrs.push(egl::NONE as EGLint); let shared_context = if let Some(shared_context) = @@ -212,6 +245,10 @@ impl GlContext for NotCurrentContext { fn context_api(&self) -> ContextApi { self.inner.context_api() } + + fn priority(&self) -> Priority { + self.inner.priority() + } } impl GetGlConfig for NotCurrentContext { @@ -286,6 +323,10 @@ impl GlContext for PossiblyCurrentContext { fn context_api(&self) -> ContextApi { self.inner.context_api() } + + fn priority(&self) -> Priority { + self.inner.priority() + } } impl GetGlConfig for PossiblyCurrentContext { @@ -380,6 +421,16 @@ impl ContextInner { } } + fn priority(&self) -> Priority { + match self.query_attribute(egl::CONTEXT_PRIORITY_LEVEL_IMG as EGLint).map(|a| a as EGLenum) + { + Some(egl::CONTEXT_PRIORITY_LOW_IMG) => Priority::Low, + Some(egl::CONTEXT_PRIORITY_HIGH_IMG) => Priority::High, + Some(egl::CONTEXT_PRIORITY_REALTIME_NV) => Priority::Realtime, + _ => Priority::Medium, + } + } + /// Query the context attribute. fn query_attribute(&self, attribute: EGLint) -> Option { unsafe { diff --git a/glutin/src/api/glx/context.rs b/glutin/src/api/glx/context.rs index 12189a57a2..e4f0c15e4b 100644 --- a/glutin/src/api/glx/context.rs +++ b/glutin/src/api/glx/context.rs @@ -10,8 +10,8 @@ use glutin_glx_sys::{glx, glx_extra}; use crate::config::GetGlConfig; use crate::context::{ - self, AsRawContext, ContextApi, ContextAttributes, GlProfile, RawContext, ReleaseBehavior, - Robustness, Version, + self, AsRawContext, ContextApi, ContextAttributes, GlProfile, Priority, RawContext, + ReleaseBehavior, Robustness, Version, }; use crate::display::{DisplayFeatures, GetGlDisplay}; use crate::error::{ErrorKind, Result}; @@ -281,6 +281,10 @@ impl GlContext for NotCurrentContext { fn context_api(&self) -> ContextApi { self.inner.context_api() } + + fn priority(&self) -> Priority { + Priority::Medium + } } impl GetGlConfig for NotCurrentContext { @@ -353,6 +357,10 @@ impl GlContext for PossiblyCurrentContext { fn context_api(&self) -> ContextApi { self.inner.context_api() } + + fn priority(&self) -> Priority { + Priority::Medium + } } impl GetGlConfig for PossiblyCurrentContext { diff --git a/glutin/src/api/wgl/context.rs b/glutin/src/api/wgl/context.rs index 67d44b2524..7bfa43bb8a 100644 --- a/glutin/src/api/wgl/context.rs +++ b/glutin/src/api/wgl/context.rs @@ -13,8 +13,8 @@ use windows_sys::Win32::Graphics::Gdi::{self as gdi, HDC}; use crate::config::GetGlConfig; use crate::context::{ - self, AsRawContext, ContextApi, ContextAttributes, GlProfile, RawContext, ReleaseBehavior, - Robustness, Version, + self, AsRawContext, ContextApi, ContextAttributes, GlProfile, Priority, RawContext, + ReleaseBehavior, Robustness, Version, }; use crate::display::{DisplayFeatures, GetGlDisplay}; use crate::error::{ErrorKind, Result}; @@ -268,6 +268,10 @@ impl GlContext for NotCurrentContext { fn context_api(&self) -> ContextApi { self.inner.context_api() } + + fn priority(&self) -> Priority { + Priority::Medium + } } impl GetGlDisplay for NotCurrentContext { @@ -364,6 +368,10 @@ impl GlContext for PossiblyCurrentContext { fn context_api(&self) -> ContextApi { self.inner.context_api() } + + fn priority(&self) -> Priority { + Priority::Medium + } } impl AsRawContext for PossiblyCurrentContext { diff --git a/glutin/src/context.rs b/glutin/src/context.rs index 8e89283ec9..801e26ea38 100644 --- a/glutin/src/context.rs +++ b/glutin/src/context.rs @@ -34,6 +34,9 @@ pub trait GlContext: Sealed { /// /// The returned value's [`Version`] will always be `None`. fn context_api(&self) -> ContextApi; + + /// Get the [`Priority`] used by the context. + fn priority(&self) -> Priority; } /// A trait to group common not current operations. @@ -224,6 +227,24 @@ impl ContextAttributesBuilder { self } + /// Set the priority hint, which might not be honored if the API does not + /// support it, if there are constraints on the number of high priority + /// contexts available in the system, or system policy limits access to + /// high priority contexts to appropriate system privilege level the + /// context creation may fail. + /// + /// By default no priority is specified, which corresponds to + /// [`Priority::Medium`]. + /// + /// # Api specific + /// + /// - **WGL/GLX:** not implemented. + /// - **CGL:** not supported. + pub fn with_priority(mut self, priority: Priority) -> Self { + self.attributes.priority = Some(priority); + self + } + /// Build the context attributes. /// /// The `raw_window_handle` isn't required and here for WGL compatibility. @@ -251,6 +272,8 @@ pub struct ContextAttributes { pub(crate) api: Option, + pub(crate) priority: Option, + pub(crate) shared_context: Option, pub(crate) raw_window_handle: Option, @@ -471,6 +494,10 @@ impl GlContext for NotCurrentContext { fn context_api(&self) -> ContextApi { gl_api_dispatch!(self; Self(context) => context.context_api()) } + + fn priority(&self) -> Priority { + gl_api_dispatch!(self; Self(context) => context.priority()) + } } impl GetGlConfig for NotCurrentContext { @@ -599,6 +626,10 @@ impl GlContext for PossiblyCurrentContext { fn context_api(&self) -> ContextApi { gl_api_dispatch!(self; Self(context) => context.context_api()) } + + fn priority(&self) -> Priority { + gl_api_dispatch!(self; Self(context) => context.priority()) + } } impl GetGlConfig for PossiblyCurrentContext { @@ -645,6 +676,25 @@ pub enum RawContext { Cgl(*const ffi::c_void), } +/// Priority hint +#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] +pub enum Priority { + /// Lowest priority, contexts using this priority give way for most other + /// contexts. + Low, + /// Default priority. + #[default] + Medium, + /// High priority is usually required for VR applications. + High, + /// Realtime priority contexts are executed immediately and preempt any + /// current context running. + /// + /// When such context is not supported, [`Priority::High`] will be requested + /// instead. + Realtime, +} + /// Pick `GlProfile` and `Version` based on the provided params. #[cfg(any(egl_backend, glx_backend, wgl_backend))] pub(crate) fn pick_profile( diff --git a/glutin_egl_sys/build.rs b/glutin_egl_sys/build.rs index c8dbedf87a..3915585143 100644 --- a/glutin_egl_sys/build.rs +++ b/glutin_egl_sys/build.rs @@ -35,6 +35,7 @@ fn main() { "EGL_EXT_platform_wayland", "EGL_EXT_platform_x11", "EGL_EXT_swap_buffers_with_damage", + "EGL_IMG_context_priority", "EGL_KHR_create_context", "EGL_KHR_create_context_no_error", "EGL_KHR_display_reference", @@ -47,6 +48,7 @@ fn main() { "EGL_KHR_swap_buffers_with_damage", "EGL_KHR_wait_sync", "EGL_MESA_platform_gbm", + "EGL_NV_context_priority_realtime", ]); if target.contains("ios") {