2012-11-25 04:26:37 +00:00
|
|
|
// Windows layer-independent code
|
|
|
|
|
2014-07-06 00:11:58 +00:00
|
|
|
#include "compat.h"
|
2012-11-25 04:26:37 +00:00
|
|
|
#include "build.h"
|
|
|
|
#include "baselayer.h"
|
2013-01-04 23:42:43 +00:00
|
|
|
#include "osd.h"
|
2013-03-21 09:48:21 +00:00
|
|
|
#include "cache1d.h"
|
2019-09-25 20:38:47 +00:00
|
|
|
#include "zstring.h"
|
2012-11-25 04:26:37 +00:00
|
|
|
#include "winbits.h"
|
|
|
|
|
2019-10-04 21:29:00 +00:00
|
|
|
FString progdir;
|
2012-11-25 04:26:37 +00:00
|
|
|
//
|
2019-09-25 20:38:47 +00:00
|
|
|
// CheckWinVersion() -- check to see what version of Windows we happen to be running under (stripped down to what is actually still supported.)
|
2012-11-25 04:26:37 +00:00
|
|
|
//
|
|
|
|
|
2019-09-25 20:38:47 +00:00
|
|
|
void win_init(void)
|
2012-11-25 04:26:37 +00:00
|
|
|
{
|
|
|
|
const char *ver = "";
|
2019-09-25 20:38:47 +00:00
|
|
|
OSVERSIONINFOEXA osv;
|
2012-11-25 04:26:37 +00:00
|
|
|
|
2019-09-25 20:38:47 +00:00
|
|
|
osv.dwOSVersionInfoSize = sizeof(osv);
|
|
|
|
GetVersionExA((LPOSVERSIONINFOA)&osv);
|
|
|
|
|
2012-11-25 04:26:37 +00:00
|
|
|
switch (osv.dwPlatformId)
|
|
|
|
{
|
2015-01-11 04:52:45 +00:00
|
|
|
case VER_PLATFORM_WIN32_NT:
|
|
|
|
switch (osv.dwMajorVersion)
|
2012-11-25 04:26:37 +00:00
|
|
|
{
|
2015-01-11 04:52:45 +00:00
|
|
|
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)
|
|
|
|
{
|
2016-02-29 06:34:04 +00:00
|
|
|
case 0: ver = osv.wProductType == VER_NT_WORKSTATION ? "10" : "Server 2016"; break;
|
2015-01-11 04:52:45 +00:00
|
|
|
}
|
|
|
|
break;
|
2012-11-25 04:26:37 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-09-25 20:38:47 +00:00
|
|
|
FStringf str("Windows %s", ver);
|
2015-01-11 04:53:01 +00:00
|
|
|
|
|
|
|
// service packs
|
2015-01-12 01:54:50 +00:00
|
|
|
if (osv.szCSDVersion[0])
|
2015-01-11 04:53:01 +00:00
|
|
|
{
|
2019-09-25 20:38:47 +00:00
|
|
|
str.AppendFormat(" %s", osv.szCSDVersion);
|
2015-01-11 04:53:01 +00:00
|
|
|
}
|
|
|
|
|
2019-09-25 20:38:47 +00:00
|
|
|
initprintf("Running on %s (build %lu.%lu.%lu)\n", str.GetChars(), osv.dwMajorVersion, osv.dwMinorVersion, osv.dwBuildNumber);
|
2012-11-25 04:26:37 +00:00
|
|
|
}
|
|
|
|
|
2019-09-25 20:38:47 +00:00
|
|
|
//==========================================================================
|
2013-10-07 10:05:41 +00:00
|
|
|
//
|
2019-09-25 20:38:47 +00:00
|
|
|
// win_buildargs
|
2013-10-07 10:05:41 +00:00
|
|
|
//
|
2019-09-25 20:38:47 +00:00
|
|
|
// This should be removed once everything can use the FArgs list.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2013-10-07 10:05:41 +00:00
|
|
|
|
2013-10-06 07:49:26 +00:00
|
|
|
|
2015-02-11 05:21:50 +00:00
|
|
|
int32_t win_buildargs(char **argvbuf)
|
|
|
|
{
|
|
|
|
int32_t buildargc = 0;
|
2019-09-25 20:38:47 +00:00
|
|
|
|
|
|
|
FString cmdline_utf8 = FString(GetCommandLineW());
|
2015-02-11 05:21:50 +00:00
|
|
|
|
2019-09-25 20:38:47 +00:00
|
|
|
*argvbuf = Xstrdup(cmdline_utf8.GetChars());
|
2015-02-11 05:21:50 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-10-04 21:29:00 +00:00
|
|
|
// Figure out what directory the program resides in.
|
|
|
|
progdir = argvbuf[0];
|
|
|
|
auto lastsep = progdir.LastIndexOf('/');
|
|
|
|
if (lastsep != -1)
|
|
|
|
progdir.Truncate(lastsep + 1);
|
|
|
|
|
|
|
|
return buildargc;
|
2015-02-11 05:21:50 +00:00
|
|
|
}
|
|
|
|
|
2013-10-06 07:49:26 +00:00
|
|
|
|
2019-09-13 19:43:05 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// 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;
|
|
|
|
|