diff --git a/README.md b/README.md index 4cf5858d..3362aa07 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,8 @@ does not find Doxygen, the documentation will not be generated. absolute and relative window size limits - Added `glfwGetKeyName` for querying the layout-specific name of printable keys + - Added `glfwGetTimerValue` and `glfwGetTimerFrequency` for raw timer access + - Added `GLFWuint64` for platform-independent 64-bit unsigned values - Added `GLFW_NO_API` for creating window without contexts - Added `GLFW_CONTEXT_NO_ERROR` context hint for `GL_KHR_no_error` support - Added `GLFW_INCLUDE_VULKAN` for including the Vulkan header diff --git a/docs/input.dox b/docs/input.dox index 136319b9..2be3d023 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -554,6 +554,21 @@ glfwSetTime(4.0); This sets the timer to the specified time, in seconds. +You can also access the raw timer value, in 1 / frequency seconds, +with @ref glfwGetTimerValue. + +@code +GLFWuint64 value = glfwGetTimerValue(); +@endcode + +The frequency of the raw timer varies depending on what time sources are +available on the machine. You can query its frequency, in Hz, with @ref +glfwGetTimerFrequency. + +@code +GLFWuint64 freqency = glfwGetTimerFrequency(); +@endcode + @section clipboard Clipboard input and output diff --git a/docs/news.dox b/docs/news.dox index 6bf800ac..71e29d57 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -37,6 +37,12 @@ GLFW now supports window maximization with @ref glfwMaximizeWindow and the GLFW now supports giving windows input focus with @ref glfwFocusWindow. +@subsection news_32_timer Raw timer access + +GLFW now supports raw timer values with @ref glfwGetTimerValue and @ref +glfwGetTimerFrequency. + + @section news_31 New features in 3.1 These are the release highlights. For a full list of changes see the diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 9259f55e..85510d64 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -728,6 +728,19 @@ extern "C" { * GLFW API types *************************************************************************/ +/*! @brief 64-bit unsigned integer. + * + * 64-bit unsigned integer. + * + * @since Added in version 3.2. + */ +#if defined(_MSC_VER) && (_MSC_VER < 1600) +typedef unsigned __int64 GLFWuint64; +#else + #include +typedef uint64_t GLFWuint64; +#endif + /*! @brief Client API function pointer type. * * Generic function pointer used for returning client API function pointers @@ -3557,6 +3570,47 @@ GLFWAPI double glfwGetTime(void); */ GLFWAPI void glfwSetTime(double time); +/*! @brief Returns the current value of the raw timer. + * + * This function returns the current value of the raw timer. To get its + * frequency, call @ref glfwGetTimerFrequency. + * + * @return The value of the timer, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_VALUE. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref time + * @sa glfwGetTimerFrequency + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI GLFWuint64 glfwGetTimerValue(void); + +/*! @brief Returns the frequency, in Hz, of the raw timer. + * + * @return The frequency of the timer, in Hz, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_VALUE. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref time + * @sa glfwGetTimerValue + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI GLFWuint64 glfwGetTimerFrequency(void); + /*! @brief Makes the context of the specified window current for the calling * thread. * diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index 212a8ad8..bb52252d 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -118,8 +118,7 @@ typedef struct _GLFWcursorNS // typedef struct _GLFWtimeNS { - double base; - double resolution; + GLFWuint64 frequency; } _GLFWtimeNS; diff --git a/src/cocoa_time.c b/src/cocoa_time.c index 1a644868..20b938d7 100644 --- a/src/cocoa_time.c +++ b/src/cocoa_time.c @@ -29,14 +29,6 @@ #include -// Return raw time -// -static uint64_t getRawTime(void) -{ - return mach_absolute_time(); -} - - ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// @@ -48,8 +40,7 @@ void _glfwInitTimerNS(void) mach_timebase_info_data_t info; mach_timebase_info(&info); - _glfw.ns_time.resolution = (double) info.numer / (info.denom * 1.0e9); - _glfw.ns_time.base = getRawTime(); + _glfw.ns_time.frequency = (info.denom * 1e9) / info.numer; } @@ -57,15 +48,13 @@ void _glfwInitTimerNS(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -double _glfwPlatformGetTime(void) +GLFWuint64 _glfwPlatformGetTimerValue(void) { - return (double) (getRawTime() - _glfw.ns_time.base) * - _glfw.ns_time.resolution; + return mach_absolute_time(); } -void _glfwPlatformSetTime(double time) +GLFWuint64 _glfwPlatformGetTimerFrequency(void) { - _glfw.ns_time.base = getRawTime() - - (uint64_t) (time / _glfw.ns_time.resolution); + return _glfw.ns_time.frequency; } diff --git a/src/init.c b/src/init.c index 06b09712..3674dcf0 100644 --- a/src/init.c +++ b/src/init.c @@ -135,6 +135,8 @@ GLFWAPI int glfwInit(void) _glfw.monitors = _glfwPlatformGetMonitors(&_glfw.monitorCount); _glfwInitialized = GLFW_TRUE; + _glfw.timerOffset = _glfwPlatformGetTimerValue(); + // Not all window hints have zero as their default value glfwDefaultWindowHints(); diff --git a/src/input.c b/src/input.c index be93e39b..368a5569 100644 --- a/src/input.c +++ b/src/input.c @@ -645,7 +645,8 @@ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle) GLFWAPI double glfwGetTime(void) { _GLFW_REQUIRE_INIT_OR_RETURN(0.0); - return _glfwPlatformGetTime(); + return (double) (_glfwPlatformGetTimerValue() - _glfw.timerOffset) / + _glfwPlatformGetTimerFrequency(); } GLFWAPI void glfwSetTime(double time) @@ -658,6 +659,19 @@ GLFWAPI void glfwSetTime(double time) return; } - _glfwPlatformSetTime(time); + _glfw.timerOffset = _glfwPlatformGetTimerValue() - + (GLFWuint64) (time * _glfwPlatformGetTimerFrequency()); +} + +GLFWAPI GLFWuint64 glfwGetTimerValue(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(0); + return _glfwPlatformGetTimerValue(); +} + +GLFWAPI GLFWuint64 glfwGetTimerFrequency(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(0); + return _glfwPlatformGetTimerFrequency(); } diff --git a/src/internal.h b/src/internal.h index cbc04828..68e2d7d1 100644 --- a/src/internal.h +++ b/src/internal.h @@ -47,13 +47,6 @@ #define GLFW_INCLUDE_NONE #include "../include/GLFW/glfw3.h" -#if defined(_MSC_VER) && (_MSC_VER < 1600) -typedef unsigned __int64 GLFWuint64; -#else - #include -typedef uint64_t GLFWuint64; -#endif - typedef int GLFWbool; typedef struct _GLFWwndconfig _GLFWwndconfig; @@ -432,6 +425,8 @@ struct _GLFWlibrary _GLFWmonitor** monitors; int monitorCount; + GLFWuint64 timerOffset; + struct { GLFWbool available; void* handle; @@ -596,15 +591,15 @@ const unsigned char* _glfwPlatformGetJoystickButtons(int joy, int* count); */ const char* _glfwPlatformGetJoystickName(int joy); -/*! @copydoc glfwGetTime +/*! @copydoc glfwGetTimerValue * @ingroup platform */ -double _glfwPlatformGetTime(void); +GLFWuint64 _glfwPlatformGetTimerValue(void); -/*! @copydoc glfwSetTime +/*! @copydoc glfwGetTimerFrequency * @ingroup platform */ -void _glfwPlatformSetTime(double time); +GLFWuint64 _glfwPlatformGetTimerFrequency(void); /*! @ingroup platform */ diff --git a/src/posix_time.c b/src/posix_time.c index ac664124..228f2f7e 100644 --- a/src/posix_time.c +++ b/src/posix_time.c @@ -30,28 +30,6 @@ #include #include -// Return raw time -// -static uint64_t getRawTime(void) -{ -#if defined(CLOCK_MONOTONIC) - if (_glfw.posix_time.monotonic) - { - struct timespec ts; - - clock_gettime(CLOCK_MONOTONIC, &ts); - return (uint64_t) ts.tv_sec * (uint64_t) 1000000000 + (uint64_t) ts.tv_nsec; - } - else -#endif - { - struct timeval tv; - - gettimeofday(&tv, NULL); - return (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec; - } -} - ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// @@ -67,15 +45,14 @@ void _glfwInitTimerPOSIX(void) if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { _glfw.posix_time.monotonic = GLFW_TRUE; - _glfw.posix_time.resolution = 1e-9; + _glfw.posix_time.frequency = 1000000000; } else #endif { - _glfw.posix_time.resolution = 1e-6; + _glfw.posix_time.monotonic = GLFW_FALSE; + _glfw.posix_time.frequency = 1000000; } - - _glfw.posix_time.base = getRawTime(); } @@ -83,15 +60,26 @@ void _glfwInitTimerPOSIX(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -double _glfwPlatformGetTime(void) +GLFWuint64 _glfwPlatformGetTimerValue(void) { - return (double) (getRawTime() - _glfw.posix_time.base) * - _glfw.posix_time.resolution; +#if defined(CLOCK_MONOTONIC) + if (_glfw.posix_time.monotonic) + { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t) ts.tv_sec * (uint64_t) 1000000000 + (uint64_t) ts.tv_nsec; + } + else +#endif + { + struct timeval tv; + gettimeofday(&tv, NULL); + return (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec; + } } -void _glfwPlatformSetTime(double time) +GLFWuint64 _glfwPlatformGetTimerFrequency(void) { - _glfw.posix_time.base = getRawTime() - - (uint64_t) (time / _glfw.posix_time.resolution); + return _glfw.posix_time.frequency; } diff --git a/src/posix_time.h b/src/posix_time.h index b3061fda..31591737 100644 --- a/src/posix_time.h +++ b/src/posix_time.h @@ -38,8 +38,7 @@ typedef struct _GLFWtimePOSIX { GLFWbool monotonic; - double resolution; - uint64_t base; + GLFWuint64 frequency; } _GLFWtimePOSIX; diff --git a/src/win32_platform.h b/src/win32_platform.h index 47b4999a..4ac274b6 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -277,8 +277,7 @@ typedef struct _GLFWcursorWin32 typedef struct _GLFWtimeWin32 { GLFWbool hasPC; - double resolution; - unsigned __int64 base; + GLFWuint64 frequency; } _GLFWtimeWin32; diff --git a/src/win32_time.c b/src/win32_time.c index c8bb61f8..ec6294db 100644 --- a/src/win32_time.c +++ b/src/win32_time.c @@ -28,21 +28,6 @@ #include "internal.h" -// Return raw time -// -static unsigned __int64 getRawTime(void) -{ - if (_glfw.win32_time.hasPC) - { - unsigned __int64 time; - QueryPerformanceCounter((LARGE_INTEGER*) &time); - return time; - } - else - return (unsigned __int64) _glfw_timeGetTime(); -} - - ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// @@ -51,20 +36,18 @@ static unsigned __int64 getRawTime(void) // void _glfwInitTimerWin32(void) { - unsigned __int64 frequency; + GLFWuint64 frequency; if (QueryPerformanceFrequency((LARGE_INTEGER*) &frequency)) { _glfw.win32_time.hasPC = GLFW_TRUE; - _glfw.win32_time.resolution = 1.0 / (double) frequency; + _glfw.win32_time.frequency = frequency; } else { _glfw.win32_time.hasPC = GLFW_FALSE; - _glfw.win32_time.resolution = 0.001; // winmm resolution is 1 ms + _glfw.win32_time.frequency = 1000; } - - _glfw.win32_time.base = getRawTime(); } @@ -72,15 +55,20 @@ void _glfwInitTimerWin32(void) ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -double _glfwPlatformGetTime(void) +GLFWuint64 _glfwPlatformGetTimerValue(void) { - return (double) (getRawTime() - _glfw.win32_time.base) * - _glfw.win32_time.resolution; + if (_glfw.win32_time.hasPC) + { + GLFWuint64 value; + QueryPerformanceCounter((LARGE_INTEGER*) &value); + return value; + } + else + return (GLFWuint64) _glfw_timeGetTime(); } -void _glfwPlatformSetTime(double time) +GLFWuint64 _glfwPlatformGetTimerFrequency(void) { - _glfw.win32_time.base = getRawTime() - - (unsigned __int64) (time / _glfw.win32_time.resolution); + return _glfw.win32_time.frequency; } diff --git a/src/x11_window.c b/src/x11_window.c index e106fc40..5c347694 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1688,7 +1688,7 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, if (!_glfwPlatformWindowVisible(window) && _glfw.x11.NET_REQUEST_FRAME_EXTENTS) { - double base; + GLFWuint64 base; XEvent event; // Ensure _NET_FRAME_EXTENTS is set, allowing glfwGetWindowFrameSize to @@ -1696,13 +1696,14 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, sendEventToWM(window, _glfw.x11.NET_REQUEST_FRAME_EXTENTS, 0, 0, 0, 0, 0); + base = _glfwPlatformGetTimerValue(); + // HACK: Poll with timeout for the required reply instead of blocking // This is done because some window managers (at least Unity, // Fluxbox and Xfwm) failed to send the required reply // They have been fixed but broken versions are still in the wild // If you are affected by this and your window manager is NOT // listed above, PLEASE report it to their and our issue trackers - base = _glfwPlatformGetTime(); while (!XCheckIfEvent(_glfw.x11.display, &event, isFrameExtentsEvent, @@ -1711,7 +1712,8 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, double remaining; struct timeval timeout; - remaining = 0.5 + base - _glfwPlatformGetTime(); + remaining = 0.5 - (_glfwPlatformGetTimerValue() - base) / + (double) _glfwPlatformGetTimerFrequency(); if (remaining <= 0.0) { _glfwInputError(GLFW_PLATFORM_ERROR,