mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2025-01-22 01:01:18 +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
|
@ -38,13 +38,10 @@ qboolean is_portable;
|
|||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int time, oldtime, newtime;
|
||||
int verLen, i;
|
||||
long long oldtime, newtime;
|
||||
const char* versionString;
|
||||
|
||||
#ifndef BUSY_WAIT
|
||||
struct timespec t;
|
||||
#endif
|
||||
struct timespec t = {0, 5000};
|
||||
|
||||
/* register signal handler */
|
||||
registerHandler();
|
||||
|
@ -134,27 +131,16 @@ main(int argc, char **argv)
|
|||
/* Do not delay reads on stdin*/
|
||||
fcntl(fileno(stdin), F_SETFL, fcntl(fileno(stdin), F_GETFL, NULL) | FNDELAY);
|
||||
|
||||
oldtime = Sys_Milliseconds();
|
||||
t.tv_sec = 0;
|
||||
oldtime = Sys_Microseconds();
|
||||
|
||||
/* The legendary Quake II mainloop */
|
||||
/* The mainloop. The legend. */
|
||||
while (1)
|
||||
{
|
||||
/* find time spent rendering last frame */
|
||||
do
|
||||
{
|
||||
#ifndef BUSY_WAIT
|
||||
/* Sleep 10 microseconds */
|
||||
t.tv_nsec = 10000;
|
||||
nanosleep(&t, NULL);
|
||||
#endif
|
||||
// Throttle the game a little bit.
|
||||
nanosleep(&t, NULL);
|
||||
|
||||
newtime = Sys_Milliseconds();
|
||||
time = newtime - oldtime;
|
||||
}
|
||||
while (time < 1);
|
||||
|
||||
Qcommon_Frame(time);
|
||||
newtime = Sys_Microseconds();
|
||||
Qcommon_Frame(newtime - oldtime);
|
||||
oldtime = newtime;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
#include <dirent.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "../../common/header/common.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
|
||||
Sys_Milliseconds(void)
|
||||
{
|
||||
struct timeval tp;
|
||||
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;
|
||||
curtime = (int)(Sys_Microseconds()/1000ll);
|
||||
|
||||
return curtime;
|
||||
}
|
||||
|
||||
void
|
||||
Sys_Sleep(int msec)
|
||||
{
|
||||
usleep((unsigned int)1000 * msec);
|
||||
}
|
||||
|
||||
void
|
||||
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
|
||||
Sys_Milliseconds(void)
|
||||
{
|
||||
static int base;
|
||||
static qboolean initialized = false;
|
||||
|
||||
if (!initialized)
|
||||
{ /* let base retain 16 bits of effectively random data */
|
||||
base = timeGetTime() & 0xffff0000;
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
curtime = timeGetTime() - base;
|
||||
curtime = (int)(Sys_Microseconds()/1000ll);
|
||||
|
||||
return curtime;
|
||||
}
|
||||
|
@ -437,6 +457,22 @@ Sys_Sleep(int 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
|
||||
|
@ -745,7 +781,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|||
LPSTR lpCmdLine, int nCmdShow)
|
||||
{
|
||||
MSG msg;
|
||||
int time, oldtime, newtime;
|
||||
long long oldtime, newtime;
|
||||
|
||||
/* Previous instances do not exist in Win32 */
|
||||
if (hPrevInstance)
|
||||
|
@ -817,7 +853,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|||
Qcommon_Init(argc, argv);
|
||||
|
||||
/* Save our time */
|
||||
oldtime = Sys_Milliseconds();
|
||||
oldtime = Sys_Microseconds();
|
||||
|
||||
/* The legendary main loop */
|
||||
while (1)
|
||||
|
@ -840,14 +876,11 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
newtime = Sys_Milliseconds();
|
||||
time = newtime - oldtime;
|
||||
}
|
||||
while (time < 1);
|
||||
// Throttle the game a little bit
|
||||
Sys_Nanosleep(5000);
|
||||
|
||||
Qcommon_Frame(time);
|
||||
newtime = Sys_Microseconds();
|
||||
Qcommon_Frame(newtime - oldtime);
|
||||
oldtime = newtime;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,12 +35,6 @@ extern char key_lines[NUM_KEY_LINES][MAXCMDLINE];
|
|||
extern int edit_line;
|
||||
extern int key_linepos;
|
||||
|
||||
void
|
||||
DrawString(int x, int y, char *s)
|
||||
{
|
||||
DrawStringScaled(x, y, s, 1.0f);
|
||||
}
|
||||
|
||||
void
|
||||
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
|
||||
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
|
||||
* typing goes beyond the right edge
|
||||
|
|
|
@ -44,21 +44,18 @@ cvar_t *cl_noskins;
|
|||
cvar_t *cl_footsteps;
|
||||
cvar_t *cl_timeout;
|
||||
cvar_t *cl_predict;
|
||||
cvar_t *cl_maxfps;
|
||||
cvar_t *cl_drawfps;
|
||||
cvar_t *cl_gun;
|
||||
cvar_t *cl_add_particles;
|
||||
cvar_t *cl_add_lights;
|
||||
cvar_t *cl_add_entities;
|
||||
cvar_t *cl_add_blend;
|
||||
cvar_t *cl_async;
|
||||
|
||||
cvar_t *cl_shownet;
|
||||
cvar_t *cl_showmiss;
|
||||
cvar_t *cl_showclamp;
|
||||
|
||||
cvar_t *cl_paused;
|
||||
cvar_t *cl_timedemo;
|
||||
|
||||
cvar_t *lookspring;
|
||||
cvar_t *lookstrafe;
|
||||
|
@ -83,8 +80,6 @@ cvar_t *hand;
|
|||
cvar_t *gender;
|
||||
cvar_t *gender_auto;
|
||||
|
||||
cvar_t *gl_maxfps;
|
||||
|
||||
cvar_t *gl_stereo;
|
||||
cvar_t *gl_stereo_separation;
|
||||
cvar_t *gl_stereo_convergence;
|
||||
|
@ -484,9 +479,7 @@ CL_InitLocal(void)
|
|||
cl_footsteps = Cvar_Get("cl_footsteps", "1", 0);
|
||||
cl_noskins = Cvar_Get("cl_noskins", "0", 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_async = Cvar_Get("cl_async", "1", CVAR_ARCHIVE);
|
||||
|
||||
cl_upspeed = Cvar_Get("cl_upspeed", "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_timeout = Cvar_Get("cl_timeout", "120", 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_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
|
||||
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 packetdelta = 1000;
|
||||
static int renderdelta = 1000;
|
||||
static int miscdelta = 1000;
|
||||
|
||||
qboolean packetframe = true;
|
||||
qboolean renderframe = true;
|
||||
qboolean miscframe = true;
|
||||
|
||||
// Dedicated?
|
||||
if (dedicated->value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Target render frame rate
|
||||
if (R_IsVSyncActive())
|
||||
{
|
||||
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;
|
||||
// Calculate simulation time.
|
||||
cls.nframetime = packetdelta / 1000000.0f;
|
||||
cls.rframetime = renderdelta / 1000000.0f;
|
||||
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)
|
||||
{
|
||||
cls.nframetime = 0.5f;
|
||||
|
@ -775,72 +730,19 @@ CL_Frame(int msec)
|
|||
cls.rframetime = 0.5f;
|
||||
}
|
||||
|
||||
/* if in the debugger last frame, don't timeout */
|
||||
if (msec > 5000)
|
||||
// if in the debugger last frame, don't timeout.
|
||||
if (timedelta > 5000000)
|
||||
{
|
||||
cls.netchan.last_received = Sys_Milliseconds();
|
||||
}
|
||||
|
||||
if (!cl_timedemo->value)
|
||||
{
|
||||
// Don't flood while connecting
|
||||
if ((cls.state == ca_connected) && (packetdelta < 100))
|
||||
// Don't throttle too much when connecting / loading.
|
||||
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
|
||||
|
@ -870,20 +772,14 @@ CL_Frame(int msec)
|
|||
|
||||
if (packetframe)
|
||||
{
|
||||
packetdelta = 0;
|
||||
|
||||
CL_SendCmd();
|
||||
CL_CheckForResend();
|
||||
}
|
||||
|
||||
if (renderframe)
|
||||
{
|
||||
renderdelta = 0;
|
||||
|
||||
if (miscframe)
|
||||
{
|
||||
miscdelta = 0;
|
||||
|
||||
VID_CheckChanges();
|
||||
}
|
||||
|
||||
|
|
|
@ -1410,6 +1410,84 @@ SCR_DrawLayout(void)
|
|||
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
|
||||
* explicitly to flush text to the screen.
|
||||
|
@ -1535,13 +1613,6 @@ SCR_UpdateScreen(void)
|
|||
SCR_DrawNet();
|
||||
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)
|
||||
{
|
||||
SCR_DebugGraph(cls.rframetime * 300, 0);
|
||||
|
@ -1563,6 +1634,7 @@ SCR_UpdateScreen(void)
|
|||
}
|
||||
}
|
||||
|
||||
SCR_Framecounter();
|
||||
R_EndFrame();
|
||||
}
|
||||
|
||||
|
|
|
@ -766,8 +766,7 @@ void Sys_Error(char *error, ...);
|
|||
void Sys_Quit(void);
|
||||
char *Sys_GetHomeDir(void);
|
||||
const char *Sys_GetBinaryDir(void);
|
||||
void Sys_Sleep(int msec);
|
||||
|
||||
long long Sys_Microseconds(void);
|
||||
void Sys_FreeLibrary(void *handle);
|
||||
void *Sys_LoadLibrary(const char *path, const char *sym, void **handle);
|
||||
void *Sys_GetProcAddress(void *handle, const char *sym);
|
||||
|
@ -778,7 +777,8 @@ void Sys_RedirectStdout(void);
|
|||
void CL_Init(void);
|
||||
void CL_Drop(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 SCR_BeginLoadingPlaque(void);
|
||||
|
||||
|
|
|
@ -35,7 +35,12 @@ cvar_t *developer;
|
|||
cvar_t *modder;
|
||||
cvar_t *timescale;
|
||||
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
|
||||
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 zhead_t z_chain;
|
||||
|
||||
// Forward declarations
|
||||
#ifndef DEDICATED_ONLY
|
||||
int GLimp_GetRefreshRate(void);
|
||||
qboolean R_IsVSyncActive(void);
|
||||
#endif
|
||||
|
||||
static byte chktbl[1024] = {
|
||||
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,
|
||||
|
@ -234,6 +245,7 @@ Qcommon_Init(int argc, char **argv)
|
|||
timescale = Cvar_Get("timescale", "1", 0);
|
||||
fixedtime = Cvar_Get("fixedtime", "0", 0);
|
||||
logfile_active = Cvar_Get("logfile", "1", CVAR_ARCHIVE);
|
||||
cl_timedemo = Cvar_Get("timedemo", "0", 0);
|
||||
#ifndef DEDICATED_ONLY
|
||||
showtrace = Cvar_Get("showtrace", "0", 0);
|
||||
#endif
|
||||
|
@ -244,6 +256,11 @@ Qcommon_Init(int argc, char **argv)
|
|||
dedicated = Cvar_Get("dedicated", "0", CVAR_NOSET);
|
||||
#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);
|
||||
Cvar_Get("version", s, CVAR_SERVERINFO | CVAR_NOSET);
|
||||
|
||||
|
@ -299,11 +316,55 @@ Qcommon_Frame(int msec)
|
|||
int time_after;
|
||||
#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))
|
||||
{
|
||||
return; /* an ERR_DROP was thrown */
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (log_stats->modified)
|
||||
{
|
||||
log_stats->modified = false;
|
||||
|
@ -333,20 +394,18 @@ Qcommon_Frame(int msec)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Timing debug crap. Just for historical reasons.
|
||||
if (fixedtime->value)
|
||||
{
|
||||
msec = fixedtime->value;
|
||||
msec = (int)fixedtime->value;
|
||||
}
|
||||
else if (timescale->value)
|
||||
{
|
||||
msec *= timescale->value;
|
||||
|
||||
if (msec < 1)
|
||||
{
|
||||
msec = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifndef DEDICATED_ONLY
|
||||
if (showtrace->value)
|
||||
{
|
||||
|
@ -360,19 +419,80 @@ Qcommon_Frame(int msec)
|
|||
}
|
||||
#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();
|
||||
|
||||
|
||||
#ifndef DEDICATED_ONLY
|
||||
if (host_speeds->value)
|
||||
{
|
||||
|
@ -380,7 +500,13 @@ Qcommon_Frame(int msec)
|
|||
}
|
||||
#endif
|
||||
|
||||
SV_Frame(msec);
|
||||
|
||||
// Run the serverframe.
|
||||
if (packetframe) {
|
||||
SV_Frame(servertimedelta);
|
||||
servertimedelta = 0;
|
||||
}
|
||||
|
||||
|
||||
#ifndef DEDICATED_ONLY
|
||||
if (host_speeds->value)
|
||||
|
@ -388,7 +514,14 @@ Qcommon_Frame(int msec)
|
|||
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)
|
||||
{
|
||||
|
@ -406,6 +539,20 @@ Qcommon_Frame(int msec)
|
|||
all, sv, gm, cl, rf);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Reset deltas if necessary.
|
||||
if (packetframe) {
|
||||
packetdelta = 0;
|
||||
}
|
||||
|
||||
if (renderframe) {
|
||||
renderdelta = 0;
|
||||
}
|
||||
|
||||
if (miscframe) {
|
||||
miscdelta = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -388,7 +388,7 @@ SV_Frame(int msec)
|
|||
return;
|
||||
}
|
||||
|
||||
svs.realtime += msec;
|
||||
svs.realtime += msec / 1000;
|
||||
|
||||
/* keep the random time dependent */
|
||||
randk();
|
||||
|
|
Loading…
Reference in a new issue