+double Sys_DoubleTime(void)
+{
+ static int first = true;
+ static double oldtime = 0.0, curtime = 0.0;
+ double newtime;
+ if(sys_usenoclockbutbenchmark.integer)
+ {
+ double old_benchmark_time = benchmark_time;
+ benchmark_time += 1;
+ if(benchmark_time == old_benchmark_time)
+ Sys_Error("sys_usenoclockbutbenchmark cannot run any longer, sorry");
+ return benchmark_time * 0.000001;
+ }
+
+ // first all the OPTIONAL timers
+
+#if HAVE_QUERYPERFORMANCECOUNTER
+ else if (sys_usequeryperformancecounter.integer)
+ {
+ // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
+ // QueryPerformanceCounter
+ // platform:
+ // Windows 95/98/ME/NT/2000/XP
+ // features:
+ // very accurate (CPU cycles)
+ // known issues:
+ // does not necessarily match realtime too well (tends to get faster and faster in win98)
+ // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
+ double timescale;
+ LARGE_INTEGER PerformanceFreq;
+ LARGE_INTEGER PerformanceCount;
+
+ if (!QueryPerformanceFrequency (&PerformanceFreq))
+ {
+ Con_Printf ("No hardware timer available\n");
+ // fall back to timeGetTime
+ Cvar_SetValueQuick(&sys_usequeryperformancecounter, false);
+ return Sys_DoubleTime();
+ }
+ QueryPerformanceCounter (&PerformanceCount);
+
+ #ifdef __BORLANDC__
+ timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
+ newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
+ #else
+ timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
+ newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
+ #endif
+ }
+#endif
+
+#if HAVE_CLOCKGETTIME
+ else if (sys_useclockgettime.integer)
+ {
+ struct timespec ts;
+# ifdef CLOCK_MONOTONIC
+ // linux
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+# else
+ // sunos
+ clock_gettime(CLOCK_HIGHRES, &ts);
+# endif
+ newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
+ }
+#endif
+
+ // now all the FALLBACK timers
+ else if(sys_supportsdlgetticks && sys_usesdlgetticks.integer)
+ {
+ newtime = (double) Sys_SDL_GetTicks() / 1000.0;
+ }
+#if HAVE_GETTIMEOFDAY
+ else
+ {
+ struct timeval tp;
+ gettimeofday(&tp, NULL);
+ newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
+ }
+#elif HAVE_TIMEGETTIME
+ else
+ {
+ static int firsttimegettime = true;
+ // timeGetTime
+ // platform:
+ // Windows 95/98/ME/NT/2000/XP
+ // features:
+ // reasonable accuracy (millisecond)
+ // issues:
+ // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
+
+ // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
+ if (firsttimegettime)
+ {
+ timeBeginPeriod (1);
+ firsttimegettime = false;
+ }
+
+ newtime = (double) timeGetTime () / 1000.0;
+ }
+#else
+ // fallback for using the SDL timer if no other timer is available
+ else
+ {
+ newtime = (double) Sys_SDL_GetTicks() / 1000.0;
+ // this calls Sys_Error() if not linking against SDL
+ }
+#endif
+
+ if (first)
+ {
+ first = false;
+ oldtime = newtime;
+ }
+
+ if (newtime < oldtime)
+ {
+ // warn if it's significant
+ if (newtime - oldtime < -0.01)
+ Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
+ }
+ else if (newtime > oldtime + 1800)
+ {
+ Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
+ }
+ else
+ curtime += newtime - oldtime;
+ oldtime = newtime;
+
+ return curtime;
+}
+
+void Sys_Sleep(int microseconds)
+{
+ double t = 0;
+ if(sys_usenoclockbutbenchmark.integer)
+ {
+ if(microseconds)
+ {
+ double old_benchmark_time = benchmark_time;
+ benchmark_time += microseconds;
+ if(benchmark_time == old_benchmark_time)
+ Sys_Error("sys_usenoclockbutbenchmark cannot run any longer, sorry");
+ }
+ return;
+ }
+ if(sys_debugsleep.integer)
+ {
+ t = Sys_DoubleTime();
+ }
+ if(sys_supportsdlgetticks && sys_usesdldelay.integer)
+ {
+ Sys_SDL_Delay(microseconds / 1000);
+ }
+#if HAVE_SELECT
+ else
+ {
+ struct timeval tv;
+ tv.tv_sec = microseconds / 1000000;
+ tv.tv_usec = microseconds % 1000000;
+ select(0, NULL, NULL, NULL, &tv);
+ }
+#elif HAVE_USLEEP
+ else
+ {
+ usleep(microseconds);
+ }
+#elif HAVE_Sleep
+ else
+ {
+ Sleep(microseconds / 1000);
+ }
+#else
+ else
+ {
+ Sys_SDL_Delay(microseconds / 1000);
+ }
+#endif
+ if(sys_debugsleep.integer)
+ {
+ t = Sys_DoubleTime() - t;
+ printf("%d %d # debugsleep\n", microseconds, (unsigned int)(t * 1000000));
+ }
+}
+
+const char *Sys_FindInPATH(const char *name, char namesep, const char *PATH, char pathsep, char *buf, size_t bufsize)
+{
+ const char *p = PATH;
+ const char *q;
+ if(p && name)
+ {
+ while((q = strchr(p, ':')))
+ {
+ dpsnprintf(buf, bufsize, "%.*s%c%s", (int)(q-p), p, namesep, name);
+ if(FS_SysFileExists(buf))
+ return buf;
+ p = q + 1;
+ }
+ if(!q) // none found - try the last item
+ {
+ dpsnprintf(buf, bufsize, "%s%c%s", p, namesep, name);
+ if(FS_SysFileExists(buf))
+ return buf;
+ }
+ }
+ return name;
+}
+
+const char *Sys_FindExecutableName(void)
+{
+#if defined(WIN32)
+ return com_argv[0];
+#else
+ static char exenamebuf[MAX_OSPATH+1];
+ ssize_t n = -1;
+#if defined(__FreeBSD__)
+ n = readlink("/proc/curproc/file", exenamebuf, sizeof(exenamebuf)-1);
+#elif defined(__linux__)
+ n = readlink("/proc/self/exe", exenamebuf, sizeof(exenamebuf)-1);
+#endif
+ if(n > 0 && (size_t)(n) < sizeof(exenamebuf))
+ {
+ exenamebuf[n] = 0;
+ return exenamebuf;
+ }
+ if(strchr(com_argv[0], '/'))
+ return com_argv[0]; // possibly a relative path
+ else
+ return Sys_FindInPATH(com_argv[0], '/', getenv("PATH"), ':', exenamebuf, sizeof(exenamebuf));
+#endif
+}
+
+void Sys_ProvideSelfFD(void)
+{
+ if(com_selffd != -1)
+ return;
+ com_selffd = FS_SysOpenFD(Sys_FindExecutableName(), "rb", false);
+}
+
+// for x86 cpus only... (x64 has SSE2_PRESENT)
+#if defined(SSE_POSSIBLE) && !defined(SSE2_PRESENT)
+// code from SDL, shortened as we can expect CPUID to work
+static int CPUID_Features(void)
+{
+ int features = 0;
+# if defined(__GNUC__) && defined(__i386__)
+ __asm__ (
+" movl %%ebx,%%edi\n"
+" xorl %%eax,%%eax \n"
+" incl %%eax \n"
+" cpuid # Get family/model/stepping/features\n"
+" movl %%edx,%0 \n"
+" movl %%edi,%%ebx\n"
+ : "=m" (features)
+ :
+ : "%eax", "%ecx", "%edx", "%edi"
+ );
+# elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
+ __asm {
+ xor eax, eax
+ inc eax
+ cpuid ; Get family/model/stepping/features
+ mov features, edx
+ }
+# else
+# error SSE_POSSIBLE set but no CPUID implementation
+# endif
+ return features;
+}
+
+qboolean Sys_HaveSSE(void)
+{
+ // COMMANDLINEOPTION: SSE: -nosse disables SSE support and detection
+ if(COM_CheckParm("-nosse"))
+ return false;
+ // COMMANDLINEOPTION: SSE: -forcesse enables SSE support and disables detection
+ if(COM_CheckParm("-forcesse") || COM_CheckParm("-forcesse2"))
+ return true;
+ if(CPUID_Features() & (1 << 25))
+ return true;
+ return false;
+}
+
+qboolean Sys_HaveSSE2(void)
+{
+ // COMMANDLINEOPTION: SSE2: -nosse2 disables SSE2 support and detection
+ if(COM_CheckParm("-nosse") || COM_CheckParm("-nosse2"))
+ return false;
+ // COMMANDLINEOPTION: SSE2: -forcesse2 enables SSE2 support and disables detection
+ if(COM_CheckParm("-forcesse2"))
+ return true;
+ if((CPUID_Features() & (3 << 25)) == (3 << 25)) // SSE is 1<<25, SSE2 is 1<<26
+ return true;
+ return false;
+}
+#endif