1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21// LOVE
22#include "common/config.h"
23#include "common/int.h"
24#include "common/delay.h"
25#include "Timer.h"
26
27#include <iostream>
28#if defined(LOVE_WINDOWS)
29#include <windows.h>
30#elif defined(LOVE_MACOSX) || defined(LOVE_IOS)
31#include <mach/mach_time.h>
32#include <sys/time.h>
33#elif defined(LOVE_LINUX)
34#include <unistd.h>
35#include <time.h>
36#include <sys/time.h>
37#endif
38
39namespace love
40{
41namespace timer
42{
43
44Timer::Timer()
45 : currTime(0)
46 , prevFpsUpdate(0)
47 , fps(0)
48 , averageDelta(0)
49 , fpsUpdateFrequency(1)
50 , frames(0)
51 , dt(0)
52{
53 prevFpsUpdate = currTime = getTime();
54}
55
56double Timer::step()
57{
58 // Frames rendered
59 frames++;
60
61 // "Current" time is previous time by now.
62 prevTime = currTime;
63
64 // Get time from system.
65 currTime = getTime();
66
67 // Convert to number of seconds.
68 dt = currTime - prevTime;
69
70 double timeSinceLast = currTime - prevFpsUpdate;
71 // Update FPS?
72 if (timeSinceLast > fpsUpdateFrequency)
73 {
74 fps = int((frames/timeSinceLast) + 0.5);
75 averageDelta = timeSinceLast/frames;
76 prevFpsUpdate = currTime;
77 frames = 0;
78 }
79
80 return dt;
81}
82
83void Timer::sleep(double seconds) const
84{
85 if (seconds >= 0)
86 love::sleep((unsigned int)(seconds*1000));
87}
88
89double Timer::getDelta() const
90{
91 return dt;
92}
93
94int Timer::getFPS() const
95{
96 return fps;
97}
98
99double Timer::getAverageDelta() const
100{
101 return averageDelta;
102}
103
104#if defined(LOVE_LINUX)
105
106static inline timespec getTimeOfDay()
107{
108 timeval t;
109 gettimeofday(&t, NULL);
110 return timespec { t.tv_sec, t.tv_usec * 1000 };
111}
112
113static timespec getTimeAbsolute()
114{
115 // Check for POSIX timers and monotonic clocks. If not supported, use the gettimeofday fallback.
116#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK) \
117&& (defined(CLOCK_MONOTONIC_RAW) || defined(CLOCK_MONOTONIC))
118
119#ifdef CLOCK_MONOTONIC_RAW
120 clockid_t clk_id = CLOCK_MONOTONIC_RAW;
121#else
122 clockid_t clk_id = CLOCK_MONOTONIC;
123#endif
124
125 timespec t;
126 if (clock_gettime(clk_id, &t) == 0)
127 return t;
128 else
129 return getTimeOfDay();
130#endif
131 return getTimeOfDay();
132}
133
134double Timer::getTime()
135{
136 static const timespec start = getTimeAbsolute();
137 const timespec now = getTimeAbsolute();
138 // tv_sec and tv_nsec should be signed on POSIX, so we are fine in just subtracting here.
139 const long sec = now.tv_sec - start.tv_sec;
140 const long nsec = now.tv_nsec - start.tv_nsec;
141 return (double) sec + (double) nsec / 1.0e9;
142}
143
144#elif defined(LOVE_MACOSX) || defined(LOVE_IOS)
145
146static mach_timebase_info_data_t getTimebaseInfo()
147{
148 mach_timebase_info_data_t info;
149 mach_timebase_info(&info);
150 return info;
151}
152
153double Timer::getTime()
154{
155 static const mach_timebase_info_data_t info = getTimebaseInfo();
156 static const uint64_t start = mach_absolute_time();
157 const uint64_t rel = mach_absolute_time() - start;
158 return ((double) rel * 1.0e-9) * (double) info.numer / (double) info.denom;
159}
160
161#elif defined(LOVE_WINDOWS)
162
163static LARGE_INTEGER getTimeAbsolute()
164{
165 LARGE_INTEGER t;
166 QueryPerformanceCounter(&t);
167 return t;
168}
169
170static LARGE_INTEGER getFrequency()
171{
172 LARGE_INTEGER freq;
173 // "On systems that run Windows XP or later, the function will always succeed and will thus never return zero."
174 QueryPerformanceFrequency(&freq);
175 return freq;
176}
177
178double Timer::getTime()
179{
180 static const LARGE_INTEGER freq = getFrequency();
181 static const LARGE_INTEGER start = getTimeAbsolute();
182 const LARGE_INTEGER now = getTimeAbsolute();
183 LARGE_INTEGER rel;
184 rel.QuadPart = now.QuadPart - start.QuadPart;
185 return (double) rel.QuadPart / (double) freq.QuadPart;
186}
187
188#endif
189
190} // timer
191} // love
192