1
0
Fork 0
forked from fte/fteqw

tweak demo playback to not have extra penalties, and closer sync.

fix occasional vid_restart crash.
fix dynamic rtlight memory leak.
tweak some gl robustness things, so we can throw away the gl context and restart video cleanly if the drivers decide to randomly crash us. grr. dodgy drivers/hardware are annoying.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4775 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2014-10-22 19:41:20 +00:00
parent ddb3a52987
commit 1b64a9c9c4
14 changed files with 176 additions and 35 deletions

View file

@ -34,9 +34,10 @@ char lastdemoname[256];
extern cvar_t qtvcl_forceversion1;
extern cvar_t qtvcl_eztvextensions;
unsigned char demobuffer[1024*66];
int demobuffersize;
int demopreparsedbytes;
static unsigned char demobuffer[1024*66]; //input buffer
static int demooffset; //start offset of demo buffer
static int demobuffersize; //number of valid bytes within the buffer
static int demopreparsedbytes; //number of bytes within the valid buffer that has already been pre-parsed.
qboolean disablepreparse;
qboolean endofdemo;
@ -268,6 +269,14 @@ int readdemobytes(int *readpos, void *data, int len)
if (len < 0)
Host_EndGame("Corrupt demo");
//if there's not enough space in the buffer, flush it now and allow grabbing a new chunk
//try to ensure it happens periodically enough for the preparsing stuff to happen early.
if (demooffset+*readpos+len > demobuffersize || demooffset > sizeof(demobuffer)/2)
{
memmove(demobuffer, demobuffer+demooffset, demobuffersize);
demooffset = 0;
}
if (demopreparsedbytes < 0) //won't happen in normal running, but can still happen on corrupt data... if we don't disconnect first.
{
Con_Printf("reset preparsed (underflow)\n");
@ -279,16 +288,18 @@ int readdemobytes(int *readpos, void *data, int len)
demopreparsedbytes = 0;
}
trybytes = sizeof(demobuffer)-demobuffersize;
i = VFS_READ(cls.demoinfile, demobuffer+demobuffersize, trybytes);
trybytes = sizeof(demobuffer)-demooffset-demobuffersize;
if (trybytes)
i = VFS_READ(cls.demoinfile, demobuffer+demooffset+demobuffersize, trybytes);
else
i = 0;
if (i > 0)
{
demobuffersize += i;
if (disablepreparse)
demopreparsedbytes = demobuffersize;
else
demopreparsedbytes += demo_preparsedemo(demobuffer+demopreparsedbytes, demobuffersize-demopreparsedbytes);
demopreparsedbytes += demo_preparsedemo(demobuffer+demooffset+demopreparsedbytes, demobuffersize-demopreparsedbytes);
}
if (*readpos+len > demobuffersize)
@ -301,16 +312,16 @@ int readdemobytes(int *readpos, void *data, int len)
// len = demobuffersize;
return 0;
}
memcpy(data, demobuffer+*readpos, len);
memcpy(data, demobuffer+demooffset+*readpos, len);
*readpos += len;
return len;
}
void demo_flushbytes(int bytes)
{
if (bytes > demobuffersize)
if (demooffset+bytes > demobuffersize)
Sys_Error("demo_flushbytes: flushed too much!\n");
memmove(demobuffer, demobuffer+bytes, demobuffersize - bytes);
demooffset += bytes;
demobuffersize -= bytes;
if (demopreparsedbytes < bytes)
@ -321,6 +332,7 @@ void demo_flushbytes(int bytes)
void demo_flushcache(void)
{
demooffset = 0;
demobuffersize = 0;
demopreparsedbytes = 0;
@ -333,6 +345,7 @@ void demo_resetcache(int bytes, void *data)
endofdemo = false;
demo_flushcache();
demooffset = 0;
demobuffersize = bytes;
demopreparsedbytes = 0;
memcpy(demobuffer, data, bytes);

View file

@ -4566,7 +4566,7 @@ double Host_Frame (double time)
CL_UseIndepPhysics(!!cl_threadedphysics.ival);
cl.do_lerp_players = cl_lerp_players.ival || (cls.demoplayback==DPB_MVD || cls.demoplayback == DPB_EZTV) || (cls.demoplayback && !cl_nolerp.ival);
cl.do_lerp_players = cl_lerp_players.ival || (cls.demoplayback==DPB_MVD || cls.demoplayback == DPB_EZTV) || (cls.demoplayback && !cl_nolerp.ival && !cls.timedemo);
CL_AllowIndependantSendCmd(false);
// fetch results from server

View file

@ -548,6 +548,12 @@ void CL_CalcClientTime(void)
{
float oldst = realtime;
if (cls.demoplayback && cls.timedemo)
{ //more deterministic. one frame is drawn per demo packet parsed. so sync to it as closely as possible.
/*NOTE: this also has the effect of speeding up particles etc*/
extern float olddemotime;
cl.servertime = olddemotime;
}
if (cls.protocol == CP_QUAKEWORLD && cls.demoplayback == DPB_MVD && !(cls.fteprotocolextensions2 & PEXT2_REPLACEMENTDELTAS))
{
extern float nextdemotime, olddemotime, demtime;

View file

@ -151,6 +151,7 @@ qboolean Media_BackgroundTrack(const char *track, const char *looptrack)
Q_strncpyz(currenttrack.filename, trackname, sizeof(currenttrack.filename));
fakecdactive = true;
media_playing = true;
cdplayingtrack = tracknum;
return true;
}
#endif

View file

@ -261,6 +261,8 @@ cvar_t vid_gl_context_forwardcompatible = CVARD ("vid_gl_context_forwardcompati
cvar_t vid_gl_context_compatibility = CVARD ("vid_gl_context_compatibility", "1", "Requests an OpenGL context with fixed-function backwards compat.");
cvar_t vid_gl_context_debug = CVARD ("vid_gl_context_debug", "0", "Requests a debug opengl context. This provides better error oreporting."); //for my ati drivers, debug 1 only works if version >= 3
cvar_t vid_gl_context_es = CVARD ("vid_gl_context_es", "0", "Requests an OpenGLES context. Be sure to set vid_gl_context_version to 2 or so."); //requires version set correctly, no debug, no compat
cvar_t vid_gl_context_robustness = CVARD ("vid_gl_context_robustness", "1", "Attempt to enforce extra buffer protection in the gl driver, but can be slower with pre-gl3 hardware.");
cvar_t vid_gl_context_selfreset = CVARD ("vid_gl_context_selfreset", "1", "Upon hardware failure, have the engine create a new context instead of depending on the drivers to restore everything. This can help to avoid graphics drivers randomly killing your game, and can help reduce memory requirements.");
#endif
#if 1
@ -396,6 +398,8 @@ void GLRenderer_Init(void)
Cvar_Register (&vid_gl_context_forwardcompatible, GLRENDEREROPTIONS);
Cvar_Register (&vid_gl_context_compatibility, GLRENDEREROPTIONS);
Cvar_Register (&vid_gl_context_es, GLRENDEREROPTIONS);
Cvar_Register (&vid_gl_context_robustness, GLRENDEREROPTIONS);
Cvar_Register (&vid_gl_context_selfreset, GLRENDEREROPTIONS);
//screen
Cvar_Register (&vid_preservegamma, GLRENDEREROPTIONS);

View file

@ -424,7 +424,8 @@ void Cbuf_Execute (void)
int level;
for (level = 0; level < sizeof(cmd_text)/sizeof(cmd_text[0]); level++)
Cbuf_ExecuteLevel(level);
if (cmd_text[level].buf.cursize)
Cbuf_ExecuteLevel(level);
}
/*

View file

@ -401,6 +401,17 @@ void GL_MTBind(int tmu, int target, texid_t texnum)
}
}
#if 0//def GLSLONLY
void GL_LazyBind(int tmu, int target, texid_t texnum)
{
int glnum = texnum?texnum->num:0;
if (shaderstate.currenttextures[tmu] != glnum)
{
qglBindTextureUnit(tmu, glnum);
shaderstate.currenttextures[tmu] = glnum;
}
}
#else
void GL_LazyBind(int tmu, int target, texid_t texnum)
{
int glnum = texnum?texnum->num:0;
@ -436,6 +447,7 @@ void GL_LazyBind(int tmu, int target, texid_t texnum)
qglBindTexture (target, glnum);
}
}
#endif
static void BE_ApplyAttributes(unsigned int bitstochange, unsigned int bitstoendisable)
{
@ -785,7 +797,6 @@ void GLBE_RenderShadowBuffer(unsigned int numverts, int vbo, vecV_t *verts, unsi
shaderstate.sourcevbo = &shaderstate.dummyvbo;
shaderstate.dummyvbo.indicies.gl.vbo = ibo;
GL_SelectEBO(ibo);
if (shaderstate.allblackshader)
{
@ -801,7 +812,7 @@ void GLBE_RenderShadowBuffer(unsigned int numverts, int vbo, vecV_t *verts, unsi
}
shaderstate.lastuniform = shaderstate.allblackshader;
GL_SelectEBO(ibo);
qglDrawRangeElements(GL_TRIANGLES, 0, numverts, numindicies, GL_INDEX_TYPE, indicies);
}
else
@ -810,6 +821,7 @@ void GLBE_RenderShadowBuffer(unsigned int numverts, int vbo, vecV_t *verts, unsi
BE_EnableShaderAttributes((1u<<VATTR_LEG_VERTEX), 0);
//draw cached world shadow mesh
GL_SelectEBO(ibo);
qglDrawRangeElements(GL_TRIANGLES, 0, numverts, numindicies, GL_INDEX_TYPE, indicies);
}
RQuantAdd(RQUANT_SHADOWFACES, numindicies/3);
@ -858,7 +870,7 @@ void R_FetchTopColour(int *retred, int *retgreen, int *retblue)
i = cv;
else
i = TOP_RANGE>>4;
if (i > 8)
if (i >= 8)
{
i<<=4;
}
@ -894,7 +906,7 @@ void R_FetchBottomColour(int *retred, int *retgreen, int *retblue)
i = cv;
else
i = BOTTOM_RANGE>>4;
if (i > 8)
if (i >= 8)
{
i<<=4;
}

View file

@ -611,6 +611,7 @@ void Mod_Shutdown (qboolean final)
#ifndef SERVERONLY
r_worldentity.model = NULL; //just in case.
cl_numvisedicts = 0; //make sure nothing gets cached.
#endif
}

View file

@ -208,6 +208,25 @@ void GLSCR_UpdateScreen (void)
GL_EndRendering ();
VID_SwapBuffers();
RSpeedEnd(RSPEED_FINISH);
//gl 4.5 / GL_ARB_robustness / GL_KHR_robustness
if (qglGetGraphicsResetStatus)
{
GLenum err = qglGetGraphicsResetStatus();
switch(err)
{
case GL_NO_ERROR:
break;
case GL_GUILTY_CONTEXT_RESET: //we did it
case GL_INNOCENT_CONTEXT_RESET: //something else broke the hardware and broke our ram
case GL_UNKNOWN_CONTEXT_RESET: //whodunit
default:
Con_Printf("OpenGL reset detected\n");
Sys_Sleep(3.0);
Cmd_ExecuteString("vid_restart", RESTRICT_LOCAL);
break;
}
}
}

View file

@ -525,7 +525,8 @@ static struct shadowmesh_s *SHM_FinishShadowMesh(dlight_t *dl)
case QR_OPENGL:
if (!qglGenBuffersARB)
return sh_shmesh;
qglGenBuffersARB(2, sh_shmesh->vebo);
if (!sh_shmesh->vebo[0])
qglGenBuffersARB(2, sh_shmesh->vebo);
GL_DeselectVAO();
GL_SelectVBO(sh_shmesh->vebo[0]);

View file

@ -161,6 +161,8 @@ void (APIENTRY *qglEnableClientState) (GLenum array);
void (APIENTRY *qglPushAttrib) (GLbitfield mask);
void (APIENTRY *qglPopAttrib) (void);
GLenum (APIENTRY *qglGetGraphicsResetStatus) (void);
void (APIENTRY *qglFogf) (GLenum pname, GLfloat param);
void (APIENTRY *qglFogi) (GLenum pname, GLint param);
void (APIENTRY *qglFogfv) (GLenum pname, const GLfloat *params);
@ -526,6 +528,10 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
}
else
gl_config.nofixedfunc = false;
#ifdef GLSLONLY
gl_config.nofixedfunc = true;
#endif
}
gl_config.maxglslversion = 0;
@ -935,6 +941,14 @@ void GL_CheckExtensions (void *(*getglfunction) (char *name))
}
}
if (gl_config.glversion >= 4.5) //the core version
qglGetGraphicsResetStatus = (void *)getglext("glGetGraphicsResetStatus");
else if (GL_CheckExtension("GL_ARB_robustness")) //desktop extension
qglGetGraphicsResetStatus = (void *)getglext("glGetGraphicsResetStatusARB");
else if (GL_CheckExtension("GL_KHR_robustness")) //glorified gles extension
qglGetGraphicsResetStatus = (void *)getglext("glGetGraphicsResetStatusKHR");
else
qglGetGraphicsResetStatus = NULL; //its not allowed to crash us. probably will. grr. oh well.
//we only use vao if we don't have a choice.
//certain drivers (*cough* mesa *cough*) update vao0 state even when a different vao is bound.

View file

@ -94,6 +94,8 @@ extern cvar_t vid_width;
extern cvar_t vid_height;
extern cvar_t vid_wndalpha;
const char *wgl_extensions;
typedef enum {MS_WINDOWED, MS_FULLSCREEN, MS_FULLDIB, MS_UNINIT} modestate_t;
BOOL bSetupPixelFormat(HDC hDC, rendererstate_t *info);
@ -174,6 +176,8 @@ extern cvar_t vid_gl_context_debug;
extern cvar_t vid_gl_context_es;
extern cvar_t vid_gl_context_forwardcompatible;
extern cvar_t vid_gl_context_compatibility;
extern cvar_t vid_gl_context_robustness;
extern cvar_t vid_gl_context_selfreset;
int window_center_x, window_center_y, window_x, window_y, window_width, window_height;
RECT window_rect;
@ -415,14 +419,16 @@ HGLRC (APIENTRY *qwglCreateContextAttribsARB)(HDC hDC, HGLRC hShareContext, cons
#define WGL_CONTEXT_FLAGS_ARB 0x2094
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001
#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x0004 /*WGL_ARB_create_context_robustness*/
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 /*WGL_ARB_create_context_profile*/
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 /*WGL_CONTEXT_ES2_PROFILE_BIT_EXT*/
#define ERROR_INVALID_VERSION_ARB 0x2095
#define ERROR_INVALID_PROFILE_ARB 0x2096
#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 /*WGL_ARB_create_context_robustness*/
#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261
#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252
qboolean GLInitialise (char *renderer)
{
@ -1196,6 +1202,44 @@ void VID_UpdateWindowStatus (HWND hWnd)
INS_UpdateClipCursor ();
}
qboolean WGL_CheckExtension(char *extname)
{
// int i;
int len;
const char *foo;
cvar_t *v = Cvar_Get(va("gl_ext_%s", extname), "1", 0, "GL Extensions");
if (v && !v->ival)
{
Con_Printf("Cvar %s is 0\n", v->name);
return false;
}
/* if (gl_num_extensions && qglGetStringi)
{
for (i = 0; i < gl_num_extensions; i++)
if (!strcmp(qglGetStringi(GL_EXTENSIONS, i), extname))
{
Con_DPrintf("Detected GL extension %s\n", extname);
return true;
}
}
*/
if (!wgl_extensions)
return false;
//the list is space delimited. we cannot just strstr lest we find leading/trailing _FOO_.
len = strlen(extname);
for (foo = wgl_extensions; *foo; )
{
if (!strncmp(foo, extname, len) && (foo[len] == ' ' || !foo[len]))
return true;
while(*foo && *foo != ' ')
foo++;
if (*foo == ' ')
foo++;
}
return false;
}
//====================================
@ -1252,7 +1296,6 @@ qboolean VID_AttachGL (rendererstate_t *info)
return false;
}
if (developer.ival)
{
char *(WINAPI *wglGetExtensionsString)(HDC hdc) = NULL;
if (!wglGetExtensionsString)
@ -1262,9 +1305,14 @@ qboolean VID_AttachGL (rendererstate_t *info)
if (!wglGetExtensionsString)
wglGetExtensionsString = getglfunc("wglGetExtensionsStringEXT");
if (wglGetExtensionsString)
Con_SafePrintf("WGL extensions: %s\n", wglGetExtensionsString(maindc));
wgl_extensions = wglGetExtensionsString(maindc);
else
wgl_extensions = NULL;
}
if (developer.ival)
Con_SafePrintf("WGL extensions: %s\n", wgl_extensions?"NONE":wgl_extensions);
qwglCreateContextAttribsARB = getglfunc("wglCreateContextAttribsARB");
#if 1//def _DEBUG
//attempt to promote that to opengl3.
@ -1277,7 +1325,7 @@ qboolean VID_AttachGL (rendererstate_t *info)
char *ver;
ver = vid_gl_context_version.string;
if (!*ver && vid_gl_context_es.ival)
if (!*ver && vid_gl_context_es.ival && WGL_CheckExtension("WGL_EXT_create_context_es2_profile"))
ver = "2.0";
mv = ver;
@ -1304,6 +1352,8 @@ qboolean VID_AttachGL (rendererstate_t *info)
attribs[i+1] |= WGL_CONTEXT_DEBUG_BIT_ARB;
if (vid_gl_context_forwardcompatible.ival)
attribs[i+1] |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
if (vid_gl_context_robustness.ival && WGL_CheckExtension("WGL_ARB_create_context_robustness"))
attribs[i+1] |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
if (attribs[i+1])
{
@ -1311,20 +1361,29 @@ qboolean VID_AttachGL (rendererstate_t *info)
i += 2;
}
if (vid_gl_context_selfreset.ival && WGL_CheckExtension("WGL_ARB_create_context_robustness"))
{
attribs[i++] = WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB;
attribs[i++] = WGL_LOSE_CONTEXT_ON_RESET_ARB;
}
/*only switch contexts if there's actually a point*/
if (i || !vid_gl_context_compatibility.ival || vid_gl_context_es.ival)
{
attribs[i+1] = 0;
if (vid_gl_context_es.ival)
attribs[i+1] |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT;
else if (vid_gl_context_compatibility.ival)
attribs[i+1] |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
else
attribs[i+1] |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
attribs[i] = WGL_CONTEXT_PROFILE_MASK_ARB;
//WGL_CONTEXT_PROFILE_MASK_ARB is ignored if < 3.2 - however, nvidia do not agree and return errors
if (atof(ver) >= 3.2 || vid_gl_context_es.ival)
i+=2;
if (WGL_CheckExtension("WGL_ARB_create_context_profile"))
{
attribs[i+1] = 0;
if (vid_gl_context_es.ival && (WGL_CheckExtension("WGL_EXT_create_context_es_profile") || WGL_CheckExtension("WGL_EXT_create_context_es2_profile")))
attribs[i+1] |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT;
else if (vid_gl_context_compatibility.ival)
attribs[i+1] |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
else
attribs[i+1] |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
attribs[i] = WGL_CONTEXT_PROFILE_MASK_ARB;
//WGL_CONTEXT_PROFILE_MASK_ARB is ignored if < 3.2 - however, nvidia do not agree and return errors
if (atof(ver) >= 3.2 || vid_gl_context_es.ival)
i+=2;
}
attribs[i] = 0;

View file

@ -718,6 +718,8 @@ extern GLboolean (APIENTRY *qglUnmapBufferARB)(GLenum target);
#endif
extern void (APIENTRY *qglDrawBuffers)(GLsizei n, GLsizei *ids); //gl2
extern GLenum (APIENTRY *qglGetGraphicsResetStatus) (void);
//non-gles2 gl functions
extern void (APIENTRY *qglAccum) (GLenum op, GLfloat value);
extern void (APIENTRY *qglAlphaFunc) (GLenum func, GLclampf ref);

View file

@ -14,7 +14,7 @@ extern qlpMTex3FUNC qglMultiTexCoord3fARB;
extern qlpMTex2FUNC qglMultiTexCoord2fARB;
//This stuff is normally supplied in the <GL/glext.h> header file. I don't actually have one of them, so it's here instead.
#if 0 //change to 1 if you do actually have the file in question.
#if 0 //change to 1 if you do actually have the file in question - and its up to date.
#include <GL/glext.h> //would be ideal.
#else
@ -720,6 +720,14 @@ typedef void (APIENTRY * PFNGLUNLOCKARRAYSEXTPROC) (void);
#define GL_NUM_EXTENSIONS 0x821D
#endif
//GL_ARB_robustness, core in 4.5
#ifndef GL_GUILTY_CONTEXT_RESET
//#define GL_NO_ERROR 0x0000
#define GL_GUILTY_CONTEXT_RESET 0x8253
#define GL_INNOCENT_CONTEXT_RESET 0x8254
#define GL_UNKNOWN_CONTEXT_RESET 0x8255
#endif
#ifndef GL_DEPTH_CLAMP_ARB
#define GL_DEPTH_CLAMP_ARB 0x864F
#endif