From b05ef16d817af85d175d60422591d90fe3ec4218 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 23 Jan 2015 09:31:05 +0100 Subject: [PATCH] Implement vsync for x11 and add vsync example --- Cargo.toml | 3 +++ build.rs | 2 ++ examples/vsync.rs | 46 ++++++++++++++++++++++++++++++++++++++++++ src/x11/window/mod.rs | 47 +++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 examples/vsync.rs diff --git a/Cargo.toml b/Cargo.toml index b7a148c9..a277291d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,9 @@ gl_common = "*" gl_generator = "*" khronos_api = "*" +[dev-dependencies] +clock_ticks = "*" + [target.arm-linux-androideabi.dependencies.android_glue] git = "https://github.com/tomaka/android-rs-glue" diff --git a/build.rs b/build.rs index f49b47f1..15a0f6da 100644 --- a/build.rs +++ b/build.rs @@ -39,6 +39,8 @@ fn main() { khronos_api::GLX_XML, vec![ "GLX_ARB_create_context".to_string(), + "GLX_EXT_swap_control".to_string(), + "GLX_SGI_swap_control".to_string() ], "1.4", "core", &mut file).unwrap(); } diff --git a/examples/vsync.rs b/examples/vsync.rs new file mode 100644 index 00000000..ec9ea79f --- /dev/null +++ b/examples/vsync.rs @@ -0,0 +1,46 @@ +#[cfg(target_os = "android")] +#[macro_use] +extern crate android_glue; + +extern crate clock_ticks; +extern crate glutin; + +mod support; + +#[cfg(target_os = "android")] +android_start!(main); + +#[cfg(not(feature = "window"))] +fn main() { println!("This example requires glutin to be compiled with the `window` feature"); } + +#[cfg(feature = "window")] +fn resize_callback(width: u32, height: u32) { + println!("Window resized to {}x{}", width, height); +} + +#[cfg(feature = "window")] +fn main() { + println!("Vsync example. This example may panic if your driver or your system forces \ + you out of vsync. This is intended when `build_strict` is used."); + + let mut window = glutin::WindowBuilder::new().with_vsync().build_strict().unwrap(); + window.set_window_resize_callback(Some(resize_callback as fn(u32, u32))); + unsafe { window.make_current() }; + + let context = support::load(&window); + + while !window.is_closed() { + let before = clock_ticks::precise_time_ns(); + + context.draw_frame((0.0, 1.0, 0.0, 1.0)); + window.swap_buffers(); + + for ev in window.poll_events() { + println!("{:?}", ev); + } + + let after = clock_ticks::precise_time_ns(); + println!("Vsync example - Time of previous frame: {}ms", + (after - before) as f32 / 1000000.0); + } +} diff --git a/src/x11/window/mod.rs b/src/x11/window/mod.rs index f4c296a1..d3c5163d 100644 --- a/src/x11/window/mod.rs +++ b/src/x11/window/mod.rs @@ -298,7 +298,7 @@ impl Window { // creating GL context - let context = unsafe { + let (context, extra_functions) = unsafe { let mut attributes = Vec::new(); if builder.gl_version.is_some() { @@ -345,9 +345,52 @@ impl Window { return Err(OsError(format!("GL context creation failed"))); } - context + (context, extra_functions) }; + // vsync + if builder.vsync { + unsafe { ffi::glx::MakeCurrent(display, window, context) }; + + if extra_functions.SwapIntervalEXT.is_loaded() { + // this should be the most common extension + unsafe { + extra_functions.SwapIntervalEXT(display as *mut _, window, 1); + } + + // checking that it worked + if builder.strict { + let mut swap = unsafe { mem::uninitialized() }; + unsafe { + ffi::glx::QueryDrawable(display, window, + ffi::glx_extra::SWAP_INTERVAL_EXT as i32, + &mut swap); + } + + if swap != 1 { + return Err(OsError(format!("Couldn't setup vsync: expected \ + interval `1` but got `{}`", swap))); + } + } + + // GLX_MESA_swap_control is not official + /*} else if extra_functions.SwapIntervalMESA.is_loaded() { + unsafe { + extra_functions.SwapIntervalMESA(1); + }*/ + + } else if extra_functions.SwapIntervalSGI.is_loaded() { + unsafe { + extra_functions.SwapIntervalSGI(1); + } + + } else if builder.strict { + return Err(OsError(format!("Couldn't find any available vsync extension"))); + } + + unsafe { ffi::glx::MakeCurrent(display, 0, ptr::null()) }; + } + // creating the window object let window = Window { x: Arc::new(XWindow {