diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index 2deeab6c5..5b2a6622d 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -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); diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 889daeb15..058318201 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -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 diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 31cd03f36..375572996 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -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; diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index 73e4298a7..d332596b2 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -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 diff --git a/engine/client/renderer.c b/engine/client/renderer.c index 0afbda391..448a82891 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -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); diff --git a/engine/common/cmd.c b/engine/common/cmd.c index db9cc2a41..4cea96d22 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -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); } /* diff --git a/engine/gl/gl_backend.c b/engine/gl/gl_backend.c index 474c6cdec..8d3d94813 100644 --- a/engine/gl/gl_backend.c +++ b/engine/gl/gl_backend.c @@ -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<>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; } diff --git a/engine/gl/gl_model.c b/engine/gl/gl_model.c index 5ca01d404..14a2a49c2 100644 --- a/engine/gl/gl_model.c +++ b/engine/gl/gl_model.c @@ -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 } diff --git a/engine/gl/gl_screen.c b/engine/gl/gl_screen.c index b94a226c6..23e040fae 100644 --- a/engine/gl/gl_screen.c +++ b/engine/gl/gl_screen.c @@ -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; + } + } } diff --git a/engine/gl/gl_shadow.c b/engine/gl/gl_shadow.c index 8ea8dcda1..6f91e0723 100644 --- a/engine/gl/gl_shadow.c +++ b/engine/gl/gl_shadow.c @@ -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]); diff --git a/engine/gl/gl_vidcommon.c b/engine/gl/gl_vidcommon.c index ef73cd0ac..c57efa6f2 100644 --- a/engine/gl/gl_vidcommon.c +++ b/engine/gl/gl_vidcommon.c @@ -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. diff --git a/engine/gl/gl_vidnt.c b/engine/gl/gl_vidnt.c index 06b99e35f..c3751f7fa 100644 --- a/engine/gl/gl_vidnt.c +++ b/engine/gl/gl_vidnt.c @@ -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; diff --git a/engine/gl/glquake.h b/engine/gl/glquake.h index 2377fe04f..cc2c0d4d4 100644 --- a/engine/gl/glquake.h +++ b/engine/gl/glquake.h @@ -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); diff --git a/engine/gl/glsupp.h b/engine/gl/glsupp.h index 571b7b471..7de92b4bd 100644 --- a/engine/gl/glsupp.h +++ b/engine/gl/glsupp.h @@ -14,7 +14,7 @@ extern qlpMTex3FUNC qglMultiTexCoord3fARB; extern qlpMTex2FUNC qglMultiTexCoord2fARB; //This stuff is normally supplied in the 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 //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