aboutsummaryrefslogtreecommitdiffstats
path: root/LibOVR/Src/Kernel/OVR_Timer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'LibOVR/Src/Kernel/OVR_Timer.cpp')
-rw-r--r--LibOVR/Src/Kernel/OVR_Timer.cpp551
1 files changed, 0 insertions, 551 deletions
diff --git a/LibOVR/Src/Kernel/OVR_Timer.cpp b/LibOVR/Src/Kernel/OVR_Timer.cpp
deleted file mode 100644
index 3a75ec2..0000000
--- a/LibOVR/Src/Kernel/OVR_Timer.cpp
+++ /dev/null
@@ -1,551 +0,0 @@
-/************************************************************************************
-
-Filename : OVR_Timer.cpp
-Content : Provides static functions for precise timing
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
-
-Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
-you may not use the Oculus VR Rift SDK except in compliance with the License,
-which is provided at the time of installation or download, or which
-otherwise accompanies this software in either electronic or hard copy form.
-
-You may obtain a copy of the License at
-
-http://www.oculusvr.com/licenses/LICENSE-3.2
-
-Unless required by applicable law or agreed to in writing, the Oculus VR SDK
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-************************************************************************************/
-
-#include "OVR_Timer.h"
-#include "OVR_Log.h"
-
-#if defined(OVR_OS_MS) && !defined(OVR_OS_MS_MOBILE)
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <MMSystem.h>
-#elif defined(OVR_OS_ANDROID)
-#include <time.h>
-#include <android/log.h>
-#elif defined(OVR_OS_MAC)
-#include <mach/mach_time.h>
-#else
-#include <time.h>
-#include <sys/time.h>
-#include <errno.h>
-#endif
-
-
-#if defined(OVR_BUILD_DEBUG) && defined(OVR_OS_WIN32)
- #ifndef NTSTATUS
- #define NTSTATUS DWORD
- #endif
-
- typedef NTSTATUS (NTAPI* NtQueryTimerResolutionType)(PULONG MaximumTime, PULONG MinimumTime, PULONG CurrentTime);
- NtQueryTimerResolutionType pNtQueryTimerResolution;
-#endif
-
-
-
-#if defined(OVR_OS_MS) && !defined(OVR_OS_WIN32) // Non-desktop Microsoft platforms...
-
-// Add this alias here because we're not going to include OVR_CAPI.cpp
-extern "C" {
- double ovr_GetTimeInSeconds()
- {
- return Timer::GetSeconds();
- }
-}
-
-#endif
-
-
-
-
-namespace OVR {
-
-// For recorded data playback
-bool Timer::useFakeSeconds = false;
-double Timer::FakeSeconds = 0;
-
-
-
-
-//------------------------------------------------------------------------
-// *** Android Specific Timer
-
-#if defined(OVR_OS_ANDROID) // To consider: This implementation can also work on most Linux distributions
-
-//------------------------------------------------------------------------
-// *** Timer - Platform Independent functions
-
-// Returns global high-resolution application timer in seconds.
-double Timer::GetSeconds()
-{
- if(useFakeSeconds)
- return FakeSeconds;
-
- // Choreographer vsync timestamp is based on.
- struct timespec tp;
- const int status = clock_gettime(CLOCK_MONOTONIC, &tp);
-
-#ifdef OVR_BUILD_DEBUG
- if (status != 0)
- {
- OVR_DEBUG_LOG(("clock_gettime status=%i", status ));
- }
-#else
- OVR_UNUSED(status);
-#endif
-
- return (double)tp.tv_sec;
-}
-
-
-
-uint64_t Timer::GetTicksNanos()
-{
- if (useFakeSeconds)
- return (uint64_t) (FakeSeconds * NanosPerSecond);
-
- // Choreographer vsync timestamp is based on.
- struct timespec tp;
- const int status = clock_gettime(CLOCK_MONOTONIC, &tp);
-
-#ifdef OVR_BUILD_DEBUG
- if (status != 0)
- {
- OVR_DEBUG_LOG(("clock_gettime status=%i", status ));
- }
-#else
- OVR_UNUSED(status);
-#endif
-
- const uint64_t result = (uint64_t)tp.tv_sec * (uint64_t)(1000 * 1000 * 1000) + uint64_t(tp.tv_nsec);
- return result;
-}
-
-
-void Timer::initializeTimerSystem()
-{
- // Empty for this platform.
-}
-
-void Timer::shutdownTimerSystem()
-{
- // Empty for this platform.
-}
-
-
-
-
-
-//------------------------------------------------------------------------
-// *** Win32 Specific Timer
-
-#elif defined (OVR_OS_MS)
-
-
-// This helper class implements high-resolution wrapper that combines timeGetTime() output
-// with QueryPerformanceCounter. timeGetTime() is lower precision but drives the high bits,
-// as it's tied to the system clock.
-struct PerformanceTimer
-{
- PerformanceTimer()
- : UsingVistaOrLater(false),
- TimeCS(),
- OldMMTimeMs(0),
- MMTimeWrapCounter(0),
- PerfFrequency(0),
- PerfFrequencyInverse(0),
- PerfFrequencyInverseNanos(0),
- PerfMinusTicksDeltaNanos(0),
- LastResultNanos(0)
- { }
-
- enum {
- MMTimerResolutionNanos = 1000000
- };
-
- void Initialize();
- void Shutdown();
-
- uint64_t GetTimeSeconds();
- double GetTimeSecondsDouble();
- uint64_t GetTimeNanos();
-
- UINT64 getFrequency()
- {
- if (PerfFrequency == 0)
- {
- LARGE_INTEGER freq;
- QueryPerformanceFrequency(&freq);
- PerfFrequency = freq.QuadPart;
- PerfFrequencyInverse = 1.0 / (double)PerfFrequency;
- PerfFrequencyInverseNanos = 1000000000.0 / (double)PerfFrequency;
- }
- return PerfFrequency;
- }
-
- double GetFrequencyInverse()
- {
- OVR_ASSERT(PerfFrequencyInverse != 0.0); // Assert that the frequency has been initialized.
- return PerfFrequencyInverse;
- }
-
- bool UsingVistaOrLater;
-
- CRITICAL_SECTION TimeCS;
- // timeGetTime() support with wrap.
- uint32_t OldMMTimeMs;
- uint32_t MMTimeWrapCounter;
- // Cached performance frequency result.
- uint64_t PerfFrequency; // cycles per second, typically a large value like 3000000, but usually not the same as the CPU clock rate.
- double PerfFrequencyInverse; // seconds per cycle (will be a small fractional value).
- double PerfFrequencyInverseNanos; // nanoseconds per cycle.
-
- // Computed as (perfCounterNanos - ticksCounterNanos) initially,
- // and used to adjust timing.
- uint64_t PerfMinusTicksDeltaNanos;
- // Last returned value in nanoseconds, to ensure we don't back-step in time.
- uint64_t LastResultNanos;
-};
-
-static PerformanceTimer Win32_PerfTimer;
-
-
-void PerformanceTimer::Initialize()
-{
- #if defined(OVR_OS_WIN32) // Desktop Windows only
- // The following has the effect of setting the NT timer resolution (NtSetTimerResolution) to 1 millisecond.
- MMRESULT mmr = timeBeginPeriod(1);
- OVR_ASSERT(TIMERR_NOERROR == mmr);
- OVR_UNUSED(mmr);
- #endif
-
- InitializeCriticalSection(&TimeCS);
- MMTimeWrapCounter = 0;
- getFrequency();
-
- #if defined(OVR_OS_WIN32) // Desktop Windows only
- // Set Vista flag. On Vista, we can just use QPC() without all the extra work
- OSVERSIONINFOEX ver;
- ZeroMemory(&ver, sizeof(OSVERSIONINFOEX));
- ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
- ver.dwMajorVersion = 6; // Vista+
-
- DWORDLONG condMask = 0;
- VER_SET_CONDITION(condMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
-
- // VerifyVersionInfo returns true if the OS meets the conditions set above
- UsingVistaOrLater = VerifyVersionInfo(&ver, VER_MAJORVERSION, condMask) != 0;
- #else
- UsingVistaOrLater = true;
- #endif
-
- OVR_DEBUG_LOG(("PerformanceTimer UsingVistaOrLater = %d", (int)UsingVistaOrLater));
-
- #if defined(OVR_BUILD_DEBUG) && defined(OVR_OS_WIN32)
- HMODULE hNtDll = LoadLibrary(L"NtDll.dll");
- if (hNtDll)
- {
- pNtQueryTimerResolution = (NtQueryTimerResolutionType)GetProcAddress(hNtDll, "NtQueryTimerResolution");
- //pNtSetTimerResolution = (NtSetTimerResolutionType)GetProcAddress(hNtDll, "NtSetTimerResolution");
-
- if(pNtQueryTimerResolution)
- {
- ULONG MinimumResolution; // in 100-ns units
- ULONG MaximumResolution;
- ULONG ActualResolution;
- pNtQueryTimerResolution(&MinimumResolution, &MaximumResolution, &ActualResolution);
- OVR_DEBUG_LOG(("NtQueryTimerResolution = Min %ld us, Max %ld us, Current %ld us", MinimumResolution / 10, MaximumResolution / 10, ActualResolution / 10));
- }
-
- FreeLibrary(hNtDll);
- }
- #endif
-}
-
-void PerformanceTimer::Shutdown()
-{
- DeleteCriticalSection(&TimeCS);
-
- #if defined(OVR_OS_WIN32) // Desktop Windows only
- MMRESULT mmr = timeEndPeriod(1);
- OVR_ASSERT(TIMERR_NOERROR == mmr);
- OVR_UNUSED(mmr);
- #endif
-}
-
-
-uint64_t PerformanceTimer::GetTimeSeconds()
-{
- if (UsingVistaOrLater)
- {
- LARGE_INTEGER li;
- QueryPerformanceCounter(&li);
- OVR_ASSERT(PerfFrequencyInverse != 0); // Initialize should have been called earlier.
- return (uint64_t)(li.QuadPart * PerfFrequencyInverse);
- }
-
- return (uint64_t)(GetTimeNanos() * .0000000001);
-}
-
-
-double PerformanceTimer::GetTimeSecondsDouble()
-{
- if (UsingVistaOrLater)
- {
- LARGE_INTEGER li;
- QueryPerformanceCounter(&li);
- OVR_ASSERT(PerfFrequencyInverse != 0);
- return (li.QuadPart * PerfFrequencyInverse);
- }
-
- return (GetTimeNanos() * .0000000001);
-}
-
-
-uint64_t PerformanceTimer::GetTimeNanos()
-{
- uint64_t resultNanos;
- LARGE_INTEGER li;
-
- OVR_ASSERT(PerfFrequencyInverseNanos != 0); // Initialize should have been called earlier.
-
- if (UsingVistaOrLater) // Includes non-desktop platforms
- {
- // Then we can use QPC() directly without all that extra work
- QueryPerformanceCounter(&li);
- resultNanos = (uint64_t)(li.QuadPart * PerfFrequencyInverseNanos);
- }
- else
- {
- // On Win32 QueryPerformanceFrequency is unreliable due to SMP and
- // performance levels, so use this logic to detect wrapping and track
- // high bits.
- ::EnterCriticalSection(&TimeCS);
-
- // Get raw value and perf counter "At the same time".
- QueryPerformanceCounter(&li);
-
- DWORD mmTimeMs = timeGetTime();
- if (OldMMTimeMs > mmTimeMs)
- MMTimeWrapCounter++;
- OldMMTimeMs = mmTimeMs;
-
- // Normalize to nanoseconds.
- uint64_t perfCounterNanos = (uint64_t)(li.QuadPart * PerfFrequencyInverseNanos);
- uint64_t mmCounterNanos = ((uint64_t(MMTimeWrapCounter) << 32) | mmTimeMs) * 1000000;
- if (PerfMinusTicksDeltaNanos == 0)
- PerfMinusTicksDeltaNanos = perfCounterNanos - mmCounterNanos;
-
- // Compute result before snapping.
- //
- // On first call, this evaluates to:
- // resultNanos = mmCounterNanos.
- // Next call, assuming no wrap:
- // resultNanos = prev_mmCounterNanos + (perfCounterNanos - prev_perfCounterNanos).
- // After wrap, this would be:
- // resultNanos = snapped(prev_mmCounterNanos +/- 1ms) + (perfCounterNanos - prev_perfCounterNanos).
- //
- resultNanos = perfCounterNanos - PerfMinusTicksDeltaNanos;
-
- // Snap the range so that resultNanos never moves further apart then its target resolution.
- // It's better to allow more slack on the high side as timeGetTime() may be updated at sporadically
- // larger then 1 ms intervals even when 1 ms resolution is requested.
- if (resultNanos > (mmCounterNanos + MMTimerResolutionNanos*2))
- {
- resultNanos = mmCounterNanos + MMTimerResolutionNanos*2;
- if (resultNanos < LastResultNanos)
- resultNanos = LastResultNanos;
- PerfMinusTicksDeltaNanos = perfCounterNanos - resultNanos;
- }
- else if (resultNanos < (mmCounterNanos - MMTimerResolutionNanos))
- {
- resultNanos = mmCounterNanos - MMTimerResolutionNanos;
- if (resultNanos < LastResultNanos)
- resultNanos = LastResultNanos;
- PerfMinusTicksDeltaNanos = perfCounterNanos - resultNanos;
- }
-
- LastResultNanos = resultNanos;
- ::LeaveCriticalSection(&TimeCS);
- }
-
- //Tom's addition, to keep precision
- //static uint64_t initial_time = 0;
- //if (!initial_time) initial_time = resultNanos;
- //resultNanos -= initial_time;
- // FIXME: This cannot be used for cross-process timestamps
-
- return resultNanos;
-}
-
-
-//------------------------------------------------------------------------
-// *** Timer - Platform Independent functions
-
-// Returns global high-resolution application timer in seconds.
-double Timer::GetSeconds()
-{
- if(useFakeSeconds)
- return FakeSeconds;
-
- return Win32_PerfTimer.GetTimeSecondsDouble();
-}
-
-
-
-// Delegate to PerformanceTimer.
-uint64_t Timer::GetTicksNanos()
-{
- if (useFakeSeconds)
- return (uint64_t) (FakeSeconds * NanosPerSecond);
-
- return Win32_PerfTimer.GetTimeNanos();
-}
-void Timer::initializeTimerSystem()
-{
- Win32_PerfTimer.Initialize();
-}
-void Timer::shutdownTimerSystem()
-{
- Win32_PerfTimer.Shutdown();
-}
-
-
-
-#elif defined(OVR_OS_MAC)
-
-
-double Timer::TimeConvertFactorNanos = 0.0;
-double Timer::TimeConvertFactorSeconds = 0.0;
-
-
-//------------------------------------------------------------------------
-// *** Standard OS Timer
-
-// Returns global high-resolution application timer in seconds.
-double Timer::GetSeconds()
-{
- if(useFakeSeconds)
- return FakeSeconds;
-
- OVR_ASSERT(TimeConvertFactorNanos != 0.0);
- return (double)mach_absolute_time() * TimeConvertFactorNanos;
-}
-
-
-uint64_t Timer::GetTicksNanos()
-{
- if (useFakeSeconds)
- return (uint64_t) (FakeSeconds * NanosPerSecond);
-
- OVR_ASSERT(TimeConvertFactorSeconds != 0.0);
- return (uint64_t)(mach_absolute_time() * TimeConvertFactorSeconds);
-}
-
-void Timer::initializeTimerSystem()
-{
- mach_timebase_info_data_t timeBase;
- mach_timebase_info(&timeBase);
- TimeConvertFactorSeconds = ((double)timeBase.numer / (double)timeBase.denom);
- TimeConvertFactorNanos = TimeConvertFactorSeconds / 1000000000.0;
-}
-
-void Timer::shutdownTimerSystem()
-{
- // Empty for this platform.
-}
-
-
-#else // Posix platforms (e.g. Linux, BSD Unix)
-
-
-bool Timer::MonotonicClockAvailable = false;
-
-
-// Returns global high-resolution application timer in seconds.
-double Timer::GetSeconds()
-{
- if(useFakeSeconds)
- return FakeSeconds;
-
- // http://linux/die/netman3/clock_gettime
- #if defined(CLOCK_MONOTONIC) // If we can use clock_gettime, which has nanosecond precision...
- if(MonotonicClockAvailable)
- {
- timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts); // Better to use CLOCK_MONOTONIC than CLOCK_REALTIME.
- return static_cast<double>(ts.tv_sec) + static_cast<double>(ts.tv_nsec) / 1E9;
- }
- #endif
-
- // We cannot use rdtsc because its frequency changes at runtime.
- struct timeval tv;
- gettimeofday(&tv, 0);
-
- return static_cast<double>(tv.tv_sec) + static_cast<double>(tv.tv_usec) / 1E6;
-}
-
-
-uint64_t Timer::GetTicksNanos()
-{
- if (useFakeSeconds)
- return (uint64_t) (FakeSeconds * NanosPerSecond);
-
- #if defined(CLOCK_MONOTONIC) // If we can use clock_gettime, which has nanosecond precision...
- if(MonotonicClockAvailable)
- {
- timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- return ((uint64_t)ts.tv_sec * 1000000000ULL) + (uint64_t)ts.tv_nsec;
- }
- #endif
-
-
- // We cannot use rdtsc because its frequency changes at runtime.
- uint64_t result;
-
- // Return microseconds.
- struct timeval tv;
-
- gettimeofday(&tv, 0);
-
- result = (uint64_t)tv.tv_sec * 1000000;
- result += tv.tv_usec;
-
- return result * 1000;
-}
-
-
-void Timer::initializeTimerSystem()
-{
- #if defined(CLOCK_MONOTONIC)
- timespec ts; // We could also check for the availability of CLOCK_MONOTONIC with sysconf(_SC_MONOTONIC_CLOCK)
- int result = clock_gettime(CLOCK_MONOTONIC, &ts);
- MonotonicClockAvailable = (result == 0);
- #endif
-}
-
-void Timer::shutdownTimerSystem()
-{
- // Empty for this platform.
-}
-
-
-
-#endif // OS-specific
-
-
-
-} // OVR
-