#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2013 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License #ifndef NUCLEX_GAME_TIMING_WINDOWSCLOCK_H #define NUCLEX_GAME_TIMING_WINDOWSCLOCK_H #include "../Config.h" #include "Clock.h" #include #include namespace Nuclex { namespace Game { namespace Timing { // ------------------------------------------------------------------------------------------- // /// Uses the Windows API to obtain accurate timings on Microsoft systems /// /// /// This clock uses the performance counter API if available to obtain a very high /// resolution timer (usually in the GHz range) on Windows systems. If a performance /// counter is not available, it will opt for timeGetTime(), which only offers /// a resolution of 1 KHz. /// /// /// This clock also protects you against some systems known to exist in the wild where /// time can jump due to hardware flaws (http://support.microsoft.com/kb/274323/en-us) /// or skip back on a multi-core CPU when counters are not synchronized across cores, /// causing different counters to be accessed depending on which the CPU core the calling /// thread happened to be scheduled on. /// /// /// For the best possible timing quality, always query time on the same CPU core by /// setting a preferred core (don't force affinity, messing with the OS thread scheduler /// is bad practice because it might force your game into a crawl if that one CPU core /// happens to run a heavy task if if all other cores are free). /// /// class WindowsClock : public Clock { /// Initializes a new Windows clock public: NUCLEX_GAME_API WindowsClock(); /// Destroys the clock public: NUCLEX_GAME_API virtual ~WindowsClock(); /// Tries to determine the performance counter frequency /// Receives the frequency of the performance counter /// /// True if the performance counter is available and its frequency was stored in /// the provided variable, false otherwise. /// public: NUCLEX_GAME_API static bool TryGetCountFrequency(std::uint64_t &countFrequency); /// Returns the number of counts per second /// The total number of counts per second for the timer being used public: NUCLEX_GAME_API static std::uint64_t GetCountFrequency(); /// Returns the number of counts that have passed /// The total number of counts that have passed since a defined time /// /// The "defined time" can be anything, typically it's either when the process /// started or when the system was booted. The absolute value has no particular meaning /// and should only be used to compare against an earlier value. /// public: NUCLEX_GAME_API static std::uint64_t GetCurrentCounts(); /// Retrieves the current system uptime in milliseconds /// The system uptime in milliseconds public: NUCLEX_GAME_API static std::chrono::milliseconds GetUptime(); /// /// Retrieves the maximum value the time can assume before wrapping around to 0 again /// /// The highest possible value GetTime() can return public: NUCLEX_GAME_API std::uint64_t GetWraparoundTime() const; /// Retrieves the clock's current time /// The number of ticks the clock has ticked to far /// /// There's no rule for what a clock's time should be relative to, only that it /// keeps counting at a fixed pace. The clock could begin ticking when the system /// boots, when the application starts or when the class is instantiated. /// public: NUCLEX_GAME_API std::uint64_t GetTime() const; /// Retrieves the clock's tick frequency /// How often the clock will tick in one second public: NUCLEX_GAME_API std::uint64_t GetFrequency() const; /// Retrieves the time scaled to the performance counter frequency /// The time from timeGetTime() scaled to the performance counter /// /// This must not be called if the performance counter is not available. /// private: std::uint64_t getTimeAsCounts() const; /// How often the performance counter ticks per second private: std::uint64_t performanceCounterFrequency; /// Previous value of the performance counter private: mutable std::uint64_t previousCounts; /// Offset of the performance counter relative to timeGetTime() private: mutable std::uint64_t performanceCounterOffset; /// Mutex used to update the clock private: mutable std::mutex mutex; /// The resolution of the millisecond fallback timer private: std::uint32_t timerResolution; }; // ------------------------------------------------------------------------------------------- // }}} // namespace Nuclex::Game::Timing #endif // NUCLEX_GAME_TIMING_WINDOWSCLOCK_H