Disable vsync when benchmarking

Description

OpenGL usually uses double-buffering.

Some OpenGL configurations enable vsync by default.

Vsync limits how fast we can render. Wait for the next frame.

Disabling vsync can cause wasted work (rendering a frame that will never be displayed), but also avoids input latency.

TODO

Commands

git clone git@github.com:atsheehan/iridium
cd iridium
git checkout 74ad215fa2ec22b00d2360f31905f339219a9ac5
cargo run --release

Code Changes

Modified src/main.rsGitHub

@@ -22,7 +22,7 @@
2222 let options = get_options();
2323
2424 let event_loop = EventLoop::new().unwrap();
25- let mut renderer = Renderer::new(&event_loop, options.windowed);
25+ let mut renderer = Renderer::new(&event_loop, options.windowed, options.disable_vsync);
2626
2727 let mut world = World::new(256, 32, 256);
2828 renderer.update_block_cache(world.block_positions());
@@ -131,10 +131,15 @@
131131
132132 struct GameOptions {
133133 windowed: bool,
134+ disable_vsync: bool,
134135 }
135136
136137 fn get_options() -> GameOptions {
137138 let args: Vec<String> = std::env::args().collect();
138139 let windowed = args.iter().any(|arg| arg == "-w" || arg == "--windowed");
139- GameOptions { windowed }
140+ let disable_vsync = args.iter().any(|arg| arg == "-v" || arg == "--no-vsync");
141+ GameOptions {
142+ windowed,
143+ disable_vsync,
144+ }
140145 }
@@ -22,7 +22,7 @@
22 let options = get_options();
23
24 let event_loop = EventLoop::new().unwrap();
25- let mut renderer = Renderer::new(&event_loop, options.windowed);
26
27 let mut world = World::new(256, 32, 256);
28 renderer.update_block_cache(world.block_positions());
@@ -131,10 +131,15 @@
131
132 struct GameOptions {
133 windowed: bool,
 
134 }
135
136 fn get_options() -> GameOptions {
137 let args: Vec<String> = std::env::args().collect();
138 let windowed = args.iter().any(|arg| arg == "-w" || arg == "--windowed");
139- GameOptions { windowed }
 
 
 
 
140 }
@@ -22,7 +22,7 @@
22 let options = get_options();
23
24 let event_loop = EventLoop::new().unwrap();
25+ let mut renderer = Renderer::new(&event_loop, options.windowed, options.disable_vsync);
26
27 let mut world = World::new(256, 32, 256);
28 renderer.update_block_cache(world.block_positions());
@@ -131,10 +131,15 @@
131
132 struct GameOptions {
133 windowed: bool,
134+ disable_vsync: bool,
135 }
136
137 fn get_options() -> GameOptions {
138 let args: Vec<String> = std::env::args().collect();
139 let windowed = args.iter().any(|arg| arg == "-w" || arg == "--windowed");
140+ let disable_vsync = args.iter().any(|arg| arg == "-v" || arg == "--no-vsync");
141+ GameOptions {
142+ windowed,
143+ disable_vsync,
144+ }
145 }

Modified src/render.rsGitHub

@@ -2,6 +2,7 @@
22 collections::HashMap,
33 ffi::{c_void, CString},
44 fmt::Display,
5+ num::NonZeroU32,
56 };
67
78 use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint};
@@ -10,7 +11,7 @@
1011 context::{ContextApi, ContextAttributesBuilder, PossiblyCurrentContext, Version},
1112 display::GetGlDisplay,
1213 prelude::{GlDisplay, NotCurrentGlContext},
13- surface::{GlSurface, Surface, SurfaceAttributesBuilder, WindowSurface},
14+ surface::{GlSurface, Surface, SurfaceAttributesBuilder, SwapInterval, WindowSurface},
1415 };
1516 use glutin_winit::{DisplayBuilder, GlWindow};
1617 use raw_window_handle::HasRawWindowHandle;
@@ -44,7 +45,7 @@
4445 }
4546
4647 impl Renderer {
47- pub(crate) fn new(event_loop: &EventLoop<()>, windowed: bool) -> Self {
48+ pub(crate) fn new(event_loop: &EventLoop<()>, windowed: bool, disable_vsync: bool) -> Self {
4849 let fullscreen_option = if windowed {
4950 None
5051 } else {
@@ -85,6 +86,14 @@
8586 .unwrap()
8687 };
8788
89+ let swap_interval = if disable_vsync {
90+ SwapInterval::DontWait
91+ } else {
92+ SwapInterval::Wait(NonZeroU32::new(1).unwrap())
93+ };
94+
95+ surface.set_swap_interval(&context, swap_interval).unwrap();
96+
8897 gl::load_with(|s| display.get_proc_address(&CString::new(s).unwrap()));
8998
9099 let cube_program =
@@ -2,6 +2,7 @@
2 collections::HashMap,
3 ffi::{c_void, CString},
4 fmt::Display,
 
5 };
6
7 use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint};
@@ -10,7 +11,7 @@
10 context::{ContextApi, ContextAttributesBuilder, PossiblyCurrentContext, Version},
11 display::GetGlDisplay,
12 prelude::{GlDisplay, NotCurrentGlContext},
13- surface::{GlSurface, Surface, SurfaceAttributesBuilder, WindowSurface},
14 };
15 use glutin_winit::{DisplayBuilder, GlWindow};
16 use raw_window_handle::HasRawWindowHandle;
@@ -44,7 +45,7 @@
44 }
45
46 impl Renderer {
47- pub(crate) fn new(event_loop: &EventLoop<()>, windowed: bool) -> Self {
48 let fullscreen_option = if windowed {
49 None
50 } else {
@@ -85,6 +86,14 @@
85 .unwrap()
86 };
87
 
 
 
 
 
 
 
 
88 gl::load_with(|s| display.get_proc_address(&CString::new(s).unwrap()));
89
90 let cube_program =
@@ -2,6 +2,7 @@
2 collections::HashMap,
3 ffi::{c_void, CString},
4 fmt::Display,
5+ num::NonZeroU32,
6 };
7
8 use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint};
@@ -10,7 +11,7 @@
11 context::{ContextApi, ContextAttributesBuilder, PossiblyCurrentContext, Version},
12 display::GetGlDisplay,
13 prelude::{GlDisplay, NotCurrentGlContext},
14+ surface::{GlSurface, Surface, SurfaceAttributesBuilder, SwapInterval, WindowSurface},
15 };
16 use glutin_winit::{DisplayBuilder, GlWindow};
17 use raw_window_handle::HasRawWindowHandle;
@@ -44,7 +45,7 @@
45 }
46
47 impl Renderer {
48+ pub(crate) fn new(event_loop: &EventLoop<()>, windowed: bool, disable_vsync: bool) -> Self {
49 let fullscreen_option = if windowed {
50 None
51 } else {
@@ -85,6 +86,14 @@
86 .unwrap()
87 };
88
89+ let swap_interval = if disable_vsync {
90+ SwapInterval::DontWait
91+ } else {
92+ SwapInterval::Wait(NonZeroU32::new(1).unwrap())
93+ };
94+
95+ surface.set_swap_interval(&context, swap_interval).unwrap();
96+
97 gl::load_with(|s| display.get_proc_address(&CString::new(s).unwrap()));
98
99 let cube_program =