Browse Source

Updated love.timer.getTime to be microsecond-precise and monotonic (thanks Boolsheet), removed the now-obsolete love.timer.getMicroTime (issue #492)

Alex Szpakowski 12 years ago
parent
commit
9fc2a085cd

+ 1 - 1
src/modules/font/freetype/Font.cpp

@@ -52,7 +52,7 @@ Rasterizer *Font::newRasterizer(love::image::ImageData *data, const std::string
 {
 	size_t strlen = text.size();
 	size_t numglyphs = 0;
-	
+
 	unsigned int *glyphs = new unsigned int[strlen];
 
 	try

+ 6 - 8
src/modules/timer/Timer.h

@@ -63,21 +63,19 @@ public:
 	 * @return The "current" FPS.
 	 **/
 	virtual int getFPS() const = 0;
-	virtual double getAverageDelta() const = 0;
 
 	/**
-	 * Gets the amount of time since the program started. Only useful for timing
-	 * code or measuring intervals.
-	 * @return The time (in seconds) since the program started.
+	 * Gets the average delta time (seconds per frame) over the last second.
 	 **/
-	virtual double getTime() const = 0;
+	virtual double getAverageDelta() const = 0;
 
 	/**
-	 * Gets the amount of time passed since an unspecified time. The time is accurate
-	 * to the microsecond, and is limited to 24 hours.
+	 * Gets the amount of time passed since an unspecified time. Useful for
+	 * profiling code or measuring intervals. The time is microsecond-precise,
+	 * and increases monotonically.
 	 * @return The time (in seconds)
 	 **/
-	virtual double getMicroTime() const = 0;
+	virtual double getTime() const = 0;
 
 }; // Timer
 

+ 68 - 36
src/modules/timer/sdl/Timer.cpp

@@ -18,17 +18,38 @@
  * 3. This notice may not be removed or altered from any source distribution.
  **/
 
+// LOVE
 #include "common/config.h"
-#include "common/delay.h"
+#include "Timer.h"
 
-#ifdef LOVE_WINDOWS
-#	include <windows.h>
-#	include <time.h>
-#else
-#	include <sys/time.h>
+#include "common/delay.h"
+#include "common/int.h"
+
+// SDL
+#include <SDL.h>
+
+#if defined(LOVE_WINDOWS)
+#include <windows.h>
+#elif defined(LOVE_MACOSX)
+#include <mach/mach_time.h>
+#include <sys/time.h>
+#elif defined(LOVE_LINUX)
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
 #endif
 
-#include "Timer.h"
+namespace
+{
+#if defined(LOVE_LINUX)
+inline double getTimeOfDay()
+{
+	timeval t;
+	gettimeofday(&t, NULL);
+	return (double) t.tv_sec + (double) t.tv_usec / 1000000.0;
+}
+#endif
+}
 
 namespace love
 {
@@ -45,12 +66,13 @@ Timer::Timer()
 	, fpsUpdateFrequency(1)
 	, frames(0)
 	, dt(0)
+	, timerFrequency(getTimerFrequency())
 {
-	// Init the SDL timer system.
+	// Init the SDL timer system (needed for SDL_Delay.)
 	if (SDL_InitSubSystem(SDL_INIT_TIMER) < 0)
-		throw Exception(SDL_GetError());
+		throw love::Exception("%s", SDL_GetError());
 
-	prevFpsUpdate = currTime = getMicroTime();
+	prevFpsUpdate = currTime = getTime();
 }
 
 Timer::~Timer()
@@ -72,10 +94,10 @@ void Timer::step()
 	// "Current" time is previous time by now.
 	prevTime = currTime;
 
-	// Get ticks from SDL
-	currTime = getMicroTime();
+	// Get ticks from system.
+	currTime = getTime();
 
-	// Convert to number of seconds
+	// Convert to number of seconds.
 	dt = currTime - prevTime;
 
 	double timeSinceLast = currTime - prevFpsUpdate;
@@ -110,35 +132,45 @@ double Timer::getAverageDelta() const
 	return averageDelta;
 }
 
-double Timer::getTime() const
+double Timer::getTimerFrequency()
 {
-	return SDL_GetTicks()/1000.0;
+#if defined(LOVE_MACOSX)
+	mach_timebase_info_data_t info;
+	mach_timebase_info(&info);
+	return (double) info.numer / (double) info.denom / 1000000000.0;
+#elif defined(LOVE_WINDOWS)
+	LARGE_INTEGER temp;
+	if (QueryPerformanceFrequency(&temp) != 0 && temp.QuadPart != 0)
+		return 1.0 / (double) temp.QuadPart;
+#endif
+	return 0;
 }
 
-double Timer::getMicroTime() const
+double Timer::getTime() const
 {
-#ifdef LOVE_WINDOWS
-	static __int64 freq = 0;
-
-	if (!freq)
-	{
-		LARGE_INTEGER temp;
-		QueryPerformanceFrequency(&temp);
-
-		freq = (__int64) temp.QuadPart;
-	}
-
+#if defined(LOVE_LINUX)
+	double mt;
+	// Check for POSIX timers and monotonic clocks. If not supported, use the gettimeofday fallback.
+#if _POSIX_TIMERS > 0 && defined(_POSIX_MONOTONIC_CLOCK) \
+&& (defined(CLOCK_MONOTONIC_RAW) || defined(CLOCK_MONOTONIC))
+	timespec t;
+#ifdef CLOCK_MONOTONIC_RAW
+	clockid_t clk_id = CLOCK_MONOTONIC_RAW;
+#else
+	clockid_t clk_id = CLOCK_MONOTONIC;
+#endif
+	if (clock_gettime(clk_id, &t) == 0)
+		mt = (double) t.tv_sec + (double) t.tv_nsec / 1000000000.0;
+	else
+#endif
+		mt = getTimeOfDay();
+	return mt;
+#elif defined(LOVE_MACOSX)
+	return (double) mach_absolute_time() * timerFrequency;
+#elif defined(LOVE_WINDOWS)
 	LARGE_INTEGER microTime;
 	QueryPerformanceCounter(&microTime);
-
-	// The 64 to 32 bit integer conversion, assuming the fraction part down
-	// to microseconds takes 20 bits, should not be a problem unless the
-	// system has an uptime of a few decades.
-	return (double) microTime.QuadPart / (double) freq;
-#else
-	timeval t;
-	gettimeofday(&t, NULL);
-	return t.tv_sec + t.tv_usec/1000000.0;
+	return (double) microTime.QuadPart * timerFrequency;
 #endif
 }
 

+ 7 - 5
src/modules/timer/sdl/Timer.h

@@ -21,11 +21,8 @@
 #ifndef LOVE_TIMER_SDL_TIMER_H
 #define LOVE_TIMER_SDL_TIMER_H
 
-// SDL
-#include <SDL.h>
-
 // LOVE
-#include <timer/Timer.h>
+#include "timer/Timer.h"
 
 namespace love
 {
@@ -59,7 +56,6 @@ public:
 	int getFPS() const;
 	double getAverageDelta() const;
 	double getTime() const;
-	double getMicroTime() const;
 
 private:
 
@@ -81,6 +77,12 @@ private:
 	// The current timestep.
 	double dt;
 
+	// The reciprocal of the timer frequency.
+	const double timerFrequency;
+
+	// Returns the timer frequency on some platforms.
+	static double getTimerFrequency();
+	
 }; // Timer
 
 } // sdl

+ 0 - 7
src/modules/timer/wrap_Timer.cpp

@@ -68,12 +68,6 @@ int w_getTime(lua_State *L)
 	return 1;
 }
 
-int w_getMicroTime(lua_State *L)
-{
-	lua_pushnumber(L, instance->getMicroTime());
-	return 1;
-}
-
 // List of functions to wrap.
 static const luaL_Reg functions[] =
 {
@@ -83,7 +77,6 @@ static const luaL_Reg functions[] =
 	{ "getAverageDelta", w_getAverageDelta },
 	{ "sleep", w_sleep },
 	{ "getTime", w_getTime },
-	{ "getMicroTime", w_getMicroTime },
 	{ 0, 0 }
 };
 

+ 0 - 1
src/modules/timer/wrap_Timer.h

@@ -35,7 +35,6 @@ int w_getFPS(lua_State *L);
 int w_getAverageDelta(lua_State *L);
 int w_sleep(lua_State *L);
 int w_getTime(lua_State *L);
-int w_getMicroTime(lua_State *L);
 extern "C" LOVE_EXPORT int luaopen_love_timer(lua_State *L);
 
 } // timer

+ 17 - 18
src/modules/window/sdl/Window.cpp

@@ -18,15 +18,15 @@
  * 3. This notice may not be removed or altered from any source distribution.
  **/
 
-// STL
-#include <iostream>
+// LOVE
+#include "common/config.h"
+#include "Window.h"
 
 // SDL
 #include <SDL.h>
 
-// LOVE
-#include "common/config.h"
-#include "Window.h"
+// STL
+#include <iostream>
 
 namespace love
 {
@@ -49,7 +49,9 @@ Window::~Window()
 }
 
 Window::_currentMode::_currentMode()
-	: width(800), height(600), fullscreen(false), vsync(true), fsaa(0)
+	: width(800)
+	, height(600)
+	, flags()
 {
 }
 
@@ -177,12 +179,12 @@ bool Window::setWindow(int width, int height, WindowFlags *flags)
 	// Set the new display mode as the current display mode.
 	currentMode.width = width;
 	currentMode.height = height;
-	currentMode.fsaa = fsaa;
-	currentMode.fullscreen = fullscreen;
-	currentMode.vsync = (real_vsync != 0);
-	currentMode.resizable = ((surface->flags & SDL_RESIZABLE) != 0);
-	currentMode.borderless = ((surface->flags & SDL_NOFRAME) != 0);
-	currentMode.centered = centered;
+	currentMode.flags.fsaa = fsaa;
+	currentMode.flags.fullscreen = fullscreen;
+	currentMode.flags.vsync = (real_vsync != 0);
+	currentMode.flags.resizable = ((surface->flags & SDL_RESIZABLE) != 0);
+	currentMode.flags.borderless = ((surface->flags & SDL_NOFRAME) != 0);
+	currentMode.flags.centered = centered;
 
 	return true;
 }
@@ -191,12 +193,7 @@ void Window::getWindow(int &width, int &height, WindowFlags &flags) const
 {
 	width = currentMode.width;
 	height = currentMode.height;
-	flags.fullscreen = currentMode.fullscreen;
-	flags.vsync = currentMode.vsync;
-	flags.fsaa = currentMode.fsaa;
-	flags.resizable = currentMode.resizable;
-	flags.borderless = currentMode.borderless;
-	flags.centered = currentMode.centered;
+	flags = currentMode.flags;
 }
 
 bool Window::checkWindowSize(int width, int height, bool fullscreen) const
@@ -232,6 +229,7 @@ WindowSize *Window::getFullscreenSizes(int &n) const
 		WindowSize w = {modes[i]->w, modes[i]->h};
 		sizes[i] = w;
 	}
+
 	return sizes;
 }
 
@@ -286,6 +284,7 @@ bool Window::setIcon(love::image::ImageData *imgd)
 	SDL_Surface *icon = SDL_CreateRGBSurfaceFrom(imgd->getData(), w, h, 32, pitch, rmask, gmask, bmask, amask);
 	SDL_WM_SetIcon(icon, NULL);
 	SDL_FreeSurface(icon);
+
 	return true;
 }
 

+ 10 - 7
src/modules/window/sdl/Window.h

@@ -22,7 +22,7 @@
 #define LOVE_WINDOW_SDL_WINDOW_H
 
 // LOVE
-#include <window/Window.h>
+#include "window/Window.h"
 
 namespace love
 {
@@ -34,6 +34,7 @@ namespace sdl
 class Window : public love::window::Window
 {
 public:
+
 	Window();
 	~Window();
 
@@ -62,21 +63,23 @@ public:
 	static love::window::Window *getSingleton();
 
 	const char *getName() const;
+
 private:
+
 	std::string windowTitle;
+
 	struct _currentMode
 	{
 		_currentMode();
+
 		int width;
 		int height;
-		bool fullscreen;
-		bool vsync;
-		int fsaa;
-		bool resizable;
-		bool borderless;
-		bool centered;
+		WindowFlags flags;
+
 	} currentMode;
+
 	bool created;
+
 }; // Window
 
 } // sdl