Add Lua bindings for RegionMap and region list
[ardour.git] / libs / pbd / windows_timer_utils.cc
index fcf8fa80038586cc39ce5507139bf4684ae90073..0fab935b082e5f0c4709e16040fd360e16b085d7 100644 (file)
 
 #include "pbd/compose.h"
 #include "pbd/debug.h"
+#include "pbd/error.h"
+
+#include "pbd/i18n.h"
 
 #define DEBUG_TIMING(msg) DEBUG_TRACE (PBD::DEBUG::Timing, msg);
 
 namespace {
 
+static
 UINT&
-old_timer_resolution ()
+timer_resolution ()
 {
        static UINT timer_res_ms = 0;
        return timer_res_ms;
 }
 
-} // anon namespace
+} // namespace
 
 namespace PBD {
 
 namespace MMTIMERS {
 
 bool
-set_min_resolution ()
+get_min_resolution (uint32_t& min_resolution_ms)
 {
        TIMECAPS caps;
 
@@ -50,61 +54,58 @@ set_min_resolution ()
                DEBUG_TIMING ("Could not get timer device capabilities.\n");
                return false;
        }
-       return set_resolution(caps.wPeriodMin);
+
+       min_resolution_ms = caps.wPeriodMin;
+       return true;
 }
 
 bool
-set_resolution (uint32_t timer_resolution_ms)
+set_min_resolution ()
 {
-       TIMECAPS caps;
+       uint32_t min_resolution = 0;
 
-       if (timeGetDevCaps (&caps, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
-               DEBUG_TIMING ("Could not get timer device capabilities.\n");
+       if (!get_min_resolution (min_resolution)) {
                return false;
        }
 
-       UINT old_timer_res = caps.wPeriodMin;
-
-       if (timeBeginPeriod(timer_resolution_ms) != TIMERR_NOERROR) {
-               DEBUG_TIMING(
-                   string_compose("Could not set minimum timer resolution to %1(ms)\n",
-                                  timer_resolution_ms));
+       if (!set_resolution (min_resolution)) {
                return false;
        }
-
-       old_timer_resolution () = old_timer_res;
-
-       DEBUG_TIMING (string_compose ("Multimedia timer resolution set to %1(ms)\n",
-                                     caps.wPeriodMin));
        return true;
 }
 
 bool
-get_resolution (uint32_t& timer_resolution_ms)
+set_resolution (uint32_t timer_resolution_ms)
 {
-       TIMECAPS caps;
+       if (timer_resolution() != 0) {
+               DEBUG_TIMING(
+                   "Timer resolution must be reset before setting new resolution.\n");
+       }
 
-       if (timeGetDevCaps(&caps, sizeof(TIMECAPS)) != TIMERR_NOERROR) {
-               DEBUG_TIMING ("Could not get timer device capabilities.\n");
+       if (timeBeginPeriod(timer_resolution_ms) != TIMERR_NOERROR) {
+               DEBUG_TIMING(
+                   string_compose("Could not set timer resolution to %1(ms)\n",
+                                  timer_resolution_ms));
                return false;
        }
-       timer_resolution_ms = caps.wPeriodMin;
+
+       timer_resolution() = timer_resolution_ms;
+
+       DEBUG_TIMING (string_compose ("Multimedia timer resolution set to %1(ms)\n",
+                                     timer_resolution_ms));
        return true;
 }
 
 bool
 reset_resolution ()
 {
-       if (old_timer_resolution ()) {
-               if (timeEndPeriod (old_timer_resolution ()) != TIMERR_NOERROR) {
-                       DEBUG_TIMING ("Could not reset timer resolution.\n");
-                       return false;
-               }
+       // You must match calls to timeBegin/EndPeriod with the same resolution
+       if (timeEndPeriod(timer_resolution()) != TIMERR_NOERROR) {
+               DEBUG_TIMING("Could not reset the Timer resolution.\n");
+               return false;
        }
-
-       DEBUG_TIMING (string_compose ("Multimedia timer resolution set to %1(ms)\n",
-                                     old_timer_resolution ()));
-
+       DEBUG_TIMING("Reset the Timer resolution.\n");
+       timer_resolution() = 0;
        return true;
 }
 
@@ -112,32 +113,23 @@ reset_resolution ()
 
 namespace {
 
-bool&
-qpc_frequency_success ()
-{
-       static bool success = false;
-       return success;
-}
+static double timer_rate_us = 0.0;
 
-LARGE_INTEGER
-qpc_frequency ()
+static
+bool
+test_qpc_validity ()
 {
-       LARGE_INTEGER freq;
-       if (QueryPerformanceFrequency(&freq) == 0) {
-               DEBUG_TIMING ("Failed to determine frequency of QPC\n");
-               qpc_frequency_success() = false;
-       } else {
-               qpc_frequency_success() = true;
+       int64_t last_timer_val = PBD::QPC::get_microseconds ();
+       if (last_timer_val < 0) return false;
+
+       for (int i = 0; i < 100000; ++i) {
+               int64_t timer_val = PBD::QPC::get_microseconds ();
+               if (timer_val < 0) return false;
+               // try and test for non-syncronized TSC(AMD K8/etc)
+               if (timer_val < last_timer_val) return false;
+               last_timer_val = timer_val;
        }
-
-       return freq;
-}
-
-LARGE_INTEGER
-qpc_frequency_cached ()
-{
-       static LARGE_INTEGER frequency = qpc_frequency ();
-       return frequency;
+       return true;
 }
 
 } // anon namespace
@@ -145,11 +137,27 @@ qpc_frequency_cached ()
 namespace QPC {
 
 bool
-get_timer_valid ()
+check_timer_valid ()
 {
-       // setup caching the timer frequency
-       qpc_frequency_cached ();
-       return qpc_frequency_success ();
+       if (!timer_rate_us) {
+               return false;
+       }
+       return test_qpc_validity ();
+}
+
+bool
+initialize ()
+{
+       LARGE_INTEGER freq;
+       if (!QueryPerformanceFrequency(&freq) || freq.QuadPart < 1) {
+               info << X_("Failed to determine frequency of QPC\n") << endmsg;
+               timer_rate_us = 0;
+       } else {
+               timer_rate_us = 1000000.0 / freq.QuadPart;
+       }
+       info << string_compose(X_("QPC timer microseconds per tick: %1\n"),
+                              timer_rate_us) << endmsg;
+       return !timer_rate_us;
 }
 
 int64_t
@@ -157,12 +165,11 @@ get_microseconds ()
 {
        LARGE_INTEGER current_val;
 
-       if (qpc_frequency_success()) {
+       if (timer_rate_us) {
                // MS docs say this will always succeed for systems >= XP but it may
                // not return a monotonic value with non-invariant TSC's etc
                if (QueryPerformanceCounter(&current_val) != 0) {
-                       return (int64_t)(((double)current_val.QuadPart) /
-                                        ((double)qpc_frequency_cached().QuadPart) * 1000000.0);
+                       return (int64_t)(current_val.QuadPart * timer_rate_us);
                }
        }
        DEBUG_TIMING ("Could not get QPC timer\n");
@@ -174,7 +181,7 @@ get_microseconds ()
 int64_t
 get_microseconds ()
 {
-       if (qpc_frequency_success()) {
+       if (timer_rate_us) {
                return QPC::get_microseconds ();
        }
        // For XP systems that don't support a high-res performance counter