Browse Source

Added high precision timer routines.

* Added POSIX and SDL2 timers and stopwatches.
master
Ian Burgmyer 4 years ago
parent
commit
e71e873d44
  1. 16
      CMakeLists.txt
  2. 18
      plip-sdl/Timer.h
  3. 30
      plip-sdl/TimerPosix.cpp
  4. 24
      plip-sdl/TimerPosix.h
  5. 45
      plip-sdl/TimerSdl.cpp
  6. 27
      plip-sdl/TimerSdl.h
  7. 16
      plip-sdl/main.cpp

16
CMakeLists.txt

@ -8,6 +8,12 @@ set(CMAKE_CXX_STANDARD 14)
find_package(SDL2 REQUIRED)
if(UNIX)
add_compile_definitions(UNIX)
elseif(WIN32)
add_compile_definitions(WIN32)
endif()
###########
# libplip #
###########
@ -42,6 +48,16 @@ add_executable(${gui_name}
plip-sdl/SdlWindow.cpp
)
if(UNIX)
target_sources(${gui_name} PRIVATE
plip-sdl/TimerPosix.cpp
)
else()
target_sources(${gui_name} PRIVATE
plip-sdl/TimerSdl.cpp
)
endif()
target_include_directories(${gui_name}
PRIVATE ${CMAKE_SOURCE_DIR}/libplip
PUBLIC ${SDL2_INCLUDE_DIRS}

18
plip-sdl/Timer.h

@ -0,0 +1,18 @@
/* Timer.h
*
* Implements an interface for a high precision timer and stopwatch.
*/
#pragma once
namespace PlipSdl {
class Timer {
public:
virtual void Nanosleep(long ns) = 0;
virtual void StopwatchStart() = 0;
virtual long StopwatchStop() = 0;
protected:
Timer() = default;
};
}

30
plip-sdl/TimerPosix.cpp

@ -0,0 +1,30 @@
/* TimerPosix.cpp
*/
#include "TimerPosix.h"
namespace PlipSdl {
#pragma clang diagnostic push
#pragma ide diagnostic ignored "cppcoreguidelines-pro-type-member-init"
void TimerPosix::Nanosleep(const long ns) {
const struct timespec req { // tv_nsec must be under 1 million
.tv_sec = ns / 1000000000,
.tv_nsec = ns % 1000000000
};
struct timespec rem; // Populated by nanosleep().
nanosleep(&req, nullptr);
}
void TimerPosix::StopwatchStart() {
clock_gettime(CLOCK_MONOTONIC, &m_stopwatchVal);
}
long TimerPosix::StopwatchStop() {
struct timespec end_val;
clock_gettime(CLOCK_MONOTONIC, &end_val);
return ((end_val.tv_sec - m_stopwatchVal.tv_sec) * 1000000)
+ (end_val.tv_nsec - m_stopwatchVal.tv_nsec);
}
#pragma clang diagnostic pop
}

24
plip-sdl/TimerPosix.h

@ -0,0 +1,24 @@
/* TimerPosix.h
*
* Uses the POSIX nanosleep function to maintain timing.
*/
#pragma once
#include <ctime>
#include "Timer.h"
namespace PlipSdl {
class TimerPosix : public Timer {
public:
TimerPosix() = default;
void Nanosleep(long ns) override;
void StopwatchStart() override;
long StopwatchStop() override;
private:
struct timespec m_stopwatchVal {};
};
}

45
plip-sdl/TimerSdl.cpp

@ -0,0 +1,45 @@
/* TimerSdl.h
*
* Uses SDL's delay function to maintain timing. Since SDL's only supports
* millisecond accuracy, using the native OS timing functions is preferred
* where possible.
*/
#include "TimerSdl.h"
#define MS_TO_NS(ms) ((ms) * 1000000)
#define NS_TO_MS(ns) ((ns) / 1000000)
namespace PlipSdl {
void TimerSdl::Nanosleep(const long ns) {
// SDL2's timing functions are only precise to the millisecond, so we
// save the lost precision and apply it to a future function call.
// This method is not suitable for repeated short delays, but is
// generally fine for maintaining timing.
Uint32 waitTime = NS_TO_MS(ns);
m_sleepSkew += (float)ns / 1000000 - waitTime;
if(m_sleepSkew >= 1) {
Uint32 skewAdd = (long)m_sleepSkew;
waitTime += skewAdd;
m_sleepSkew -= skewAdd;
}
if(waitTime > 0)
SDL_Delay(waitTime);
}
void TimerSdl::StopwatchStart() {
m_stopwatchVal = SDL_GetTicks();
}
long TimerSdl::StopwatchStop() {
Uint32 endVal = SDL_GetTicks();
if(endVal >= m_stopwatchVal)
return MS_TO_NS(endVal - m_stopwatchVal);
// The timer wraps around after 49 days. Try to cope with the stopwatch
// running for that length of time. :'(
return MS_TO_NS((UINT32_MAX - endVal) + m_stopwatchVal);
}
}

27
plip-sdl/TimerSdl.h

@ -0,0 +1,27 @@
/* TimerSdl.h
*
* Uses SDL's delay function to maintain timing. Since SDL's only supports
* millisecond accuracy, using the native OS timing functions is preferred
* where possible.
*/
#pragma once
#include <SDL.h>
#include "Timer.h"
namespace PlipSdl {
class TimerSdl : public Timer {
public:
TimerSdl() = default;
void Nanosleep(long ns) override;
void StopwatchStart() override;
long StopwatchStop() override;
private:
float m_sleepSkew = 0;
Uint32 m_stopwatchVal = 0;
};
}

16
plip-sdl/main.cpp

@ -11,7 +11,13 @@
#include "SdlEvent.h"
#include "SdlWindow.h"
void gameLoop(Plip::Plip *plip) {
#ifdef UNIX
#include "TimerPosix.h"
#else
#include "TimerSdl.h"
#endif
void gameLoop(Plip::Plip *plip, PlipSdl::Timer *timer) {
}
cxxopts::ParseResult parseCmdLine(int argc, char **argv) {
@ -76,7 +82,13 @@ int main(int argc, char **argv) {
auto event = new PlipSdl::SdlEvent();
auto plip = new Plip::Plip(event, wnd);
gameLoop(plip);
#ifdef UNIX
auto timer = new PlipSdl::TimerPosix();
#else
auto timer = new PlipSdl::TimerSdl();
#endif
gameLoop(plip, timer);
return 0;
}

Loading…
Cancel
Save