diff --git a/changelog.txt b/changelog.txt index 55746dc..4450dcc 100644 --- a/changelog.txt +++ b/changelog.txt @@ -16,6 +16,8 @@ add: /toggle can now accept a value sequence (2 or more entries) to loop through if the cvar's current value is in the sequence and not in the last spot, the next one is used otherwise, the first value in the sequence is used +chg: faster map loads by limiting the rendering back-end's frame-rate + chg: on Windows, the upper limit of open stdio file handles was raised from 512 to 2048 fix: the last byte of a maximum length bitstream string wasn't parsed ("q3msgboom") diff --git a/code/client/cl_cgame.cpp b/code/client/cl_cgame.cpp index 901dcce..7bf5501 100644 --- a/code/client/cl_cgame.cpp +++ b/code/client/cl_cgame.cpp @@ -687,7 +687,9 @@ void CL_InitCGame() // init for this gamestate // use the lastExecutedServerCommand instead of the serverCommandSequence // otherwise server commands sent just before a gamestate are dropped + re.SetMaxFPS( 10 ); VM_Call( cgvm, CG_INIT, clc.serverMessageSequence, clc.lastExecutedServerCommand, clc.clientNum ); + re.SetMaxFPS( 0 ); // send a usercmd this frame, which will cause the server to send us the first snapshot cls.state = CA_PRIMED; diff --git a/code/renderer/tr_cmds.cpp b/code/renderer/tr_cmds.cpp index ee3b19d..15eb4f6 100644 --- a/code/renderer/tr_cmds.cpp +++ b/code/renderer/tr_cmds.cpp @@ -247,6 +247,12 @@ void RE_EndFrame( int* pcFE, int* pc2D, int* pc3D, qbool render ) if (!tr.registered) return; + if (tr.maxFPS > 0) { + if (Sys_Milliseconds() < tr.nextFrameTimeMS) + return; + tr.nextFrameTimeMS += 1000 / tr.maxFPS; + } + qbool delayScreenshot = qfalse; if ( !render && r_delayedScreenshotPending ) render = qtrue; diff --git a/code/renderer/tr_init.cpp b/code/renderer/tr_init.cpp index addd280..f10e40f 100644 --- a/code/renderer/tr_init.cpp +++ b/code/renderer/tr_init.cpp @@ -741,6 +741,23 @@ static int RE_GetCameraMatrixTime() } +static void RE_SetMaxFPS( int maxFPS ) +{ + if (maxFPS > 0 && tr.maxFPS == 0) { + tr.maxFPS = maxFPS; + tr.nextFrameTimeMS = Sys_Milliseconds() + 1000 / maxFPS; + tr.oldSwapInterval = r_swapInterval->integer; + ri.Cvar_Set(r_swapInterval->name, "0"); + } else if (maxFPS == 0 && tr.maxFPS > 0) { + tr.maxFPS = 0; + ri.Cvar_Set(r_swapInterval->name, va("%i", tr.oldSwapInterval)); + } else if (maxFPS > 0 && tr.maxFPS > 0) { + tr.maxFPS = maxFPS; + tr.nextFrameTimeMS = Sys_Milliseconds() + 1000 / maxFPS; + } +} + + const refexport_t* GetRefAPI( const refimport_t* rimp ) { static refexport_t re; @@ -790,5 +807,7 @@ const refexport_t* GetRefAPI( const refimport_t* rimp ) re.GetCameraMatrixTime = RE_GetCameraMatrixTime; + re.SetMaxFPS = RE_SetMaxFPS; + return &re; } diff --git a/code/renderer/tr_local.h b/code/renderer/tr_local.h index a037e2f..da2b33e 100644 --- a/code/renderer/tr_local.h +++ b/code/renderer/tr_local.h @@ -912,6 +912,11 @@ typedef struct { float sawToothTable[FUNCTABLE_SIZE]; float inverseSawToothTable[FUNCTABLE_SIZE]; float fogTable[FOG_TABLE_SIZE]; + + // back-end frame-rate limiting, useful for scenarios like CGAME_INIT + int maxFPS; // only active if > 0 + int nextFrameTimeMS; + int oldSwapInterval; } trGlobals_t; extern backEndState_t backEnd; diff --git a/code/renderer/tr_public.h b/code/renderer/tr_public.h index 13e8c96..5ed4476 100644 --- a/code/renderer/tr_public.h +++ b/code/renderer/tr_public.h @@ -163,6 +163,11 @@ typedef struct { // when the final model-view matrix is computed, for cl_drawMouseLag int (*GetCameraMatrixTime)(); + + // used for setting low frame-rates temporarily only (e.g. map loads) + // maxFPS > 0 -> throttles frame-rate, disables v-sync + // maxFPS = 0 -> no throttling , restores v-sync to whatever it was + void (*SetMaxFPS)( int maxFPS ); } refexport_t; //