Search code examples
rustgame-loopglium

Set frame redraw rate in glium?


I am trying to make a game loop using glium in rust. My goal is to get the screen to redraw 60 times per second. With the current event loop code I have, the frame only gets redrawn when the window size changes. I read in the glutin docs, that I need to call request_redraw somewhere, but I'm not sure how/where. This is my code so far:

event_loop.run(move |event, _target, control_flow| match event {
    Event::LoopDestroyed => return,
    Event::WindowEvent {
        window_id: _window_id,
        event: winevent,
    } => match winevent {
        WindowEvent::Resized(physical_size) => display.gl_window().resize(physical_size),
        WindowEvent::CloseRequested => {
            *control_flow = ControlFlow::Exit;
        }
        _ => {}
    },
    Event::RedrawRequested(_window_id) => {
        let mut target = display.draw();
        target.clear_color_srgb(rng.gen(), rng.gen(), rng.gen(), 1.0);
        target.finish().unwrap();
    }
    _ => {}
});

Solution

  • I haven't used glium before (I've been making some graphics applications directly off of Vulkano for a while). However, perusing the API, it seems you can get your Window handle from winit by going through a series of apis. I outlined them in the below code. Something like the below should work for you. The key is getting access to the Window handle from winit. Scrolling through the Window API you should see this: request_redraw. You can then insert game-loop logic around your event handler like this:

    use std::time::Instant;
    use glium::Display;
    use winit::event_loop::{EventLoop, ControlFlow};
    use winit::event::{Event, WindowEvent};
    use winit::window::Window;
    
    const TARGET_FPS: u64 = 60;
    
    /* ... some function for main loop ... */
    
    let display: Display = ... /* glium Display instance */
    
    event_loop.run(move |event, _target, control_flow| {
        let start_time = Instant::now();
        match event {
            Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
                *control_flow = ControlFlow::Exit;
            },
            ...
        /*
         * Process events here
         */
        }
        match *control_flow {
            ControlFlow::Exit => (),
            _ => {
                /*
                 * Grab window handle from the display (untested - based on API)
                 */
                display.gl_window().window().request_redraw();
                /*
                 * Below logic to attempt hitting TARGET_FPS.
                 * Basically, sleep for the rest of our milliseconds
                 */
                let elapsed_time = Instant::now().duration_since(start_time).as_millis() as u64;
    
                let wait_millis = match 1000 / TARGET_FPS >= elapsed_time {
                    true => 1000 / TARGET_FPS - elapsed_time,
                    false => 0
                };
                let new_inst = start_time + std::time::Duration::from_millis(wait_millis);
                *control_flow = ControlFlow::WaitUntil(new_inst);
            }
        }
    });