rustframe-rateglium

FPS locked to 61 in glium


As I was messing around with Glium, I made an FPS counter to appear in the terminal, but it seems locked to 61 FPS.

I tried lowering the number of rendered objects, but the result was the same. At first, I thought it was somewhat related to my 60Hz monitor or some embedded VSync feature in glium, but I recently changed my monitor, and the result was the same.]

let mut start = Instant::now();

    let mut elapsed = start.elapsed();
    let mut frame_counter = 0;



    #[allow(deprecated)]
    event_loop.run(move |ev, window_target| {
        match ev {
            glium::winit::event::Event::WindowEvent { event, .. } => match event {
                glium::winit::event::WindowEvent::CloseRequested => {
                    window_target.exit();
                },
                glium::winit::event::WindowEvent::RedrawRequested => {
// frame counter code
                    frame_counter += 1;
                    elapsed = start.elapsed();

                    if elapsed.as_millis() > 1000{
                        println!("{}", frame_counter);
                        frame_counter = 0;
                        start = Instant::now();
                    }
// drawing objects 

                    let mut target = display.draw();
                    target.clear_color(0.0, 0.05, 0.1, 1.0);

                    let uniforms = uniform! {
                        matrix: player.get_matrix(),
                        tex: player.texture
                    };

                    target.draw(&vertex_buffer, &indices, &program, &uniforms,
                                &Default::default()).unwrap();
    
                    target.finish().unwrap();
                },
// ...
         _ => (),
        }})
    .unwrap();

Solution

  • It is possible that glium is incorrectly inferring your display's refresh rate - the following fix/es worked to uncap the framerate from 60hz for me.

    It looks like glium isn't actively maintained. There are merged pull requests here and here to expose the ability to disable vsync, but the crate hasn't been updated to reflect the source changes (in fact, the last crates.io update appears to have happened 2 days before #2131 was merged!).

    To fix this, you will need to depend on the git version of glium. In your Cargo.toml, replace

    glium = "0.36.0"
    

    with

    glium = { git = "https://github.com/glium/glium.git" }
    

    Then, you will be able to call SimpleWindowBuilder::with_vsync(false) or Display::set_swap_interval(SwapInterval::DontWait).

    If you cannot depend on the git version of glium, you could also implement the SimpleWindowBuilder disable-vsync functionality yourself:

    use glium::{
        Display,
        backend::glutin::simple_window_builder::GliumEventLoop,
        glutin::{
            config::ConfigTemplateBuilder,
            display::GetGlDisplay as _,
            prelude::{GlDisplay as _, NotCurrentGlContext as _},
            surface::{GlSurface as _, SurfaceAttributesBuilder, SwapInterval, WindowSurface},
        },
        winit::{event_loop::EventLoop, raw_window_handle::HasWindowHandle as _, window::Window},
    };
    use glutin_winit::DisplayBuilder;
    
    fn create_context(event_loop: &EventLoop<()>) -> (Window, Display<WindowSurface>) {
        let display_builder = DisplayBuilder::new().with_window_attributes(Some(
            Window::default_attributes()
                .with_title("Simple Glium Window")
                .with_inner_size(glium::winit::dpi::PhysicalSize::new(800, 480)),
        ));
        let config_template_builder = ConfigTemplateBuilder::new();
        let (window, gl_config) = event_loop
            .build(display_builder, config_template_builder, |mut configs| {
                // Just use the first configuration since we don't have any special preferences
                // here
                configs.next().unwrap()
            })
            .unwrap();
    
        let window = window.unwrap();
    
        let (width, height): (u32, u32) = window.inner_size().into();
        let attrs = SurfaceAttributesBuilder::<WindowSurface>::new().build(
            window
                .window_handle()
                .expect("couldn't obtain raw window handle")
                .into(),
            std::num::NonZeroU32::new(width).unwrap(),
            std::num::NonZeroU32::new(height).unwrap(),
        );
    
        let surface = unsafe {
            gl_config
                .display()
                .create_window_surface(&gl_config, &attrs)
                .unwrap()
        };
        let context_attributes = glium::glutin::context::ContextAttributesBuilder::new().build(Some(
            window
                .window_handle()
                .expect("couldn't obtain raw window handle")
                .into(),
        ));
        let current_context = Some(unsafe {
            gl_config
                .display()
                .create_context(&gl_config, &context_attributes)
                .expect("failed to create context")
        })
        .unwrap()
        .make_current(&surface)
        .unwrap();
    
        // Finally we can set the swap interval
        surface
            .set_swap_interval(&current_context, SwapInterval::DontWait)
            .unwrap();
    
        let display = Display::from_context_surface(current_context, surface).unwrap();
    
        (window, display)
    }
    

    The swap interval is set right at the very bottom - the rest of the logic is straight from SimpleWindowBuilder::build().

    You will also need to add the following to your Cargo.toml for DisplayBuilder:

    glium-winit = "0.5.0"