raze/source/platform/win32/winbits.cpp
2019-10-19 19:22:23 +02:00

213 lines
5.9 KiB
C++

// Windows layer-independent code
#include <Windows.h>
#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];
progdir.Substitute("\\", "/");
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;