Skip to content

Commit ac1e062

Browse files
committed
fix framerate setting and vsync
1 parent 3aad93a commit ac1e062

File tree

4 files changed

+113
-16
lines changed

4 files changed

+113
-16
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ chrono = "0.4"
3030
home = "0.5"
3131
flexi_logger = { version = "0.29", default-features = false }
3232
glium = "0.36"
33+
glutin-winit = "0.5"
3334
image = { version = "0.25", default-features = false, features = [ "png" ] }
3435
indexmap = "2"
3536
lazy_static = "1"

sulis_core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ home = { workspace = true }
1212
flexi_logger = { workspace = true }
1313
image = { workspace = true }
1414
glium = { workspace = true }
15+
glutin-winit = { workspace = true }
1516
lazy_static = { workspace = true }
1617
log = { workspace = true }
1718
rand = { workspace = true }

sulis_core/src/io/glium_adapter.rs

Lines changed: 110 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
// You should have received a copy of the GNU General Public License
1515
// along with Sulis. If not, see <http://www.gnu.org/licenses/>
1616

17+
use std::num::NonZeroU32;
1718
use std::time;
1819
use std::collections::HashMap;
1920
use std::error::Error;
@@ -25,11 +26,16 @@ use crate::resource::ResourceSet;
2526
use crate::ui::{Cursor, Widget};
2627
use crate::util::{Point, get_elapsed_millis};
2728

29+
use glium::glutin::context::ContextAttributesBuilder;
30+
use glium::glutin::display::GetGlDisplay;
31+
use glium::glutin::prelude::{GlDisplay, NotCurrentGlContext};
2832
use glium::winit::application::ApplicationHandler;
29-
use glium::CapabilitiesSource;
33+
use glium::winit::raw_window_handle::{HandleError, HasWindowHandle};
34+
use glium::{CapabilitiesSource, Display};
3035
use glium::backend::Facade;
36+
use glium::backend::glutin::simple_window_builder::GliumEventLoop;
3137
use glium::glutin::config::{ColorBufferType, ConfigTemplateBuilder};
32-
use glium::glutin::surface::WindowSurface;
38+
use glium::glutin::surface::{GlSurface, SurfaceAttributesBuilder, SwapInterval, WindowSurface};
3339
use glium::texture::{RawImage2d, Texture2d};
3440
use glium::uniforms::{MagnifySamplerFilter, MinifySamplerFilter, Sampler};
3541
use glium::winit::dpi::{LogicalPosition, LogicalSize};
@@ -39,6 +45,7 @@ use glium::winit::window::{Fullscreen, Window, WindowId};
3945
use glium::winit::keyboard::{KeyCode, PhysicalKey};
4046
use glium::winit::event::{ElementState, KeyEvent, MouseButton, MouseScrollDelta, StartCause, WindowEvent};
4147
use glium::{self, Rect, Surface};
48+
use glutin_winit::DisplayBuilder;
4249

4350
const VERTEX_SHADER_SRC: &str = r#"
4451
#version 140
@@ -345,9 +352,53 @@ fn get_monitor(window: &Window) -> MonitorHandle {
345352
window.primary_monitor().unwrap()
346353
}
347354

355+
#[derive(Debug)]
356+
pub enum DisplayCreationError {
357+
CreateWindow,
358+
BuildDisplayError(Box<dyn Error>),
359+
WindowHandle(HandleError),
360+
WindowSurface(glium::glutin::error::Error),
361+
GlContext(glium::glutin::error::Error),
362+
GlContextCurrent(glium::glutin::error::Error),
363+
GlVersion(glium::IncompatibleOpenGl),
364+
SetVsync(glium::glutin::error::Error),
365+
}
366+
367+
impl std::fmt::Display for DisplayCreationError {
368+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
369+
use DisplayCreationError::*;
370+
match self {
371+
CreateWindow => write!(f, "Unable to create display"),
372+
BuildDisplayError(e) => write!(f, "Build display error: {e}"),
373+
WindowHandle(e) => write!(f, "Unable to get window handle {e}"),
374+
WindowSurface(e) => write!(f, "Unable to setup window surface {e}"),
375+
GlContext(e) => write!(f, "Unable to create GL context {e}"),
376+
GlContextCurrent(e) => write!(f, "Unable to make GL context current {e}"),
377+
GlVersion(e) => write!(f, "GL Version incompatible: {e}"),
378+
SetVsync(e) => write!(f, "Unable to set vsync mode: {e}"),
379+
}
380+
}
381+
}
382+
383+
impl Error for DisplayCreationError {
384+
fn source(&self) -> Option<&(dyn Error + 'static)> {
385+
use DisplayCreationError::*;
386+
match self {
387+
CreateWindow => None,
388+
BuildDisplayError(e) => Some(e.as_ref()),
389+
WindowHandle(e) => Some(e),
390+
WindowSurface(e) => Some(e),
391+
GlContext(e) => Some(e),
392+
GlContextCurrent(e) => Some(e),
393+
GlVersion(e) => Some(e),
394+
SetVsync(e) => Some(e),
395+
}
396+
}
397+
}
398+
348399
fn try_get_display(
349400
event_loop: &EventLoop<()>,
350-
) -> Result<(glium::Display<WindowSurface>, Window), glium::backend::glutin::DisplayCreationError> {
401+
) -> Result<(glium::Display<WindowSurface>, Window), DisplayCreationError> {
351402
let (res_x, res_y) = Config::display_resolution();
352403
let vsync = Config::vsync_enabled();
353404

@@ -363,10 +414,45 @@ fn try_get_display(
363414
.with_alpha_size(8)
364415
.with_buffer_type(ColorBufferType::Rgb { r_size: 8, g_size: 8, b_size: 8 });
365416

366-
let (window, display) = glium::backend::glutin::SimpleWindowBuilder::new()
367-
.set_window_builder(attrs)
368-
.with_config_template_builder(config_template_builder)
369-
.build(event_loop);
417+
let display_builder = DisplayBuilder::new().with_window_attributes(Some(attrs));
418+
419+
let (window, gl_config) = event_loop.build(display_builder, config_template_builder, |mut configs| {
420+
configs.next().unwrap()
421+
}).map_err(DisplayCreationError::BuildDisplayError)?;
422+
423+
let window = match window {
424+
None => return Err(DisplayCreationError::CreateWindow),
425+
Some(window) => window,
426+
};
427+
428+
let handle = window.window_handle().map_err(DisplayCreationError::WindowHandle)?;
429+
430+
let (w, h): (u32, u32) = window.inner_size().into();
431+
432+
let surface_attrs = SurfaceAttributesBuilder::<WindowSurface>::new()
433+
.build(handle.into(), NonZeroU32::new(w).unwrap(), NonZeroU32::new(h).unwrap());
434+
435+
let surface = unsafe {
436+
gl_config.display().create_window_surface(&gl_config, &surface_attrs).map_err(DisplayCreationError::WindowSurface)?
437+
};
438+
439+
let swap_interval = if vsync {
440+
SwapInterval::Wait(NonZeroU32::new(1).unwrap())
441+
} else {
442+
SwapInterval::DontWait
443+
};
444+
445+
let context_attributes = ContextAttributesBuilder::new().build(Some(handle.into()));
446+
447+
let context = unsafe {
448+
gl_config.display().create_context(&gl_config, &context_attributes).map_err(DisplayCreationError::GlContext)?
449+
};
450+
451+
let current_context = context.make_current(&surface).map_err(DisplayCreationError::GlContextCurrent)?;
452+
453+
surface.set_swap_interval(&current_context, swap_interval).map_err(DisplayCreationError::SetVsync)?;
454+
455+
let display = Display::from_context_surface(current_context, surface).map_err(DisplayCreationError::GlVersion)?;
370456

371457
Ok((display, window))
372458
}
@@ -573,14 +659,19 @@ struct GliumApp {
573659
impl ApplicationHandler for GliumApp {
574660
fn resumed(&mut self, _event_loop: &ActiveEventLoop) { }
575661

576-
fn new_events(&mut self, _event_loop: &ActiveEventLoop, _cause: StartCause) {
577-
self.last_elapsed = get_elapsed_millis(self.last_start_time.elapsed());
578-
self.last_start_time = time::Instant::now();
579-
self.total_elapsed = get_elapsed_millis(self.main_loop_start_time.elapsed());
662+
fn new_events(&mut self, _event_loop: &ActiveEventLoop, cause: StartCause) {
663+
if Config::vsync_enabled() {
664+
self.io.window.request_redraw();
665+
}
666+
667+
if let StartCause::ResumeTimeReached { .. } = cause {
668+
self.io.window.request_redraw();
669+
}
580670
}
581671

582672
fn exiting(&mut self, _event_loop: &ActiveEventLoop) {
583673
let secs = self.render_time.as_secs() as f64 + self.render_time.subsec_nanos() as f64 * 1e-9;
674+
log::info!("Runtime: {:.2} seconds", (time::Instant::now() - self.main_loop_start_time).as_secs_f32());
584675
info!(
585676
"Rendered {} frames with total render time {:.4} seconds",
586677
self.frames, secs
@@ -591,10 +682,6 @@ impl ApplicationHandler for GliumApp {
591682
);
592683
}
593684

594-
fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) {
595-
self.io.window.request_redraw();
596-
}
597-
598685
fn window_event(
599686
&mut self,
600687
event_loop: &ActiveEventLoop,
@@ -612,6 +699,10 @@ impl ApplicationHandler for GliumApp {
612699
event_loop.exit();
613700
},
614701
WindowEvent::RedrawRequested => {
702+
self.last_elapsed = get_elapsed_millis(self.last_start_time.elapsed());
703+
self.last_start_time = time::Instant::now();
704+
self.total_elapsed = get_elapsed_millis(self.main_loop_start_time.elapsed());
705+
615706
// merge all mouse move events into at most one per frame
616707
if let Some((mouse_x, mouse_y)) = self.mouse_move {
617708
InputAction::mouse_move(mouse_x, mouse_y).handle(&self.root);
@@ -644,7 +735,10 @@ impl ApplicationHandler for GliumApp {
644735

645736
self.render_time += self.last_start_time.elapsed();
646737
self.frames += 1;
647-
event_loop.set_control_flow(ControlFlow::WaitUntil(time::Instant::now() + self.frame_time));
738+
739+
if !Config::vsync_enabled() {
740+
event_loop.set_control_flow(ControlFlow::WaitUntil(self.last_start_time + self.frame_time));
741+
}
648742
},
649743
WindowEvent::CursorMoved { position, .. } => {
650744
let mouse_x = (self.ui_x as f64 * position.x / self.display_size.width) as f32 / self.scale as f32;

0 commit comments

Comments
 (0)