// Windows layer-independent code #include #include "compat.h" #include "build.h" #include "baselayer.h" #include "osd.h" #include "cache1d.h" #include "zstring.h" #include "winbits.h" FString progdir; // // CheckWinVersion() -- check to see what version of Windows we happen to be running under (stripped down to what is actually still supported.) // void win_init(void) { const char *ver = ""; OSVERSIONINFOEXA osv; osv.dwOSVersionInfoSize = sizeof(osv); GetVersionExA((LPOSVERSIONINFOA)&osv); switch (osv.dwPlatformId) { case VER_PLATFORM_WIN32_NT: switch (osv.dwMajorVersion) { case 6: switch (osv.dwMinorVersion) { case 0: ver = osv.wProductType == VER_NT_WORKSTATION ? "Vista" : "Server 2008"; break; case 1: ver = osv.wProductType == VER_NT_WORKSTATION ? "7" : "Server 2008 R2"; break; case 2: ver = osv.wProductType == VER_NT_WORKSTATION ? "8" : "Server 2012"; break; case 3: ver = osv.wProductType == VER_NT_WORKSTATION ? "8.1" : "Server 2012 R2"; break; } break; case 10: switch (osv.dwMinorVersion) { case 0: ver = osv.wProductType == VER_NT_WORKSTATION ? "10" : "Server 2016"; break; } break; } break; } FStringf str("Windows %s", ver); // service packs if (osv.szCSDVersion[0]) { str.AppendFormat(" %s", osv.szCSDVersion); } initprintf("Running on %s (build %lu.%lu.%lu)\n", str.GetChars(), osv.dwMajorVersion, osv.dwMinorVersion, osv.dwBuildNumber); } //========================================================================== // // win_buildargs // // This should be removed once everything can use the FArgs list. // //========================================================================== int32_t win_buildargs(char **argvbuf) { int32_t buildargc = 0; FString cmdline_utf8 = FString(GetCommandLineW()); *argvbuf = Xstrdup(cmdline_utf8.GetChars()); if (*argvbuf) { char quoted = 0, instring = 0, swallownext = 0; char *wp; for (const char *p = wp = *argvbuf; *p; p++) { if (*p == ' ') { if (instring) { if (!quoted) { // end of a string *(wp++) = 0; instring = 0; } else *(wp++) = *p; } } else if (*p == '"' && !swallownext) { if (instring) { if (quoted && p[1] == ' ') { // end of a string *(wp++) = 0; instring = 0; } quoted = !quoted; } else { instring = 1; quoted = 1; buildargc++; } } else if (*p == '\\' && p[1] == '"' && !swallownext) swallownext = 1; else { if (!instring) buildargc++; instring = 1; *(wp++) = *p; swallownext = 0; } } *wp = 0; } // Figure out what directory the program resides in. progdir = argvbuf[0]; auto lastsep = progdir.LastIndexOf('/'); if (lastsep != -1) progdir.Truncate(lastsep + 1); return buildargc; } //========================================================================== // // CalculateCPUSpeed // // Make a decent guess at how much time elapses between TSC steps. This can // vary over runtime depending on power management settings, so should not // be used anywhere that truely accurate timing actually matters. // //========================================================================== double PerfToSec, PerfToMillisec; #include "stats.h" static void CalculateCPUSpeed() { LARGE_INTEGER freq; QueryPerformanceFrequency(&freq); if (freq.QuadPart != 0) { LARGE_INTEGER count1, count2; cycle_t ClockCalibration; DWORD min_diff; ClockCalibration.Reset(); // Count cycles for at least 55 milliseconds. // The performance counter may be very low resolution compared to CPU // speeds today, so the longer we count, the more accurate our estimate. // On the other hand, we don't want to count too long, because we don't // want the user to notice us spend time here, since most users will // probably never use the performance statistics. min_diff = freq.LowPart * 11 / 200; // Minimize the chance of task switching during the testing by going very // high priority. This is another reason to avoid timing for too long. SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); // Make sure we start timing on a counter boundary. QueryPerformanceCounter(&count1); do { QueryPerformanceCounter(&count2); } while (count1.QuadPart == count2.QuadPart); // Do the timing loop. ClockCalibration.Clock(); do { QueryPerformanceCounter(&count1); } while ((count1.QuadPart - count2.QuadPart) < min_diff); ClockCalibration.Unclock(); SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); PerfToSec = double(count1.QuadPart - count2.QuadPart) / (double(ClockCalibration.GetRawCounter()) * freq.QuadPart); PerfToMillisec = PerfToSec * 1000.0; } } class Initer { public: Initer() { CalculateCPUSpeed(); } }; static Initer initer;