Skip to content

Commit d8882c9

Browse files
committed
retrofit to singlethread
1 parent fed8209 commit d8882c9

File tree

8 files changed

+152
-139
lines changed

8 files changed

+152
-139
lines changed

cfg/engine.cfg

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,8 @@
22
fps 60 # Currently only used by step_simulation
33
smooth_by_extrapolating_velocity true
44

5+
/engine/debug
6+
extra_frame_sleep_ms 0
7+
58
/engine/gameplay
6-
gameplay_update_tick_ms 10.0
9+
gameplay_update_tick_ms 10

flamegraph.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ APP=ecs
44

55
declare -r F=/usr/local/src/FlameGraph
66
set -x
7-
./$APP $@ &>/dev/null&
8-
sudo perf record -F 80 -a -g -p $! -- sleep 60
7+
./target/debug/$APP $@ &>/dev/null&
8+
sudo perf record -F 80 -a -g -p $! -- sleep 30
99
sudo perf script > /tmp/out.perf
1010
$F/stackcollapse-perf.pl /tmp/out.perf > /tmp/out.folded
1111
$F/flamegraph.pl /tmp/out.folded > /tmp/out.svg

src/cfg/mod.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ impl Config {
6161
for entry in section.entries.into_iter() {
6262
let name = format!("{}/{}", section.header, entry.key);
6363
let id = String_Id::from(name.as_str());
64+
eprintln!("Loading cfg var {} = {:?}", name, entry.value);
6465
match entry.value {
6566
Cfg_Value::Bool(v) => {
6667
bool_vars.insert(id, Rc::new(RefCell::new(v)));
@@ -118,7 +119,7 @@ impl Config {
118119
var
119120
} else {
120121
eprintln!(
121-
"Notice: could not find cfg_var {}: using default {}",
122+
"Notice: could not find bool cfg_var {}: using default {}",
122123
path, default
123124
);
124125
Cfg_Var::new_from_val(default)
@@ -131,7 +132,7 @@ impl Config {
131132
var
132133
} else {
133134
eprintln!(
134-
"Notice: could not find cfg_var {}: using default {}",
135+
"Notice: could not find int cfg_var {}: using default {}",
135136
path, default
136137
);
137138
Cfg_Var::new_from_val(default)
@@ -144,7 +145,7 @@ impl Config {
144145
var
145146
} else {
146147
eprintln!(
147-
"Notice: could not find cfg_var {}: using default {}",
148+
"Notice: could not find float cfg_var {}: using default {}",
148149
path, default
149150
);
150151
Cfg_Var::new_from_val(default)
@@ -157,7 +158,7 @@ impl Config {
157158
var
158159
} else {
159160
eprintln!(
160-
"Notice: could not find cfg_var {}: using default {}",
161+
"Notice: could not find string cfg_var {}: using default {}",
161162
path, default
162163
);
163164
Cfg_Var::new_from_val(String::from(default))

src/core/app.rs

+98-92
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use std::convert::TryFrom;
1818
use std::sync::mpsc;
1919
use std::thread::JoinHandle;
2020
use std::time::Duration;
21+
use std::time::SystemTime;
2122

2223
pub struct App_Config {
2324
pub title: String,
@@ -59,15 +60,17 @@ pub struct App<'r> {
5960
env: Env_Info,
6061

6162
config: cfg::Config,
62-
ui_req_tx: Option<mpsc::Sender<gfx::ui::UI_Request>>,
63+
ui_req_tx: mpsc::Sender<gfx::ui::UI_Request>,
6364

6465
// Resources
66+
gfx_resources: resources::gfx::Gfx_Resources<'r>,
6567
audio_resources: resources::audio::Audio_Resources<'r>,
6668

6769
// Engine Systems
68-
render_thread: Option<JoinHandle<()>>,
69-
render_thread_quit: Option<mpsc::Sender<()>>,
70-
input_actions_rx: Option<mpsc::Receiver<input::Action_List>>,
70+
input_system: input::Input_System,
71+
input_actions_rx: mpsc::Receiver<input::Action_List>,
72+
render_system: gfx::render_system::Render_System,
73+
ui_system: gfx::ui::UI_System,
7174
audio_system: audio::system::Audio_System,
7275
gameplay_system: gameplay_system::Gameplay_System,
7376
}
@@ -77,16 +80,21 @@ impl<'r> App<'r> {
7780
let env = Env_Info::gather().unwrap();
7881
let config = cfg::Config::new_from_dir(env.get_cfg_root());
7982

83+
let (input_tx, input_rx) = mpsc::channel();
84+
let (ui_tx, ui_rx) = mpsc::channel();
85+
8086
App {
8187
time: time::Time::new(),
8288
should_close: false,
8389
env,
8490
config,
85-
ui_req_tx: None,
91+
ui_req_tx: ui_tx,
92+
input_system: input::Input_System::new(input_tx),
93+
input_actions_rx: input_rx,
94+
gfx_resources: resources::gfx::Gfx_Resources::new(),
8695
audio_resources: resources::audio::Audio_Resources::new(sound_loader),
87-
render_thread: None,
88-
render_thread_quit: None,
89-
input_actions_rx: None,
96+
render_system: gfx::render_system::Render_System::new(),
97+
ui_system: gfx::ui::UI_System::new(ui_rx),
9098
audio_system: audio::system::Audio_System::new(10),
9199
gameplay_system: gameplay_system::Gameplay_System::new(),
92100
}
@@ -111,116 +119,89 @@ impl<'r> App<'r> {
111119
vec![config_watcher],
112120
)?;
113121

114-
Ok(())
115-
}
122+
self.gameplay_system
123+
.init(&mut self.gfx_resources, &self.env, &self.config)?;
124+
self.render_system
125+
.init(gfx::render_system::Render_System_Config {
126+
clear_color: colors::rgb(22, 0, 22),
127+
})?;
116128

117-
fn start_render_thread(
118-
&mut self,
119-
entity_transform_rx: mpsc::Receiver<(Entity, C_Transform2D)>,
120-
camera_transform_rx: mpsc::Receiver<C_Camera2D>,
121-
) {
122-
let (input_tx, input_rx) = mpsc::channel();
123-
self.input_actions_rx = Some(input_rx);
124-
125-
let (ui_tx, ui_rx) = mpsc::channel();
126-
self.ui_req_tx = Some(ui_tx);
127-
128-
let (quit_tx, quit_rx) = mpsc::channel();
129-
self.render_thread_quit = Some(quit_tx);
130-
131-
self.render_thread = Some(gfx::render_system::start_render_thread(
132-
self.env.clone(),
133-
input_tx,
134-
ui_rx,
135-
entity_transform_rx,
136-
camera_transform_rx,
137-
quit_rx,
138-
gfx::render_system::Render_System_Config {
139-
clear_color: colors::rgb(48, 10, 36),
140-
},
141-
));
129+
Ok(())
142130
}
143131

144-
pub fn run(&mut self) -> Maybe_Error {
145-
let (et_tx, et_rx) = mpsc::channel();
146-
let (cam_tx, cam_rx) = mpsc::channel();
147-
self.gameplay_system.init(&self.config, et_tx, cam_tx)?; // @Temporary workaround
148-
self.start_render_thread(et_rx, cam_rx);
149-
150-
self.start_game_loop()?;
132+
pub fn run(&mut self, window: &mut gfx::window::Window_Handle) -> Maybe_Error {
133+
self.start_game_loop(window)?;
151134
Ok(())
152135
}
153136

154-
fn start_game_loop(&mut self) -> Maybe_Error {
137+
fn start_game_loop(&mut self, window: &mut gfx::window::Window_Handle) -> Maybe_Error {
155138
let mut fps_debug = debug::fps::Fps_Console_Printer::new(&Duration::from_secs(3), "main");
156-
let input_actions_rx = self.input_actions_rx.take().unwrap();
157139
let mut execution_time = Duration::new(0, 0);
158140

159141
while !self.should_close {
160-
let frame_start_t = std::time::SystemTime::now();
161-
162142
// Update time
163143
self.time.update();
164144

165145
let dt = self.time.dt();
166-
167-
let update_time = Duration::from_nanos(
168-
(*self
146+
let real_dt = self.time.real_dt();
147+
let update_time = Duration::from_millis(
148+
*self
169149
.config
170-
.get_var_float_or("engine/gameplay/gameplay_update_tick_ms", 10.0)
171-
* 1_000_000.0) as u64,
150+
.get_var_int_or("engine/gameplay/gameplay_update_tick_ms", 10)
151+
as u64,
172152
);
173153

174-
// Update input
175-
// Note: due to SFML limitations, the event loop is run on the render thread.
176-
let actions = if let Ok(new_actions) = input_actions_rx.try_recv() {
177-
new_actions
178-
} else {
179-
input::Action_List::default()
180-
};
154+
execution_time += dt;
181155

156+
// Update input
157+
self.input_system.update(window);
158+
let actions = self.input_system.get_action_list();
182159
self.handle_actions(&actions)?;
183160

184-
execution_time += dt;
185-
161+
// Update game systems
162+
let gameplay_start_t = SystemTime::now();
186163
while execution_time > update_time {
187-
// Update game systems
188164
self.update_game_systems(update_time, &actions)?;
189165
execution_time -= update_time;
190166
}
167+
println!(
168+
"Gameplay: {} ms",
169+
SystemTime::now()
170+
.duration_since(gameplay_start_t)
171+
.unwrap()
172+
.as_millis()
173+
);
191174

192175
// Update audio
193176
self.audio_system.update();
194177

195-
self.config.update();
196-
197-
let frame_duration = std::time::SystemTime::now()
198-
.duration_since(frame_start_t)
199-
.unwrap();
200-
201-
fps_debug.tick(&self.time.real_dt());
178+
// Render
179+
let render_start_t = SystemTime::now();
180+
self.update_graphics(
181+
window,
182+
real_dt,
183+
time::duration_ratio(&execution_time, &update_time) as f32,
184+
)?;
185+
println!(
186+
"Render: {} ms",
187+
SystemTime::now()
188+
.duration_since(render_start_t)
189+
.unwrap()
190+
.as_millis()
191+
);
202192

203-
if frame_duration < update_time {
204-
std::thread::sleep(update_time - frame_duration);
205-
} else {
206-
eprintln!(
207-
"[ WARNING ] Game loop took {} ms, which is more than the requested {} ms.",
208-
frame_duration.as_millis(),
209-
update_time.as_millis()
210-
);
193+
#[cfg(debug_assertions)]
194+
{
195+
let sleep = *self
196+
.config
197+
.get_var_int_or("engine/debug/extra_frame_sleep_ms", 0)
198+
as u64;
199+
std::thread::sleep(Duration::from_millis(sleep));
211200
}
212-
}
213201

214-
self.render_thread_quit
215-
.as_mut()
216-
.unwrap()
217-
.send(())
218-
.expect("[ ERR ] Failed to send quit message to render thread!");
219-
self.render_thread
220-
.take()
221-
.unwrap()
222-
.join()
223-
.expect("[ ERR ] Failed to join render thread!");
202+
self.config.update();
203+
fps_debug.tick(&dt);
204+
}
224205

225206
Ok(())
226207
}
@@ -231,12 +212,37 @@ impl<'r> App<'r> {
231212
Ok(())
232213
}
233214

215+
fn update_graphics(
216+
&mut self,
217+
window: &mut gfx::window::Window_Handle,
218+
real_dt: Duration,
219+
frame_lag_normalized: f32,
220+
) -> Maybe_Error {
221+
let smooth_by_extrapolating_velocity = *self
222+
.config
223+
.get_var_bool_or("engine/rendering/smooth_by_extrapolating_velocity", false);
224+
225+
gfx::window::set_clear_color(window, colors::rgb(0, 0, 0));
226+
gfx::window::clear(window);
227+
self.render_system.update(
228+
window,
229+
&self.gfx_resources,
230+
&self.gameplay_system.get_camera(),
231+
&self.gameplay_system.get_renderable_entities(),
232+
frame_lag_normalized,
233+
smooth_by_extrapolating_velocity,
234+
);
235+
self.ui_system
236+
.update(&real_dt, window, &mut self.gfx_resources);
237+
gfx::window::display(window);
238+
239+
Ok(())
240+
}
241+
234242
fn handle_actions(&mut self, actions: &input::Action_List) -> Maybe_Error {
235243
use gfx::ui::UI_Request;
236244
use input::Action;
237245

238-
let ui_req_tx = self.ui_req_tx.as_ref().unwrap();
239-
240246
if actions.has_action(&Action::Quit) {
241247
self.should_close = true;
242248
} else {
@@ -247,7 +253,7 @@ impl<'r> App<'r> {
247253
if ts > 0.0 {
248254
self.time.set_time_scale(ts);
249255
}
250-
ui_req_tx
256+
self.ui_req_tx
251257
.send(UI_Request::Add_Fadeout_Text(format!(
252258
"Time scale: {:.2}",
253259
self.time.get_time_scale()
@@ -256,7 +262,7 @@ impl<'r> App<'r> {
256262
}
257263
Action::Pause_Toggle => {
258264
self.time.set_paused(!self.time.is_paused());
259-
ui_req_tx
265+
self.ui_req_tx
260266
.send(UI_Request::Add_Fadeout_Text(String::from(
261267
if self.time.is_paused() {
262268
"Paused"
@@ -271,7 +277,7 @@ impl<'r> App<'r> {
271277
let step_delta = Duration::from_nanos(
272278
u64::try_from(1_000_000_000 / *target_fps).unwrap(),
273279
);
274-
ui_req_tx
280+
self.ui_req_tx
275281
.send(UI_Request::Add_Fadeout_Text(format!(
276282
"Stepping of: {:.2} ms",
277283
time::to_secs_frac(&step_delta) * 1000.0

src/core/input.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -49,27 +49,27 @@ impl std::ops::Deref for Action_List {
4949

5050
pub struct Input_System {
5151
actions: Action_List,
52-
actions_tx: Sender<Action_List>,
5352
}
5453

5554
impl Input_System {
5655
pub fn new(actions_tx: Sender<Action_List>) -> Input_System {
5756
Input_System {
5857
actions: Action_List::default(),
59-
actions_tx,
6058
}
6159
}
6260

61+
pub fn get_action_list(&self) -> Action_List {
62+
self.actions.clone()
63+
}
64+
6365
#[cfg(feature = "use-sdl")]
6466
pub fn update(&mut self, event_pump: &mut sdl2::EventPump) {
6567
poll_events(&mut self.actions, event_pump);
66-
self.actions_tx.send(self.actions.clone()).unwrap();
6768
}
6869

6970
#[cfg(feature = "use-sfml")]
7071
pub fn update(&mut self, window: &mut sfml::graphics::RenderWindow) {
7172
poll_events(&mut self.actions, window);
72-
self.actions_tx.send(self.actions.clone()).unwrap();
7373
}
7474
}
7575

0 commit comments

Comments
 (0)