mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2025-03-08 10:24:32 +00:00
Merge branch 'framecounter_5th_try'
Like the branch name suggests this was a rather hard ride. Lessons learned: * Quake IIs timing is one big clusterfuck. * The Radeon driver for Windows has a questionable vsync implementation. What should be done: * Get rid of the global currenttime. * DEDICATED_ONLY needs to be refactored. This commit closes issue #222.
This commit is contained in:
commit
143c5d1e40
9 changed files with 348 additions and 239 deletions
src
backends
client
common
server
|
@ -38,13 +38,10 @@ qboolean is_portable;
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int time, oldtime, newtime;
|
|
||||||
int verLen, i;
|
int verLen, i;
|
||||||
|
long long oldtime, newtime;
|
||||||
const char* versionString;
|
const char* versionString;
|
||||||
|
struct timespec t = {0, 5000};
|
||||||
#ifndef BUSY_WAIT
|
|
||||||
struct timespec t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* register signal handler */
|
/* register signal handler */
|
||||||
registerHandler();
|
registerHandler();
|
||||||
|
@ -134,27 +131,16 @@ main(int argc, char **argv)
|
||||||
/* Do not delay reads on stdin*/
|
/* Do not delay reads on stdin*/
|
||||||
fcntl(fileno(stdin), F_SETFL, fcntl(fileno(stdin), F_GETFL, NULL) | FNDELAY);
|
fcntl(fileno(stdin), F_SETFL, fcntl(fileno(stdin), F_GETFL, NULL) | FNDELAY);
|
||||||
|
|
||||||
oldtime = Sys_Milliseconds();
|
oldtime = Sys_Microseconds();
|
||||||
t.tv_sec = 0;
|
|
||||||
|
|
||||||
/* The legendary Quake II mainloop */
|
/* The mainloop. The legend. */
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
/* find time spent rendering last frame */
|
// Throttle the game a little bit.
|
||||||
do
|
nanosleep(&t, NULL);
|
||||||
{
|
|
||||||
#ifndef BUSY_WAIT
|
|
||||||
/* Sleep 10 microseconds */
|
|
||||||
t.tv_nsec = 10000;
|
|
||||||
nanosleep(&t, NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
newtime = Sys_Milliseconds();
|
newtime = Sys_Microseconds();
|
||||||
time = newtime - oldtime;
|
Qcommon_Frame(newtime - oldtime);
|
||||||
}
|
|
||||||
while (time < 1);
|
|
||||||
|
|
||||||
Qcommon_Frame(time);
|
|
||||||
oldtime = newtime;
|
oldtime = newtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "../../common/header/common.h"
|
#include "../../common/header/common.h"
|
||||||
#include "../../common/header/glob.h"
|
#include "../../common/header/glob.h"
|
||||||
|
@ -79,32 +80,41 @@ Sys_Init(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long long
|
||||||
|
Sys_Microseconds(void)
|
||||||
|
{
|
||||||
|
static struct timespec last;
|
||||||
|
struct timespec now;
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
|
|
||||||
|
if(last.tv_sec == 0)
|
||||||
|
{
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &last);
|
||||||
|
return last.tv_nsec / 1000ll;
|
||||||
|
}
|
||||||
|
|
||||||
|
long long sec = now.tv_sec - last.tv_sec;
|
||||||
|
long long nsec = now.tv_nsec - last.tv_nsec;
|
||||||
|
|
||||||
|
if(nsec < 0)
|
||||||
|
{
|
||||||
|
nsec += 1000000000ll; // 1s in ns
|
||||||
|
--sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
curtime = (int)((sec*1000000ll + nsec/1000ll) / 1000ll);
|
||||||
|
return sec*1000000ll + nsec/1000ll;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Sys_Milliseconds(void)
|
Sys_Milliseconds(void)
|
||||||
{
|
{
|
||||||
struct timeval tp;
|
curtime = (int)(Sys_Microseconds()/1000ll);
|
||||||
struct timezone tzp;
|
|
||||||
static int secbase;
|
|
||||||
|
|
||||||
gettimeofday(&tp, &tzp);
|
|
||||||
|
|
||||||
if (!secbase)
|
|
||||||
{
|
|
||||||
secbase = tp.tv_sec;
|
|
||||||
return tp.tv_usec / 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
curtime = (tp.tv_sec - secbase) * 1000 + tp.tv_usec / 1000;
|
|
||||||
|
|
||||||
return curtime;
|
return curtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Sys_Sleep(int msec)
|
|
||||||
{
|
|
||||||
usleep((unsigned int)1000 * msec);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Sys_Mkdir(char *path)
|
Sys_Mkdir(char *path)
|
||||||
{
|
{
|
||||||
|
|
|
@ -414,19 +414,39 @@ ParseCommandLine(LPSTR lpCmdLine)
|
||||||
|
|
||||||
/* ======================================================================= */
|
/* ======================================================================= */
|
||||||
|
|
||||||
|
long long
|
||||||
|
Sys_Microseconds(void)
|
||||||
|
{
|
||||||
|
long long microseconds;
|
||||||
|
static long long uSecbase;
|
||||||
|
|
||||||
|
FILETIME ft;
|
||||||
|
unsigned long long tmpres = 0;
|
||||||
|
|
||||||
|
GetSystemTimeAsFileTime(&ft);
|
||||||
|
|
||||||
|
tmpres |= ft.dwHighDateTime;
|
||||||
|
tmpres <<= 32;
|
||||||
|
tmpres |= ft.dwLowDateTime;
|
||||||
|
|
||||||
|
tmpres /= 10; // Convert to microseconds.
|
||||||
|
tmpres -= 11644473600000000ULL; // ...and to unix epoch.
|
||||||
|
|
||||||
|
microseconds = tmpres;
|
||||||
|
|
||||||
|
if (!uSecbase)
|
||||||
|
{
|
||||||
|
uSecbase = microseconds - 1001;
|
||||||
|
}
|
||||||
|
|
||||||
|
curtime = (int)((microseconds - uSecbase) / 1000ll);
|
||||||
|
return microseconds - uSecbase;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Sys_Milliseconds(void)
|
Sys_Milliseconds(void)
|
||||||
{
|
{
|
||||||
static int base;
|
curtime = (int)(Sys_Microseconds()/1000ll);
|
||||||
static qboolean initialized = false;
|
|
||||||
|
|
||||||
if (!initialized)
|
|
||||||
{ /* let base retain 16 bits of effectively random data */
|
|
||||||
base = timeGetTime() & 0xffff0000;
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
curtime = timeGetTime() - base;
|
|
||||||
|
|
||||||
return curtime;
|
return curtime;
|
||||||
}
|
}
|
||||||
|
@ -437,6 +457,22 @@ Sys_Sleep(int msec)
|
||||||
Sleep(msec);
|
Sleep(msec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sys_Nanosleep(int nanosec)
|
||||||
|
{
|
||||||
|
HANDLE timer;
|
||||||
|
LARGE_INTEGER li;
|
||||||
|
|
||||||
|
timer = CreateWaitableTimer(NULL, TRUE, NULL);
|
||||||
|
|
||||||
|
// Windows has a max. resolution of 100ns.
|
||||||
|
li.QuadPart = -nanosec / 100;
|
||||||
|
|
||||||
|
SetWaitableTimer(timer, &li, 0, NULL, NULL, FALSE);
|
||||||
|
WaitForSingleObject(timer, INFINITE);
|
||||||
|
|
||||||
|
CloseHandle(timer);
|
||||||
|
}
|
||||||
|
|
||||||
/* ======================================================================= */
|
/* ======================================================================= */
|
||||||
|
|
||||||
static qboolean
|
static qboolean
|
||||||
|
@ -745,7 +781,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||||
LPSTR lpCmdLine, int nCmdShow)
|
LPSTR lpCmdLine, int nCmdShow)
|
||||||
{
|
{
|
||||||
MSG msg;
|
MSG msg;
|
||||||
int time, oldtime, newtime;
|
long long oldtime, newtime;
|
||||||
|
|
||||||
/* Previous instances do not exist in Win32 */
|
/* Previous instances do not exist in Win32 */
|
||||||
if (hPrevInstance)
|
if (hPrevInstance)
|
||||||
|
@ -817,7 +853,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||||
Qcommon_Init(argc, argv);
|
Qcommon_Init(argc, argv);
|
||||||
|
|
||||||
/* Save our time */
|
/* Save our time */
|
||||||
oldtime = Sys_Milliseconds();
|
oldtime = Sys_Microseconds();
|
||||||
|
|
||||||
/* The legendary main loop */
|
/* The legendary main loop */
|
||||||
while (1)
|
while (1)
|
||||||
|
@ -840,14 +876,11 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||||
DispatchMessage(&msg);
|
DispatchMessage(&msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
do
|
// Throttle the game a little bit
|
||||||
{
|
Sys_Nanosleep(5000);
|
||||||
newtime = Sys_Milliseconds();
|
|
||||||
time = newtime - oldtime;
|
|
||||||
}
|
|
||||||
while (time < 1);
|
|
||||||
|
|
||||||
Qcommon_Frame(time);
|
newtime = Sys_Microseconds();
|
||||||
|
Qcommon_Frame(newtime - oldtime);
|
||||||
oldtime = newtime;
|
oldtime = newtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,12 +35,6 @@ extern char key_lines[NUM_KEY_LINES][MAXCMDLINE];
|
||||||
extern int edit_line;
|
extern int edit_line;
|
||||||
extern int key_linepos;
|
extern int key_linepos;
|
||||||
|
|
||||||
void
|
|
||||||
DrawString(int x, int y, char *s)
|
|
||||||
{
|
|
||||||
DrawStringScaled(x, y, s, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
DrawStringScaled(int x, int y, char *s, float factor)
|
DrawStringScaled(int x, int y, char *s, float factor)
|
||||||
{
|
{
|
||||||
|
@ -52,12 +46,6 @@ DrawStringScaled(int x, int y, char *s, float factor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
DrawAltString(int x, int y, char *s)
|
|
||||||
{
|
|
||||||
DrawAltStringScaled(x, y, s, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
DrawAltStringScaled(int x, int y, char *s, float factor)
|
DrawAltStringScaled(int x, int y, char *s, float factor)
|
||||||
{
|
{
|
||||||
|
@ -452,29 +440,6 @@ Con_Print(char *txt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Con_CenteredPrint(char *text)
|
|
||||||
{
|
|
||||||
int l;
|
|
||||||
char buffer[1024];
|
|
||||||
|
|
||||||
l = strlen(text);
|
|
||||||
l = (con.linewidth - l) / 2;
|
|
||||||
|
|
||||||
if (l <= 0)
|
|
||||||
{
|
|
||||||
l = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memset(buffer, ' ', l);
|
|
||||||
}
|
|
||||||
|
|
||||||
strcpy(buffer + l, text);
|
|
||||||
strcat(buffer, "\n");
|
|
||||||
Con_Print(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The input line scrolls horizontally if
|
* The input line scrolls horizontally if
|
||||||
* typing goes beyond the right edge
|
* typing goes beyond the right edge
|
||||||
|
|
|
@ -44,21 +44,18 @@ cvar_t *cl_noskins;
|
||||||
cvar_t *cl_footsteps;
|
cvar_t *cl_footsteps;
|
||||||
cvar_t *cl_timeout;
|
cvar_t *cl_timeout;
|
||||||
cvar_t *cl_predict;
|
cvar_t *cl_predict;
|
||||||
cvar_t *cl_maxfps;
|
|
||||||
cvar_t *cl_drawfps;
|
cvar_t *cl_drawfps;
|
||||||
cvar_t *cl_gun;
|
cvar_t *cl_gun;
|
||||||
cvar_t *cl_add_particles;
|
cvar_t *cl_add_particles;
|
||||||
cvar_t *cl_add_lights;
|
cvar_t *cl_add_lights;
|
||||||
cvar_t *cl_add_entities;
|
cvar_t *cl_add_entities;
|
||||||
cvar_t *cl_add_blend;
|
cvar_t *cl_add_blend;
|
||||||
cvar_t *cl_async;
|
|
||||||
|
|
||||||
cvar_t *cl_shownet;
|
cvar_t *cl_shownet;
|
||||||
cvar_t *cl_showmiss;
|
cvar_t *cl_showmiss;
|
||||||
cvar_t *cl_showclamp;
|
cvar_t *cl_showclamp;
|
||||||
|
|
||||||
cvar_t *cl_paused;
|
cvar_t *cl_paused;
|
||||||
cvar_t *cl_timedemo;
|
|
||||||
|
|
||||||
cvar_t *lookspring;
|
cvar_t *lookspring;
|
||||||
cvar_t *lookstrafe;
|
cvar_t *lookstrafe;
|
||||||
|
@ -83,8 +80,6 @@ cvar_t *hand;
|
||||||
cvar_t *gender;
|
cvar_t *gender;
|
||||||
cvar_t *gender_auto;
|
cvar_t *gender_auto;
|
||||||
|
|
||||||
cvar_t *gl_maxfps;
|
|
||||||
|
|
||||||
cvar_t *gl_stereo;
|
cvar_t *gl_stereo;
|
||||||
cvar_t *gl_stereo_separation;
|
cvar_t *gl_stereo_separation;
|
||||||
cvar_t *gl_stereo_convergence;
|
cvar_t *gl_stereo_convergence;
|
||||||
|
@ -484,9 +479,7 @@ CL_InitLocal(void)
|
||||||
cl_footsteps = Cvar_Get("cl_footsteps", "1", 0);
|
cl_footsteps = Cvar_Get("cl_footsteps", "1", 0);
|
||||||
cl_noskins = Cvar_Get("cl_noskins", "0", 0);
|
cl_noskins = Cvar_Get("cl_noskins", "0", 0);
|
||||||
cl_predict = Cvar_Get("cl_predict", "1", 0);
|
cl_predict = Cvar_Get("cl_predict", "1", 0);
|
||||||
cl_maxfps = Cvar_Get("cl_maxfps", "60", CVAR_ARCHIVE);
|
|
||||||
cl_drawfps = Cvar_Get("cl_drawfps", "0", CVAR_ARCHIVE);
|
cl_drawfps = Cvar_Get("cl_drawfps", "0", CVAR_ARCHIVE);
|
||||||
cl_async = Cvar_Get("cl_async", "1", CVAR_ARCHIVE);
|
|
||||||
|
|
||||||
cl_upspeed = Cvar_Get("cl_upspeed", "200", 0);
|
cl_upspeed = Cvar_Get("cl_upspeed", "200", 0);
|
||||||
cl_forwardspeed = Cvar_Get("cl_forwardspeed", "200", 0);
|
cl_forwardspeed = Cvar_Get("cl_forwardspeed", "200", 0);
|
||||||
|
@ -511,9 +504,6 @@ CL_InitLocal(void)
|
||||||
cl_showclamp = Cvar_Get("showclamp", "0", 0);
|
cl_showclamp = Cvar_Get("showclamp", "0", 0);
|
||||||
cl_timeout = Cvar_Get("cl_timeout", "120", 0);
|
cl_timeout = Cvar_Get("cl_timeout", "120", 0);
|
||||||
cl_paused = Cvar_Get("paused", "0", 0);
|
cl_paused = Cvar_Get("paused", "0", 0);
|
||||||
cl_timedemo = Cvar_Get("timedemo", "0", 0);
|
|
||||||
|
|
||||||
gl_maxfps = Cvar_Get("gl_maxfps", "95", CVAR_ARCHIVE);
|
|
||||||
|
|
||||||
gl_stereo = Cvar_Get( "gl_stereo", "0", CVAR_ARCHIVE );
|
gl_stereo = Cvar_Get( "gl_stereo", "0", CVAR_ARCHIVE );
|
||||||
gl_stereo_separation = Cvar_Get( "gl_stereo_separation", "1", CVAR_ARCHIVE );
|
gl_stereo_separation = Cvar_Get( "gl_stereo_separation", "1", CVAR_ARCHIVE );
|
||||||
|
@ -711,60 +701,25 @@ CL_UpdateWindowedMouse(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int GLimp_GetRefreshRate(void);
|
|
||||||
qboolean R_IsVSyncActive(void);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CL_Frame(int msec)
|
CL_Frame(int packetdelta, int renderdelta, int miscdelta, int timedelta,
|
||||||
|
qboolean packetframe, qboolean renderframe, qboolean miscframe)
|
||||||
{
|
{
|
||||||
int nfps;
|
|
||||||
int rfps;
|
|
||||||
|
|
||||||
static int lasttimecalled;
|
static int lasttimecalled;
|
||||||
|
|
||||||
static int packetdelta = 1000;
|
// Dedicated?
|
||||||
static int renderdelta = 1000;
|
|
||||||
static int miscdelta = 1000;
|
|
||||||
|
|
||||||
qboolean packetframe = true;
|
|
||||||
qboolean renderframe = true;
|
|
||||||
qboolean miscframe = true;
|
|
||||||
|
|
||||||
if (dedicated->value)
|
if (dedicated->value)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Target render frame rate
|
// Calculate simulation time.
|
||||||
if (R_IsVSyncActive())
|
cls.nframetime = packetdelta / 1000000.0f;
|
||||||
{
|
cls.rframetime = renderdelta / 1000000.0f;
|
||||||
rfps = GLimp_GetRefreshRate();
|
|
||||||
|
|
||||||
if (rfps > gl_maxfps->value)
|
|
||||||
{
|
|
||||||
rfps = (int)gl_maxfps->value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rfps = (int)gl_maxfps->value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The network framerate must not be higher then the render framerate
|
|
||||||
nfps = (cl_maxfps->value > rfps) ? rfps : cl_maxfps->value;
|
|
||||||
|
|
||||||
// Adjust deltas
|
|
||||||
packetdelta += msec;
|
|
||||||
renderdelta += msec;
|
|
||||||
miscdelta += msec;
|
|
||||||
|
|
||||||
// Calculate simulation time
|
|
||||||
cls.nframetime = packetdelta * 0.001f;
|
|
||||||
cls.rframetime = renderdelta * 0.001f;
|
|
||||||
cls.realtime = curtime;
|
cls.realtime = curtime;
|
||||||
cl.time += msec;
|
cl.time += timedelta / 1000;
|
||||||
|
|
||||||
// Don't extrapolate too far ahead
|
// Don't extrapolate too far ahead.
|
||||||
if (cls.nframetime > 0.5f)
|
if (cls.nframetime > 0.5f)
|
||||||
{
|
{
|
||||||
cls.nframetime = 0.5f;
|
cls.nframetime = 0.5f;
|
||||||
|
@ -775,72 +730,19 @@ CL_Frame(int msec)
|
||||||
cls.rframetime = 0.5f;
|
cls.rframetime = 0.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if in the debugger last frame, don't timeout */
|
// if in the debugger last frame, don't timeout.
|
||||||
if (msec > 5000)
|
if (timedelta > 5000000)
|
||||||
{
|
{
|
||||||
cls.netchan.last_received = Sys_Milliseconds();
|
cls.netchan.last_received = Sys_Milliseconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cl_timedemo->value)
|
if (!cl_timedemo->value)
|
||||||
{
|
{
|
||||||
// Don't flood while connecting
|
// Don't throttle too much when connecting / loading.
|
||||||
if ((cls.state == ca_connected) && (packetdelta < 100))
|
if ((cls.state == ca_connected) && (packetdelta > 100000))
|
||||||
{
|
{
|
||||||
packetframe = false;
|
packetframe = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cl_async->value)
|
|
||||||
{
|
|
||||||
// Network frames
|
|
||||||
if (packetdelta < (1000.0f / nfps))
|
|
||||||
{
|
|
||||||
packetframe = false;
|
|
||||||
}
|
|
||||||
else if (cls.nframetime == cls.rframetime)
|
|
||||||
{
|
|
||||||
packetframe = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render frames
|
|
||||||
if (renderdelta < (1000.0f / rfps))
|
|
||||||
{
|
|
||||||
renderframe = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Misc. stuff at 10 FPS
|
|
||||||
if (miscdelta < 100.0f)
|
|
||||||
{
|
|
||||||
miscframe = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Cap frames at gl_maxfps
|
|
||||||
if (renderdelta < (1000.0f / rfps))
|
|
||||||
{
|
|
||||||
renderframe = false;
|
|
||||||
packetframe = false;
|
|
||||||
miscframe = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Throttle the game a little bit. 1000 FPS are enough.
|
|
||||||
if (!packetframe && !renderframe && !cls.forcePacket && !userinfo_modified)
|
|
||||||
{
|
|
||||||
double frametime = (1000.0 / cl_maxfps->value - packetdelta) <= (1000.0 / gl_maxfps->value - renderdelta) ?
|
|
||||||
(1000.0 / cl_maxfps->value - packetdelta) : (1000.0 / gl_maxfps->value - renderdelta);
|
|
||||||
|
|
||||||
if (frametime > 1) // FIXME: why > ??
|
|
||||||
{
|
|
||||||
Sys_Sleep(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (msec < 1)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update input stuff
|
// Update input stuff
|
||||||
|
@ -870,20 +772,14 @@ CL_Frame(int msec)
|
||||||
|
|
||||||
if (packetframe)
|
if (packetframe)
|
||||||
{
|
{
|
||||||
packetdelta = 0;
|
|
||||||
|
|
||||||
CL_SendCmd();
|
CL_SendCmd();
|
||||||
CL_CheckForResend();
|
CL_CheckForResend();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (renderframe)
|
if (renderframe)
|
||||||
{
|
{
|
||||||
renderdelta = 0;
|
|
||||||
|
|
||||||
if (miscframe)
|
if (miscframe)
|
||||||
{
|
{
|
||||||
miscdelta = 0;
|
|
||||||
|
|
||||||
VID_CheckChanges();
|
VID_CheckChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1410,6 +1410,84 @@ SCR_DrawLayout(void)
|
||||||
SCR_ExecuteLayoutString(cl.layout);
|
SCR_ExecuteLayoutString(cl.layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
|
|
||||||
|
void
|
||||||
|
SCR_Framecounter(void) {
|
||||||
|
long long newtime;
|
||||||
|
static int frame;
|
||||||
|
static int frametimes[60] = {0};
|
||||||
|
static long long oldtime;
|
||||||
|
|
||||||
|
newtime = Sys_Microseconds();
|
||||||
|
frametimes[frame] = (int)(newtime - oldtime);
|
||||||
|
|
||||||
|
oldtime = newtime;
|
||||||
|
frame++;
|
||||||
|
if (frame > 59) {
|
||||||
|
frame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float scale = SCR_GetConsoleScale();
|
||||||
|
|
||||||
|
if (cl_drawfps->value == 1) {
|
||||||
|
// Calculate average of frames.
|
||||||
|
int avg = 0;
|
||||||
|
int num = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 60; i++) {
|
||||||
|
if (frametimes[i] != 0) {
|
||||||
|
avg += frametimes[i];
|
||||||
|
num++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char str[10];
|
||||||
|
snprintf(str, sizeof(str), "%3.2ffps", (1000.0 * 1000.0) / (avg / num));
|
||||||
|
DrawStringScaled(scale*(viddef.width - 80), 0, str, scale);
|
||||||
|
} else if (cl_drawfps->value >= 2) {
|
||||||
|
// Calculate average of frames.
|
||||||
|
int avg = 0;
|
||||||
|
int num = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 60; i++) {
|
||||||
|
if (frametimes[i] != 0) {
|
||||||
|
avg += frametimes[i];
|
||||||
|
num++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Find lowest and highest
|
||||||
|
int min = frametimes[0];
|
||||||
|
int max = frametimes[1];
|
||||||
|
|
||||||
|
for (int i = 1; i < 60; i++) {
|
||||||
|
if ((frametimes[i] > 0) && (min < frametimes[i])) {
|
||||||
|
min = frametimes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((frametimes[i] > 0) && (max > frametimes[i])) {
|
||||||
|
max = frametimes[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char str[64];
|
||||||
|
snprintf(str, sizeof(str), "Min: %7.2ffps, Max: %7.2ffps, Avg: %7.2ffps",
|
||||||
|
(1000.0 * 1000.0) / min, (1000.0 * 1000.0) / max, (1000.0 * 1000.0) / (avg / num));
|
||||||
|
DrawStringScaled(viddef.width - scale*(strlen(str)*8 + 2), 0, str, scale);
|
||||||
|
|
||||||
|
if (cl_drawfps->value > 2)
|
||||||
|
{
|
||||||
|
snprintf(str, sizeof(str), "Max: %5.2fms, Min: %5.2fms, Avg: %5.2fms",
|
||||||
|
0.001f*min, 0.001f*max, 0.001f*(avg / num));
|
||||||
|
DrawStringScaled(viddef.width - scale*(strlen(str)*8 + 2), scale*10, str, scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----
|
||||||
/*
|
/*
|
||||||
* This is called every frame, and can also be called
|
* This is called every frame, and can also be called
|
||||||
* explicitly to flush text to the screen.
|
* explicitly to flush text to the screen.
|
||||||
|
@ -1535,13 +1613,6 @@ SCR_UpdateScreen(void)
|
||||||
SCR_DrawNet();
|
SCR_DrawNet();
|
||||||
SCR_CheckDrawCenterString();
|
SCR_CheckDrawCenterString();
|
||||||
|
|
||||||
if (cl_drawfps->value)
|
|
||||||
{
|
|
||||||
char s[8];
|
|
||||||
sprintf(s, "%3.0ffps", 1 / cls.rframetime);
|
|
||||||
DrawString(viddef.width - 64, 0, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (scr_timegraph->value)
|
if (scr_timegraph->value)
|
||||||
{
|
{
|
||||||
SCR_DebugGraph(cls.rframetime * 300, 0);
|
SCR_DebugGraph(cls.rframetime * 300, 0);
|
||||||
|
@ -1563,6 +1634,7 @@ SCR_UpdateScreen(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SCR_Framecounter();
|
||||||
R_EndFrame();
|
R_EndFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -766,8 +766,7 @@ void Sys_Error(char *error, ...);
|
||||||
void Sys_Quit(void);
|
void Sys_Quit(void);
|
||||||
char *Sys_GetHomeDir(void);
|
char *Sys_GetHomeDir(void);
|
||||||
const char *Sys_GetBinaryDir(void);
|
const char *Sys_GetBinaryDir(void);
|
||||||
void Sys_Sleep(int msec);
|
long long Sys_Microseconds(void);
|
||||||
|
|
||||||
void Sys_FreeLibrary(void *handle);
|
void Sys_FreeLibrary(void *handle);
|
||||||
void *Sys_LoadLibrary(const char *path, const char *sym, void **handle);
|
void *Sys_LoadLibrary(const char *path, const char *sym, void **handle);
|
||||||
void *Sys_GetProcAddress(void *handle, const char *sym);
|
void *Sys_GetProcAddress(void *handle, const char *sym);
|
||||||
|
@ -778,7 +777,8 @@ void Sys_RedirectStdout(void);
|
||||||
void CL_Init(void);
|
void CL_Init(void);
|
||||||
void CL_Drop(void);
|
void CL_Drop(void);
|
||||||
void CL_Shutdown(void);
|
void CL_Shutdown(void);
|
||||||
void CL_Frame(int msec);
|
void CL_Frame(int packetdelta, int renderdelta, int miscdelta, int timedelta, qboolean packetframe, qboolean renderframe,
|
||||||
|
qboolean miscframe);
|
||||||
void Con_Print(char *text);
|
void Con_Print(char *text);
|
||||||
void SCR_BeginLoadingPlaque(void);
|
void SCR_BeginLoadingPlaque(void);
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,12 @@ cvar_t *developer;
|
||||||
cvar_t *modder;
|
cvar_t *modder;
|
||||||
cvar_t *timescale;
|
cvar_t *timescale;
|
||||||
cvar_t *fixedtime;
|
cvar_t *fixedtime;
|
||||||
cvar_t *portable;
|
|
||||||
|
// For timing calculations.
|
||||||
|
cvar_t *cl_maxfps;
|
||||||
|
cvar_t *gl_maxfps;
|
||||||
|
cvar_t *cl_async;
|
||||||
|
cvar_t *cl_timedemo;
|
||||||
|
|
||||||
#ifndef DEDICATED_ONLY
|
#ifndef DEDICATED_ONLY
|
||||||
cvar_t *showtrace;
|
cvar_t *showtrace;
|
||||||
|
@ -46,6 +51,12 @@ extern cvar_t *logfile_active;
|
||||||
extern jmp_buf abortframe; /* an ERR_DROP occured, exit the entire frame */
|
extern jmp_buf abortframe; /* an ERR_DROP occured, exit the entire frame */
|
||||||
extern zhead_t z_chain;
|
extern zhead_t z_chain;
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
#ifndef DEDICATED_ONLY
|
||||||
|
int GLimp_GetRefreshRate(void);
|
||||||
|
qboolean R_IsVSyncActive(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
static byte chktbl[1024] = {
|
static byte chktbl[1024] = {
|
||||||
0x84, 0x47, 0x51, 0xc1, 0x93, 0x22, 0x21, 0x24, 0x2f, 0x66, 0x60, 0x4d, 0xb0, 0x7c, 0xda,
|
0x84, 0x47, 0x51, 0xc1, 0x93, 0x22, 0x21, 0x24, 0x2f, 0x66, 0x60, 0x4d, 0xb0, 0x7c, 0xda,
|
||||||
0x88, 0x54, 0x15, 0x2b, 0xc6, 0x6c, 0x89, 0xc5, 0x9d, 0x48, 0xee, 0xe6, 0x8a, 0xb5, 0xf4,
|
0x88, 0x54, 0x15, 0x2b, 0xc6, 0x6c, 0x89, 0xc5, 0x9d, 0x48, 0xee, 0xe6, 0x8a, 0xb5, 0xf4,
|
||||||
|
@ -234,6 +245,7 @@ Qcommon_Init(int argc, char **argv)
|
||||||
timescale = Cvar_Get("timescale", "1", 0);
|
timescale = Cvar_Get("timescale", "1", 0);
|
||||||
fixedtime = Cvar_Get("fixedtime", "0", 0);
|
fixedtime = Cvar_Get("fixedtime", "0", 0);
|
||||||
logfile_active = Cvar_Get("logfile", "1", CVAR_ARCHIVE);
|
logfile_active = Cvar_Get("logfile", "1", CVAR_ARCHIVE);
|
||||||
|
cl_timedemo = Cvar_Get("timedemo", "0", 0);
|
||||||
#ifndef DEDICATED_ONLY
|
#ifndef DEDICATED_ONLY
|
||||||
showtrace = Cvar_Get("showtrace", "0", 0);
|
showtrace = Cvar_Get("showtrace", "0", 0);
|
||||||
#endif
|
#endif
|
||||||
|
@ -244,6 +256,11 @@ Qcommon_Init(int argc, char **argv)
|
||||||
dedicated = Cvar_Get("dedicated", "0", CVAR_NOSET);
|
dedicated = Cvar_Get("dedicated", "0", CVAR_NOSET);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// For timing calculations.
|
||||||
|
cl_maxfps = Cvar_Get("cl_maxfps", "60", CVAR_ARCHIVE);
|
||||||
|
gl_maxfps = Cvar_Get("gl_maxfps", "95", CVAR_ARCHIVE);
|
||||||
|
cl_async = Cvar_Get("cl_async", "1", CVAR_ARCHIVE);
|
||||||
|
|
||||||
s = va("%s %s %s %s", YQ2VERSION, YQ2ARCH, BUILD_DATE, YQ2OSTYPE);
|
s = va("%s %s %s %s", YQ2VERSION, YQ2ARCH, BUILD_DATE, YQ2OSTYPE);
|
||||||
Cvar_Get("version", s, CVAR_SERVERINFO | CVAR_NOSET);
|
Cvar_Get("version", s, CVAR_SERVERINFO | CVAR_NOSET);
|
||||||
|
|
||||||
|
@ -299,11 +316,55 @@ Qcommon_Frame(int msec)
|
||||||
int time_after;
|
int time_after;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Target packetframerate.
|
||||||
|
int pfps;
|
||||||
|
|
||||||
|
//Target renderframerate.
|
||||||
|
int rfps;
|
||||||
|
|
||||||
|
// Time since last packetframe in microsec.
|
||||||
|
static int packetdelta = 1000000;
|
||||||
|
|
||||||
|
// Time since last renderframe in microsec.
|
||||||
|
static int renderdelta = 1000000;
|
||||||
|
|
||||||
|
// Time since last misc. frame in microsec.
|
||||||
|
static int miscdelta = 100000;
|
||||||
|
|
||||||
|
// Accumulated time since last client run.
|
||||||
|
static int clienttimedelta = 0;
|
||||||
|
|
||||||
|
// Accumulated time since last server run.
|
||||||
|
static int servertimedelta = 0;
|
||||||
|
|
||||||
|
/* A packetframe runs the server and the client,
|
||||||
|
but not the renderer. The minimal interval of
|
||||||
|
packetframes is about 10.000 microsec. If run
|
||||||
|
more often the movement prediction in pmove.c
|
||||||
|
breaks. That's the Q2 variant if the famous
|
||||||
|
125hz bug. */
|
||||||
|
qboolean packetframe = true;
|
||||||
|
|
||||||
|
/* A rendererframe runs the renderer, but not the
|
||||||
|
client. The minimal interval is about 1000
|
||||||
|
microseconds. */
|
||||||
|
qboolean renderframe = true;
|
||||||
|
|
||||||
|
/* A miscframe runs several maintenance task like
|
||||||
|
loading sound samples for the background music.
|
||||||
|
An interval of 100.000 microseconds is enough. */
|
||||||
|
qboolean miscframe = true;
|
||||||
|
|
||||||
|
|
||||||
|
/* In case of ERR_DROP we're jumping here. Don't know
|
||||||
|
if that' really save but it seems to work. So leave
|
||||||
|
it alone. */
|
||||||
if (setjmp(abortframe))
|
if (setjmp(abortframe))
|
||||||
{
|
{
|
||||||
return; /* an ERR_DROP was thrown */
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (log_stats->modified)
|
if (log_stats->modified)
|
||||||
{
|
{
|
||||||
log_stats->modified = false;
|
log_stats->modified = false;
|
||||||
|
@ -333,20 +394,18 @@ Qcommon_Frame(int msec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Timing debug crap. Just for historical reasons.
|
||||||
if (fixedtime->value)
|
if (fixedtime->value)
|
||||||
{
|
{
|
||||||
msec = fixedtime->value;
|
msec = (int)fixedtime->value;
|
||||||
}
|
}
|
||||||
else if (timescale->value)
|
else if (timescale->value)
|
||||||
{
|
{
|
||||||
msec *= timescale->value;
|
msec *= timescale->value;
|
||||||
|
|
||||||
if (msec < 1)
|
|
||||||
{
|
|
||||||
msec = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef DEDICATED_ONLY
|
#ifndef DEDICATED_ONLY
|
||||||
if (showtrace->value)
|
if (showtrace->value)
|
||||||
{
|
{
|
||||||
|
@ -360,19 +419,80 @@ Qcommon_Frame(int msec)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
s = Sys_ConsoleInput();
|
|
||||||
|
|
||||||
if (s)
|
// Calculate target packet- and renderframerate.
|
||||||
|
#ifndef DEDICATED_ONLY
|
||||||
|
if (R_IsVSyncActive())
|
||||||
|
{
|
||||||
|
rfps = GLimp_GetRefreshRate();
|
||||||
|
|
||||||
|
if (rfps > gl_maxfps->value)
|
||||||
{
|
{
|
||||||
Cbuf_AddText(va("%s\n", s));
|
rfps = (int)gl_maxfps->value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (s);
|
else
|
||||||
|
{
|
||||||
|
rfps = (int)gl_maxfps->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pfps = (cl_maxfps->value > rfps) ? rfps : cl_maxfps->value;
|
||||||
|
#else
|
||||||
|
pfps = (int)cl_maxfps->value;
|
||||||
|
rfps = (int)gl_maxfps->value;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Calculate timings.
|
||||||
|
packetdelta += msec;
|
||||||
|
renderdelta += msec;
|
||||||
|
miscdelta += msec;
|
||||||
|
clienttimedelta += msec;
|
||||||
|
servertimedelta += msec;
|
||||||
|
|
||||||
|
if (!cl_timedemo->value) {
|
||||||
|
if (cl_async->value) {
|
||||||
|
// Network frames..
|
||||||
|
if (packetdelta < (1000000.0f / pfps)) {
|
||||||
|
packetframe = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render frames.
|
||||||
|
if (renderdelta < (1000000.0f / rfps)) {
|
||||||
|
renderframe = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Misc. frames.
|
||||||
|
if (miscdelta < 100000.0f) {
|
||||||
|
miscframe = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Cap frames at target framerate.
|
||||||
|
if (renderdelta < (1000000.0f / rfps)) {
|
||||||
|
renderframe = false;
|
||||||
|
packetframe = false;
|
||||||
|
miscframe = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (clienttimedelta < 1000 || servertimedelta < 1000)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Dedicated server terminal console.
|
||||||
|
do {
|
||||||
|
s = Sys_ConsoleInput();
|
||||||
|
|
||||||
|
if (s) {
|
||||||
|
Cbuf_AddText(va("%s\n", s));
|
||||||
|
}
|
||||||
|
} while (s);
|
||||||
|
|
||||||
Cbuf_Execute();
|
Cbuf_Execute();
|
||||||
|
|
||||||
|
|
||||||
#ifndef DEDICATED_ONLY
|
#ifndef DEDICATED_ONLY
|
||||||
if (host_speeds->value)
|
if (host_speeds->value)
|
||||||
{
|
{
|
||||||
|
@ -380,7 +500,13 @@ Qcommon_Frame(int msec)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SV_Frame(msec);
|
|
||||||
|
// Run the serverframe.
|
||||||
|
if (packetframe) {
|
||||||
|
SV_Frame(servertimedelta);
|
||||||
|
servertimedelta = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef DEDICATED_ONLY
|
#ifndef DEDICATED_ONLY
|
||||||
if (host_speeds->value)
|
if (host_speeds->value)
|
||||||
|
@ -388,7 +514,14 @@ Qcommon_Frame(int msec)
|
||||||
time_between = Sys_Milliseconds();
|
time_between = Sys_Milliseconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
CL_Frame(msec);
|
|
||||||
|
// Run the client frame.
|
||||||
|
if (packetframe || renderframe || miscframe) {
|
||||||
|
CL_Frame(packetdelta, renderdelta, miscdelta, clienttimedelta,
|
||||||
|
packetframe, renderframe, miscframe);
|
||||||
|
clienttimedelta = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (host_speeds->value)
|
if (host_speeds->value)
|
||||||
{
|
{
|
||||||
|
@ -406,6 +539,20 @@ Qcommon_Frame(int msec)
|
||||||
all, sv, gm, cl, rf);
|
all, sv, gm, cl, rf);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Reset deltas if necessary.
|
||||||
|
if (packetframe) {
|
||||||
|
packetdelta = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (renderframe) {
|
||||||
|
renderdelta = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (miscframe) {
|
||||||
|
miscdelta = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -388,7 +388,7 @@ SV_Frame(int msec)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
svs.realtime += msec;
|
svs.realtime += msec / 1000;
|
||||||
|
|
||||||
/* keep the random time dependent */
|
/* keep the random time dependent */
|
||||||
randk();
|
randk();
|
||||||
|
|
Loading…
Reference in a new issue