win: Unify Sys_Doubletime across NQ/QW/QWSV

NQ always used the high-precision timer API, and since I added a fallback
mode it should be fine to try for high precision first on all platforms
and fall back if necessary.

Also fixes some incorrect math in the timer wraparound case which
previously existed in QW client (wrong operator precedence).

Signed-off-by: Kevin Shanahan <kmshanah@disenchant.net>
This commit is contained in:
Kevin Shanahan 2012-10-19 21:59:27 +10:30
parent 89aa411b2a
commit 489ada1caa
3 changed files with 235 additions and 47 deletions

View File

@ -298,29 +298,6 @@ Sys_MakeCodeWriteable(unsigned long startaddr, unsigned long length)
Sys_Error("Protection change failed");
}
#ifndef USE_X86_ASM
void
Sys_SetFPCW(void)
{
}
void
Sys_PushFPCW_SetHigh(void)
{
}
void
Sys_PopFPCW(void)
{
}
void
MaskExceptions(void)
{
}
#endif
static void
Sys_InitTimers(void)
@ -927,4 +904,24 @@ void
Sys_LowFPPrecision(void)
{
}
void
Sys_SetFPCW(void)
{
}
void
Sys_PushFPCW_SetHigh(void)
{
}
void
Sys_PopFPCW(void)
{
}
void
MaskExceptions(void)
{
}
#endif

View File

@ -44,6 +44,12 @@ int starttime;
qboolean ActiveApp;
qboolean WinNT;
static double timer_pfreq;
static int timer_lowshift;
static unsigned int timer_oldtime;
static qboolean timer_fallback;
static DWORD timer_fallback_start;
HWND hwnd_dialog; // startup dialog box
HANDLE qwclsemaphore;
@ -149,6 +155,46 @@ Sys_MakeCodeWriteable(unsigned long startaddr, unsigned long length)
}
static void
Sys_InitTimers(void)
{
LARGE_INTEGER freq, pcount;
unsigned int lowpart, highpart;
MaskExceptions();
Sys_SetFPCW();
if (!QueryPerformanceFrequency(&freq)) {
Con_Printf("WARNING: No hardware timer available, using fallback\n");
timer_fallback = true;
timer_fallback_start = timeGetTime();
return;
}
/*
* get 32 out of the 64 time bits such that we have around
* 1 microsecond resolution
*/
lowpart = (unsigned int)freq.LowPart;
highpart = (unsigned int)freq.HighPart;
timer_lowshift = 0;
while (highpart || (lowpart > 2000000.0)) {
timer_lowshift++;
lowpart >>= 1;
lowpart |= (highpart & 1) << 31;
highpart >>= 1;
}
timer_pfreq = 1.0 / (double)lowpart;
/* Do first time initialisation */
Sys_PushFPCW_SetHigh();
QueryPerformanceCounter(&pcount);
timer_oldtime = (unsigned int)pcount.LowPart >> timer_lowshift;
timer_oldtime |= (unsigned int)pcount.HighPart << (32 - timer_lowshift);
Sys_PopFPCW();
}
/*
================
Sys_Init
@ -252,25 +298,51 @@ Sys_Quit(void)
double
Sys_DoubleTime(void)
{
static DWORD starttime;
static qboolean first = true;
DWORD now;
static double curtime = 0.0;
static double lastcurtime = 0.0;
static int sametimecount;
now = timeGetTime();
LARGE_INTEGER pcount;
unsigned int temp, t2;
double time;
if (first) {
first = false;
starttime = now;
return 0.0;
if (timer_fallback) {
DWORD now = timeGetTime();
if (now < timer_fallback_start) /* wrapped */
return (now + (LONG_MAX - timer_fallback_start)) / 1000.0;
return (now - timer_fallback_start) / 1000.0;
}
if (now < starttime) // wrapped?
return (now / 1000.0) + (LONG_MAX - starttime / 1000.0);
Sys_PushFPCW_SetHigh();
if (now - starttime == 0)
return 0.0;
QueryPerformanceCounter(&pcount);
return (now - starttime) / 1000.0;
temp = (unsigned int)pcount.LowPart >> timer_lowshift;
temp |= (unsigned int)pcount.HighPart << (32 - timer_lowshift);
/* check for turnover or backward time */
if ((temp <= timer_oldtime) && ((timer_oldtime - temp) < 0x10000000)) {
timer_oldtime = temp; /* so we don't get stuck */
} else {
t2 = temp - timer_oldtime;
time = (double)t2 * timer_pfreq;
timer_oldtime = temp;
curtime += time;
if (curtime == lastcurtime) {
sametimecount++;
if (sametimecount > 100000) {
curtime += 1.0;
sametimecount = 0;
}
} else {
sametimecount = 0;
}
lastcurtime = curtime;
}
Sys_PopFPCW();
return curtime;
}
void
@ -439,6 +511,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
Sys_Error("Couldn't create event");
Sys_Init();
Sys_InitTimers();
// because sound is off until we become active
S_BlockSound();
@ -485,6 +558,16 @@ Sys_SetFPCW(void)
{
}
void
Sys_PushFPCW_SetHigh(void)
{
}
void
Sys_PopFPCW(void)
{
}
void
MaskExceptions(void)
{

View File

@ -17,19 +17,29 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <sys/types.h>
#include <sys/timeb.h>
#include <winsock.h>
#include <windows.h>
#include <conio.h>
#include <direct.h>
#include <limits.h>
#include "qwsvdef.h"
#include "common.h"
#include "console.h"
#include "server.h"
#include "sys.h"
static cvar_t sys_nostdout = { "sys_nostdout", "0" };
static double timer_pfreq;
static int timer_lowshift;
static unsigned int timer_oldtime;
static qboolean timer_fallback;
static DWORD timer_fallback_start;
void MaskExceptions(void);
void Sys_PopFPCW(void);
void Sys_PushFPCW_SetHigh(void);
/*
================
Sys_FileTime
@ -61,6 +71,47 @@ Sys_mkdir(const char *path)
}
static void
Sys_InitTimers(void)
{
LARGE_INTEGER freq, pcount;
unsigned int lowpart, highpart;
MaskExceptions();
Sys_SetFPCW();
if (!QueryPerformanceFrequency(&freq)) {
Con_Printf("WARNING: No hardware timer available, using fallback\n");
timer_fallback = true;
timer_fallback_start = timeGetTime();
return;
}
/*
* get 32 out of the 64 time bits such that we have around
* 1 microsecond resolution
*/
lowpart = (unsigned int)freq.LowPart;
highpart = (unsigned int)freq.HighPart;
timer_lowshift = 0;
while (highpart || (lowpart > 2000000.0)) {
timer_lowshift++;
lowpart >>= 1;
lowpart |= (highpart & 1) << 31;
highpart >>= 1;
}
timer_pfreq = 1.0 / (double)lowpart;
/* Do first time initialisation */
Sys_PushFPCW_SetHigh();
QueryPerformanceCounter(&pcount);
timer_oldtime = (unsigned int)pcount.LowPart >> timer_lowshift;
timer_oldtime |= (unsigned int)pcount.HighPart << (32 - timer_lowshift);
Sys_PopFPCW();
}
/*
================
Sys_Error
@ -91,17 +142,51 @@ Sys_DoubleTime
double
Sys_DoubleTime(void)
{
double t;
struct _timeb tstruct;
static int starttime;
static double curtime = 0.0;
static double lastcurtime = 0.0;
static int sametimecount;
_ftime(&tstruct);
LARGE_INTEGER pcount;
unsigned int temp, t2;
double time;
if (!starttime)
starttime = tstruct.time;
t = (tstruct.time - starttime) + tstruct.millitm * 0.001;
if (timer_fallback) {
DWORD now = timeGetTime();
if (now < timer_fallback_start) /* wrapped */
return (now + (LONG_MAX - timer_fallback_start)) / 1000.0;
return (now - timer_fallback_start) / 1000.0;
}
return t;
Sys_PushFPCW_SetHigh();
QueryPerformanceCounter(&pcount);
temp = (unsigned int)pcount.LowPart >> timer_lowshift;
temp |= (unsigned int)pcount.HighPart << (32 - timer_lowshift);
/* check for turnover or backward time */
if ((temp <= timer_oldtime) && ((timer_oldtime - temp) < 0x10000000)) {
timer_oldtime = temp; /* so we don't get stuck */
} else {
t2 = temp - timer_oldtime;
time = (double)t2 * timer_pfreq;
timer_oldtime = temp;
curtime += time;
if (curtime == lastcurtime) {
sametimecount++;
if (sametimecount > 100000) {
curtime += 1.0;
sametimecount = 0;
}
} else {
sametimecount = 0;
}
lastcurtime = curtime;
}
Sys_PopFPCW();
return curtime;
}
@ -195,6 +280,7 @@ void
Sys_Init(void)
{
Cvar_RegisterVariable(&sys_nostdout);
Sys_InitTimers();
}
/*
@ -266,3 +352,25 @@ main(int argc, char **argv)
return true;
}
#ifndef USE_X86_ASM
void
Sys_SetFPCW(void)
{
}
void
Sys_PushFPCW_SetHigh(void)
{
}
void
Sys_PopFPCW(void)
{
}
void
MaskExceptions(void)
{
}
#endif