Unravel Engine C++ Reference
Loading...
Searching...
No Matches
simulation.cpp
Go to the documentation of this file.
1#include "simulation.h"
2#include <algorithm>
3#include <thread>
4#include <limits>
5
6namespace unravel
7{
8
16
17void simulation::run_one_frame(bool is_active)
18{
19 // perform waiting loop if maximum fps set
20 auto max_fps = max_fps_;
21 if(!is_active && max_fps > 0)
22 {
23 max_fps = std::min(max_inactive_fps_, max_fps);
24 }
25
26 const auto wait_begin = clock_t::now();
28 if(max_fps > 0)
29 {
30 // Compute the target frame duration at the clock's native resolution
31 // BEFORE dividing. std::chrono::duration's operator/ does integer
32 // division on its stored representation, so `seconds(1) / 60` gives
33 // `seconds(0)` and `1000ms / 60` gives `16ms` (62.5 FPS), both losing
34 // the fractional part. Casting to duration_t (nanoseconds on
35 // Windows/Linux) first turns the dividend into 1'000'000'000, after
36 // which `/ 60 = 16'666'666 ns` ≈ 16.667 ms with sub-microsecond error.
37 const duration_t target_duration =
38 std::chrono::duration_cast<duration_t>(std::chrono::seconds(1)) / max_fps;
39
40 // Two-stage wait: a single coarse sleep that leaves a small safety
41 // margin to absorb OS scheduler jitter, then a yield-spin to the
42 // exact deadline. Matches the pacing approach used by Unity/Unreal.
43 // The margin trades a tiny amount of CPU for sub-millisecond timing
44 // accuracy independent of the platform timer resolution.
45 constexpr auto sleep_safety_margin = std::chrono::milliseconds(2);
46
47 const auto deadline = last_frame_timepoint_ + target_duration;
48 const auto coarse_until = deadline - sleep_safety_margin;
49
50 if(clock_t::now() < coarse_until)
51 {
52 std::this_thread::sleep_until(coarse_until);
53 }
54
55 while(clock_t::now() < deadline)
56 {
57 std::this_thread::yield();
58 }
59
60 elapsed = clock_t::now() - last_frame_timepoint_;
61 }
62
63 if(elapsed < duration_t(0))
64 {
66 }
67
68 const auto wait_end = clock_t::now();
69 last_sleep_duration_ = wait_end - wait_begin;
71 {
72 last_sleep_duration_ = duration_t::zero();
73 }
74
75 last_frame_timepoint_ = wait_end;
76
77 // if fps lower than minimum, clamp eplased time
78 if(min_fps_ > 0)
79 {
80 const duration_t target_duration =
81 std::chrono::duration_cast<duration_t>(std::chrono::seconds(1)) / min_fps_;
82 if(elapsed > target_duration)
83 {
84 elapsed = target_duration;
85 }
86 }
87
88 // perform time step smoothing
89 if(smoothing_step_ > 0)
90 {
91 timestep_ = duration_t::zero();
94 {
95 auto begin = previous_timesteps_.begin();
96 previous_timesteps_.erase(begin, begin + int(previous_timesteps_.size() - smoothing_step_));
97 for(auto step : previous_timesteps_)
98 {
99 timestep_ += step;
100 }
101 timestep_ /= static_cast<duration_t::rep>(previous_timesteps_.size());
102 }
103 else
104 {
106 }
107 }
108 else
109 {
111 }
112
113 ++frame_;
114}
115
117{
118 previous_timesteps_.clear();
119 timestep_ = duration_t::zero();
120 last_sleep_duration_ = duration_t::zero();
121 last_frame_timepoint_ = clock_t::now();
122}
123
124auto simulation::get_frame() const -> uint64_t
125{
126 return frame_;
127}
128
129void simulation::set_min_fps(uint32_t fps)
130{
131 min_fps_ = std::max<uint32_t>(fps, 0);
132}
133
134void simulation::set_max_fps(uint32_t fps)
135{
136 max_fps_ = std::max<uint32_t>(fps, 0);
137}
138
140{
141 max_inactive_fps_ = std::max<uint32_t>(fps, 0);
142}
143
145{
146 smoothing_step_ = step;
147}
148
150{
151 return clock_t::now() - launch_timepoint_;
152}
153
154auto simulation::get_fps() const -> float
155{
156 auto dt = std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(get_delta_time()).count();
157 return (std::abs(dt) < std::numeric_limits<float>::epsilon()) ? 0 : 1000.0f / dt;
158}
159
161{
162 auto dt = std::chrono::duration_cast<delta_t>(timestep_) * time_scale_;
163 return dt;
164}
165
166void simulation::set_time_scale(float time_scale)
167{
168 time_scale_ = time_scale;
169}
170
171auto simulation::get_time_scale() const -> float
172{
173 return time_scale_;
174}
175
176auto simulation::get_max_fps() const -> uint32_t
177{
178 return max_fps_;
179}
180
185} // namespace unravel
float elapsed
std::vector< duration_t > previous_timesteps_
previous time steps for smoothing in seconds
Definition simulation.h:142
auto get_delta_time() const -> delta_t
Returns the delta time in seconds.
auto get_time_scale() const -> float
auto get_fps() const -> float
Returns frames per second.
void set_time_scale(float time_scale=1.0f)
void set_time_smoothing_step(uint32_t step)
Set how many frames to average for timestep smoothing.
timepoint_t last_frame_timepoint_
frame update timer
Definition simulation.h:152
duration_t last_sleep_duration_
time spent sleeping inside the last run_one_frame call
Definition simulation.h:146
duration_t timestep_
next frame time step in seconds
Definition simulation.h:144
void set_max_inactive_fps(uint32_t fps)
Set maximum frames per second when the application does not have input focus.
uint32_t smoothing_step_
how many frames to average for the smoothed time step
Definition simulation.h:150
void run_one_frame(bool is_active)
Perform on frame computations with specified fps.
auto get_frame() const -> uint64_t
auto get_time_since_launch() const -> duration_t
Returns duration since launch.
std::chrono::duration< float > delta_t
Definition simulation.h:24
uint32_t max_inactive_fps_
Definition simulation.h:140
auto get_last_sleep_duration() const -> duration_t
Returns how long run_one_frame spent sleeping during the last call. Useful for stats overlays so they...
uint64_t frame_
current frame
Definition simulation.h:148
void set_max_fps(uint32_t fps)
Set maximum frames per second. The engine will sleep if fps is higher than this.
auto get_max_fps() const -> uint32_t
Returns the configured software FPS cap (0 means uncapped).
void set_min_fps(uint32_t fps)
Set minimum frames per second. If fps goes lower than this, time will appear to slow.
timepoint_t launch_timepoint_
time point when we launched
Definition simulation.h:154
clock_t::duration duration_t
Definition simulation.h:23
uint32_t min_fps_
minimum/maximum frames per second
Definition simulation.h:136