Antkeeper  0.0.1
frame-scheduler.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Christopher J. Howard
3  *
4  * This file is part of Antkeeper source code.
5  *
6  * Antkeeper source code is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Antkeeper source code is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
21 #include <algorithm>
22 #include <thread>
23 
25 {
26  m_frame_start_time = clock_type::now();
27 }
28 
30 {
31  // Measure duration of previous frame
32  m_frame_end_time = clock_type::now();
33  m_frame_duration = m_frame_end_time - m_frame_start_time;
34 
35  // Idle until the minimum frame duration has passed
36  if (m_frame_duration < m_min_frame_duration)
37  {
38  // Determine time to idle until
39  const time_point_type idle_time = m_frame_end_time + m_min_frame_duration - m_frame_duration;
40 
41  // Idle
42  do
43  {
44  std::this_thread::yield();
45  m_frame_end_time = clock_type::now();
46  }
47  while (m_frame_end_time < idle_time);
48 
49  // Measure duration of previous frame with idle
50  m_frame_duration = m_frame_end_time - m_frame_start_time;
51  }
52 
53  // Accumulate previous frame duration (with limit to prevent "spiral of death")
54  m_accumulated_time += std::min<duration_type>(m_max_frame_duration, m_frame_duration);
55 
56  // Start measuring duration of next frame
57  m_frame_start_time = m_frame_end_time;
58 
59  // Perform fixed-rate updates
60  while (m_accumulated_time >= m_fixed_update_interval)
61  {
62  m_fixed_update_callback(m_fixed_update_time, m_fixed_update_interval);
63 
64  m_fixed_update_time += m_fixed_update_interval;
65  m_accumulated_time -= m_fixed_update_interval;
66  }
67 
68  // Perform variable-rate update
69  m_variable_update_callback(m_fixed_update_time, m_fixed_update_interval, m_accumulated_time);
70 }
71 
72 void frame_scheduler::refresh() noexcept
73 {
74  m_accumulated_time = duration_type::zero();
75  m_frame_duration = duration_type::zero();
76  m_frame_start_time = clock_type::now();
77 }
78 
79 void frame_scheduler::reset() noexcept
80 {
81  m_fixed_update_time = duration_type::zero();
82  refresh();
83 }
clock_type::time_point time_point_type
Time point type matches the clock's time point type.
void reset() noexcept
Resets the elapsed fixed-rate update time (t), accumulated time (at), and frame timer.
void refresh() noexcept
Resets the accumulated time (at) and frame timer, but not the elapsed fixed-rate update time.
frame_scheduler() noexcept
Constructs a frame scheduler and starts its frame timer.
void tick()
Performs any scheduled fixed-rate updates followed by a single variable-rate update.