Skip to content

Commit

Permalink
Add buffer_age method on WindowedContext
Browse files Browse the repository at this point in the history
This uses `EGL_EXT_buffer_age` and `GLX_EXT_buffer_age` API to query
window's back buffer age.
  • Loading branch information
kchibisov authored May 5, 2022
1 parent e18154c commit 988b070
Show file tree
Hide file tree
Showing 13 changed files with 148 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Unreleased

- Fix crash when creating OpenGLES context without explicit version
- Add `buffer_age` method on `WindowedContext`

# Version 0.28.0 (2021-12-02)

Expand Down
22 changes: 22 additions & 0 deletions glutin/src/api/egl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,28 @@ impl Context {
pub fn get_pixel_format(&self) -> PixelFormat {
self.pixel_format.clone()
}

#[inline]
pub fn buffer_age(&self) -> u32 {
let egl = EGL.as_ref().unwrap();
let surface = self.surface.as_ref().unwrap().lock();

let mut buffer_age = 0;
let result = unsafe {
egl.QuerySurface(
self.display,
*surface as *const _,
ffi::egl::BUFFER_AGE_EXT as i32,
&mut buffer_age,
)
};

if result == ffi::egl::FALSE {
0
} else {
buffer_age as u32
}
}
}

unsafe impl Send for Context {}
Expand Down
18 changes: 18 additions & 0 deletions glutin/src/api/glx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,24 @@ impl Context {
}
}

#[inline]
pub fn buffer_age(&self) -> u32 {
let glx = GLX.as_ref().unwrap();

let mut buffer_age = 0;

unsafe {
glx.QueryDrawable(
self.xconn.display as *mut _,
self.drawable,
ffi::glx_extra::BACK_BUFFER_AGE_EXT as i32,
&mut buffer_age,
);
}

buffer_age
}

#[inline]
pub fn get_pixel_format(&self) -> PixelFormat {
self.pixel_format.clone()
Expand Down
5 changes: 5 additions & 0 deletions glutin/src/api/ios/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,11 @@ impl Context {
}
}

#[inline]
pub fn buffer_age(&self) -> u32 {
0
}

#[inline]
pub fn swap_buffers_with_damage(&self, _rects: &[Rect]) -> Result<(), ContextError> {
Err(ContextError::OsError("buffer damage not suported".to_string()))
Expand Down
5 changes: 5 additions & 0 deletions glutin/src/platform_impl/emscripten/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ impl Context {
}
}

#[inline]
pub fn buffer_age(&self) -> u32 {
0
}

#[inline]
pub fn swap_buffers(&self) -> Result<(), ContextError> {
Ok(())
Expand Down
5 changes: 5 additions & 0 deletions glutin/src/platform_impl/macos/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,11 @@ impl Context {
Ok(())
}

#[inline]
pub fn buffer_age(&self) -> u32 {
0
}

#[inline]
pub fn swap_buffers_with_damage(&self, _rects: &[Rect]) -> Result<(), ContextError> {
Err(ContextError::OsError("buffer damage not suported".to_string()))
Expand Down
11 changes: 11 additions & 0 deletions glutin/src/platform_impl/unix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,17 @@ impl Context {
}
}

#[inline]
pub fn buffer_age(&self) -> u32 {
match *self {
#[cfg(feature = "x11")]
Context::X11(ref ctx) => ctx.buffer_age(),
#[cfg(feature = "wayland")]
Context::Wayland(ref ctx) => ctx.buffer_age(),
_ => unreachable!(),
}
}

#[inline]
pub fn swap_buffers_with_damage_supported(&self) -> bool {
match *self {
Expand Down
17 changes: 12 additions & 5 deletions glutin/src/platform_impl/unix/x11.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ pub enum X11Context {

#[derive(Debug)]
pub struct ContextInner {
xconn: Arc<XConnection>,
context: X11Context,
}

Expand Down Expand Up @@ -224,7 +223,7 @@ impl Context {
Prototype::Egl(ctx) => X11Context::Egl(ctx.finish_pbuffer(size)?),
};

let context = Context::PBuffer(ContextInner { xconn: Arc::clone(&xconn), context });
let context = Context::PBuffer(ContextInner { context });

Ok(context)
} else {
Expand Down Expand Up @@ -268,7 +267,7 @@ impl Context {
_ => unimplemented!(),
};

let context = Context::Surfaceless(ContextInner { xconn: Arc::clone(&xconn), context });
let context = Context::Surfaceless(ContextInner { context });

Ok(context)
}
Expand Down Expand Up @@ -495,7 +494,7 @@ impl Context {
Prototype::Egl(ctx) => X11Context::Egl(ctx.finish(xwin as _)?),
};

let context = Context::Windowed(ContextInner { xconn: Arc::clone(&xconn), context });
let context = Context::Windowed(ContextInner { context });

Ok((win, context))
}
Expand Down Expand Up @@ -569,7 +568,7 @@ impl Context {
Prototype::Egl(ctx) => X11Context::Egl(ctx.finish(xwin as _)?),
};

let context = Context::Windowed(ContextInner { xconn: Arc::clone(&xconn), context });
let context = Context::Windowed(ContextInner { context });

Ok(context)
}
Expand Down Expand Up @@ -627,6 +626,14 @@ impl Context {
}
}

#[inline]
pub fn buffer_age(&self) -> u32 {
match self.context {
X11Context::Glx(ref ctx) => ctx.buffer_age(),
X11Context::Egl(ref ctx) => ctx.buffer_age(),
}
}

#[inline]
pub fn swap_buffers(&self) -> Result<(), ContextError> {
match self.context {
Expand Down
8 changes: 8 additions & 0 deletions glutin/src/platform_impl/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,14 @@ impl Context {
}
}

#[inline]
pub fn buffer_age(&self) -> u32 {
match *self {
Context::Egl(ref c) => c.buffer_age(),
_ => 0,
}
}

#[inline]
pub fn swap_buffers(&self) -> Result<(), ContextError> {
match *self {
Expand Down
8 changes: 8 additions & 0 deletions glutin/src/windowed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,14 @@ impl<W> ContextWrapper<PossiblyCurrent, W> {
let (width, height) = size.into();
self.context.context.resize(width, height);
}

/// Query the underlying surface back's buffer age.
///
/// Return `n` is the number of frames elapsed since it was most recently
/// drawn.
pub fn buffer_age(&self) -> u32 {
self.context.context.buffer_age()
}
}

impl<T: ContextCurrentState, W> ContextWrapper<T, W> {
Expand Down
17 changes: 9 additions & 8 deletions glutin_egl_sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,20 @@ fn main() {
Profile::Core,
Fallbacks::All,
[
"EGL_KHR_create_context",
"EGL_EXT_buffer_age",
"EGL_EXT_create_context_robustness",
"EGL_EXT_platform_base",
"EGL_EXT_platform_device",
"EGL_EXT_platform_wayland",
"EGL_EXT_platform_x11",
"EGL_KHR_create_context",
"EGL_KHR_create_context_no_error",
"EGL_KHR_platform_x11",
"EGL_KHR_platform_android",
"EGL_KHR_platform_wayland",
"EGL_KHR_platform_gbm",
"EGL_EXT_platform_base",
"EGL_EXT_platform_x11",
"EGL_MESA_platform_gbm",
"EGL_EXT_platform_wayland",
"EGL_EXT_platform_device",
"EGL_KHR_platform_wayland",
"EGL_KHR_platform_x11",
"EGL_KHR_swap_buffers_with_damage",
"EGL_MESA_platform_gbm",
],
);

Expand Down
40 changes: 40 additions & 0 deletions glutin_examples/examples/buffer_age.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
mod support;

use glutin::event::{Event, WindowEvent};
use glutin::event_loop::{ControlFlow, EventLoop};
use glutin::window::WindowBuilder;
use glutin::ContextBuilder;

fn main() {
let el = EventLoop::new();
let wb = WindowBuilder::new().with_title("A fantastic window!");

let windowed_context = ContextBuilder::new().with_vsync(true).build_windowed(wb, &el).unwrap();

let windowed_context = unsafe { windowed_context.make_current().unwrap() };

println!("Pixel format of the window's GL context: {:?}", windowed_context.get_pixel_format());

let gl = support::load(&windowed_context.context());

el.run(move |event, _, control_flow| {
println!("{:?}", event);
*control_flow = ControlFlow::Wait;

match event {
Event::LoopDestroyed => return,
Event::WindowEvent { event, .. } => match event {
WindowEvent::Resized(physical_size) => windowed_context.resize(physical_size),
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
_ => (),
},
Event::RedrawRequested(_) => {
gl.draw_frame([1.0, 0.5, 0.7, 1.0]);
println!("Buffer age: {}", windowed_context.buffer_age());
windowed_context.swap_buffers().unwrap();
windowed_context.window().request_redraw();
}
_ => (),
}
});
}
7 changes: 4 additions & 3 deletions glutin_glx_sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,18 @@ fn main() {
Profile::Core,
Fallbacks::All,
[
"GLX_ARB_context_flush_control",
"GLX_ARB_create_context",
"GLX_ARB_create_context_profile",
"GLX_ARB_create_context_robustness",
"GLX_ARB_context_flush_control",
"GLX_ARB_fbconfig_float",
"GLX_ARB_framebuffer_sRGB",
"GLX_EXT_framebuffer_sRGB",
"GLX_ARB_multisample",
"GLX_EXT_buffer_age",
"GLX_EXT_framebuffer_sRGB",
"GLX_EXT_swap_control",
"GLX_SGI_swap_control",
"GLX_MESA_swap_control",
"GLX_SGI_swap_control",
],
)
.write_bindings(gl_generator::StructGenerator, &mut file)
Expand Down

0 comments on commit 988b070

Please sign in to comment.