From 33fb1d11372ce3b1beab0407015535247d6bff14 Mon Sep 17 00:00:00 2001 From: havoc Date: Sat, 30 Jun 2018 21:59:21 +0000 Subject: [PATCH] Change MAX_TEXTUREUNITS from 16 to 32 - this fixes a memory corruption that was causing all kinds of problems (e.g. cachepic issues). Get rid of vid.texarrayunits, vid.teximageunits, vid.texunits variables as they are meaningless, assume 32 (because that is how many GL enums exist). Don't clear texture units on reset, we don't know how many texture units really exist and it's largely pointless. Do a more thorough unbind of textures on deletion, just for good measure. git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@12437 d7cf8633-e32d-0410-b094-e92efae38249 --- draw.h | 1 - gl_backend.c | 41 +++++++++++++---------------------------- gl_draw.c | 27 ++++++++++++++++++++------- gl_rmain.c | 2 +- vid.h | 5 +---- vid_sdl.c | 7 ------- vid_shared.c | 6 ------ 7 files changed, 35 insertions(+), 54 deletions(-) diff --git a/draw.h b/draw.h index 3857e98e..5e023da8 100644 --- a/draw.h +++ b/draw.h @@ -39,7 +39,6 @@ typedef enum cachepicflags_e } cachepicflags_t; -void Draw_Init (void); void Draw_Frame (void); cachepic_t *Draw_CachePic_Flags (const char *path, unsigned int cachepicflags); cachepic_t *Draw_CachePic (const char *path); // standard function with no options, used throughout engine diff --git a/gl_backend.c b/gl_backend.c index fcaeeb2d..60487161 100644 --- a/gl_backend.c +++ b/gl_backend.c @@ -1108,7 +1108,7 @@ void R_Mesh_SetRenderTargets(int fbo, rtexture_t *depthtexture, rtexture_t *colo // unbind any matching textures immediately, otherwise D3D will complain about a bound texture being used as a render target for (j = 0;j < 5;j++) if (textures[j]) - for (i = 0;i < vid.teximageunits;i++) + for (i = 0;i < MAX_TEXTUREUNITS;i++) if (gl_state.units[i].texture == textures[j]) R_Mesh_TexBind(i, NULL); // set up framebuffer object or render targets for the active rendering API @@ -1127,7 +1127,6 @@ void R_Mesh_SetRenderTargets(int fbo, rtexture_t *depthtexture, rtexture_t *colo static void GL_Backend_ResetState(void) { - unsigned int i; gl_state.active = true; gl_state.depthtest = true; gl_state.alphatest = false; @@ -1171,18 +1170,6 @@ static void GL_Backend_ResetState(void) qglVertexAttrib4f(GLSLATTRIB_COLOR, 1, 1, 1, 1); gl_state.unit = MAX_TEXTUREUNITS; gl_state.clientunit = MAX_TEXTUREUNITS; - for (i = 0;i < vid.teximageunits;i++) - { - GL_ActiveTexture(i); - qglBindTexture(GL_TEXTURE_2D, 0);CHECKGLERROR - qglBindTexture(GL_TEXTURE_3D, 0);CHECKGLERROR - qglBindTexture(GL_TEXTURE_CUBE_MAP, 0);CHECKGLERROR - } - for (i = 0;i < vid.texarrayunits;i++) - { - GL_BindVBO(0); - qglDisableVertexAttribArray(i+GLSLATTRIB_TEXCOORD0);CHECKGLERROR - } CHECKGLERROR break; } @@ -2021,6 +2008,8 @@ void R_Mesh_ColorPointer(int components, int gltype, size_t stride, const void * void R_Mesh_TexCoordPointer(unsigned int unitnum, int components, int gltype, size_t stride, const void *pointer, const r_meshbuffer_t *vertexbuffer, size_t bufferoffset) { gltextureunit_t *unit = gl_state.units + unitnum; + if (unitnum >= MAX_TEXTUREUNITS) + Sys_Error("R_Mesh_TexCoordPointer: unitnum %i > max units %i\n", unitnum, MAX_TEXTUREUNITS); // update array settings // note: there is no need to check bufferobject here because all cases // that involve a valid bufferobject also supply a texcoord array @@ -2068,8 +2057,8 @@ void R_Mesh_TexCoordPointer(unsigned int unitnum, int components, int gltype, si int R_Mesh_TexBound(unsigned int unitnum, int id) { gltextureunit_t *unit = gl_state.units + unitnum; - if (unitnum >= vid.teximageunits) - return 0; + if (unitnum >= MAX_TEXTUREUNITS) + Sys_Error("R_Mesh_TexCoordPointer: unitnum %i > max units %i\n", unitnum, MAX_TEXTUREUNITS); if (id == GL_TEXTURE_2D) return unit->t2d; if (id == GL_TEXTURE_3D) @@ -2096,16 +2085,12 @@ void R_Mesh_ClearBindingsForTexture(int texnum) { gltextureunit_t *unit; unsigned int unitnum; - // this doesn't really unbind the texture, but it does prevent a mistaken "do nothing" behavior on the next time this same texnum is bound on the same unit as the same type (this mainly affects r_shadow_bouncegrid because 3D textures are so rarely used) - for (unitnum = 0;unitnum < vid.teximageunits;unitnum++) + // unbind the texture from any units it is bound on - this prevents accidental reuse of certain textures whose bindings can linger far too long otherwise (e.g. bouncegrid which is a 3D texture) and confuse the driver later. + for (unitnum = 0; unitnum < MAX_TEXTUREUNITS; unitnum++) { unit = gl_state.units + unitnum; - if (unit->t2d == texnum) - unit->t2d = -1; - if (unit->t3d == texnum) - unit->t3d = -1; - if (unit->tcubemap == texnum) - unit->tcubemap = -1; + if (unit->texture && unit->texture->texnum == texnum) + R_Mesh_TexBind(unitnum, NULL); } } @@ -2113,8 +2098,8 @@ void R_Mesh_TexBind(unsigned int unitnum, rtexture_t *tex) { gltextureunit_t *unit = gl_state.units + unitnum; int texnum; - if (unitnum >= vid.teximageunits) - return; + if (unitnum >= MAX_TEXTUREUNITS) + Sys_Error("R_Mesh_TexBind: unitnum %i > max units %i\n", unitnum, MAX_TEXTUREUNITS); if (unit->texture == tex) return; switch(vid.renderpath) @@ -2146,9 +2131,9 @@ void R_Mesh_ResetTextureState(void) BACKENDACTIVECHECK - for (unitnum = 0;unitnum < vid.teximageunits;unitnum++) + for (unitnum = 0;unitnum < MAX_TEXTUREUNITS;unitnum++) R_Mesh_TexBind(unitnum, NULL); - for (unitnum = 0;unitnum < vid.texarrayunits;unitnum++) + for (unitnum = 0;unitnum < MAX_TEXTUREUNITS;unitnum++) R_Mesh_TexCoordPointer(unitnum, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0); } diff --git a/gl_draw.c b/gl_draw.c index fa7a8e06..c61fa366 100644 --- a/gl_draw.c +++ b/gl_draw.c @@ -111,12 +111,12 @@ cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags) // ignore TEXF_COMPRESS when comparing, because fallback pics remove the flag, and ignore TEXF_MIPMAP because QC specifies that if ((pic->texflags ^ texflags) & ~(TEXF_COMPRESS | TEXF_MIPMAP)) { - Con_DPrintf("Draw_CachePic(\"%s\"): reloading pic due to mismatch on flags\n", path); + Con_DPrintf("Draw_CachePic(\"%s\"): frame %i: reloading pic due to mismatch on flags\n", path, draw_frame); goto reload; } if (!pic->skinframe || !pic->skinframe->base) { - Con_DPrintf("Draw_CachePic(\"%s\"): reloading pic\n", path); + Con_DPrintf("Draw_CachePic(\"%s\"): frame %i: reloading pic\n", path, draw_frame); goto reload; } if (!(cachepicflags & CACHEPICFLAG_NOTPERSISTENT)) @@ -131,11 +131,11 @@ cachepic_t *Draw_CachePic_Flags(const char *path, unsigned int cachepicflags) if (numcachepics == MAX_CACHED_PICS) { - Con_Printf ("Draw_CachePic(\"%s\"): numcachepics == MAX_CACHED_PICS\n", path); + Con_Printf ("Draw_CachePic(\"%s\"): frame %i: numcachepics == MAX_CACHED_PICS\n", path, draw_frame); // FIXME: support NULL in callers? return cachepics; // return the first one } - Con_DPrintf("Draw_CachePic(\"%s\"): loading pic\n", path); + Con_DPrintf("Draw_CachePic(\"%s\"): frame %i: loading pic%s\n", path, draw_frame, (cachepicflags & CACHEPICFLAG_NOTPERSISTENT) ? " notpersist" : ""); pic = cachepics + (numcachepics++); memset(pic, 0, sizeof(*pic)); strlcpy (pic->name, path, sizeof(pic->name)); @@ -207,7 +207,10 @@ qboolean Draw_IsPicLoaded(cachepic_t *pic) if (pic == NULL) return false; if (pic->autoload && (!pic->skinframe || !pic->skinframe->base)) + { + Con_DPrintf("Draw_IsPicLoaded(\"%s\"): Loading external skin\n", pic->name); pic->skinframe = R_SkinFrame_LoadExternal(pic->name, pic->texflags | TEXF_FORCE_RELOAD, false, true); + } // skinframe will only be NULL if the pic was created with CACHEPICFLAG_FAILONMISSING and not found return pic->skinframe != NULL && pic->skinframe->base != NULL; } @@ -217,7 +220,10 @@ rtexture_t *Draw_GetPicTexture(cachepic_t *pic) if (pic == NULL) return NULL; if (pic->autoload && (!pic->skinframe || !pic->skinframe->base)) + { + Con_DPrintf("Draw_GetPicTexture(\"%s\"): Loading external skin\n", pic->name); pic->skinframe = R_SkinFrame_LoadExternal(pic->name, pic->texflags | TEXF_FORCE_RELOAD, false, true); + } pic->lastusedframe = draw_frame; return pic->skinframe ? pic->skinframe->base : NULL; } @@ -231,8 +237,13 @@ void Draw_Frame(void) return; nextpurgetime = realtime + 0.05; for (i = 0, pic = cachepics;i < numcachepics;i++, pic++) + { if (pic->autoload && pic->skinframe && pic->skinframe->base && pic->lastusedframe < draw_frame - 3) + { + Con_DPrintf("Draw_Frame(%i): Unloading \"%s\"\n", draw_frame, pic->name); R_SkinFrame_PurgeSkinFrame(pic->skinframe); + } + } draw_frame++; } @@ -251,20 +262,23 @@ cachepic_t *Draw_NewPic(const char *picname, int width, int height, unsigned cha { if (pic->flags & CACHEPICFLAG_NEWPIC && pic->skinframe && pic->skinframe->base && pic->width == width && pic->height == height) { + Con_DPrintf("Draw_NewPic(\"%s\"): frame %i: updating texture\n", picname, draw_frame); R_UpdateTexture(pic->skinframe->base, pixels_bgra, 0, 0, 0, width, height, 1); R_SkinFrame_MarkUsed(pic->skinframe); pic->lastusedframe = draw_frame; return pic; } + Con_Printf("Draw_NewPic(\"%s\"): frame %i: reloading pic because flags/size changed\n", picname, draw_frame); } else { if (numcachepics == MAX_CACHED_PICS) { - Con_Printf ("Draw_NewPic: numcachepics == MAX_CACHED_PICS\n"); + Con_Printf ("Draw_NewPic(\"%s\"): frame %i: numcachepics == MAX_CACHED_PICS\n", picname, draw_frame); // FIXME: support NULL in callers? return cachepics; // return the first one } + Con_Printf("Draw_NewPic(\"%s\"): frame %i: creating new cachepic\n", picname, draw_frame); pic = cachepics + (numcachepics++); memset(pic, 0, sizeof(*pic)); strlcpy (pic->name, picname, sizeof(pic->name)); @@ -298,9 +312,8 @@ void Draw_FreePic(const char *picname) { if (!strcmp (picname, pic->name) && pic->skinframe) { + Con_DPrintf("Draw_FreePic(\"%s\"): frame %i: freeing pic\n", picname, draw_frame); R_SkinFrame_PurgeSkinFrame(pic->skinframe); - pic->width = 0; - pic->height = 0; return; } } diff --git a/gl_rmain.c b/gl_rmain.c index 9edd9c0d..abb360d4 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -3034,7 +3034,7 @@ static void gl_main_start(void) { case RENDERPATH_GL32: case RENDERPATH_GLES2: - Cvar_SetValueQuick(&r_textureunits, vid.texunits); + Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS); Cvar_SetValueQuick(&gl_combine, 1); Cvar_SetValueQuick(&r_glsl, 1); r_loadnormalmap = true; diff --git a/vid.h b/vid.h index c281f7dc..e1b14ef1 100644 --- a/vid.h +++ b/vid.h @@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. extern int cl_available; -#define MAX_TEXTUREUNITS 16 +#define MAX_TEXTUREUNITS 32 typedef enum renderpath_e { @@ -94,9 +94,6 @@ typedef struct viddef_s renderpath_t renderpath; qboolean allowalphatocoverage; // indicates the GL_AlphaToCoverage function works on this renderpath and framebuffer - unsigned int texunits; - unsigned int teximageunits; - unsigned int texarrayunits; unsigned int drawrangeelements_maxvertices; unsigned int drawrangeelements_maxindices; diff --git a/vid_sdl.c b/vid_sdl.c index e7a32b12..f01a4e85 100644 --- a/vid_sdl.c +++ b/vid_sdl.c @@ -1768,13 +1768,6 @@ void GLES_Init(void) Con_Printf("GL_OES_texture_3d reported bogus GL_MAX_3D_TEXTURE_SIZE, disabled\n"); } - vid.texunits = 4; - vid.teximageunits = 8; - vid.texarrayunits = 5; - qglGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, (GLint*)&vid.teximageunits);CHECKGLERROR - vid.texunits = bound(1, vid.texunits, MAX_TEXTUREUNITS); - vid.teximageunits = bound(1, vid.teximageunits, MAX_TEXTUREUNITS); - vid.texarrayunits = bound(1, vid.texarrayunits, MAX_TEXTUREUNITS); Con_DPrint("Using GLES2 rendering path\n"); vid.renderpath = RENDERPATH_GLES2; vid.sRGBcapable2D = false; diff --git a/vid_shared.c b/vid_shared.c index 8d92adb0..f29eea2a 100644 --- a/vid_shared.c +++ b/vid_shared.c @@ -773,9 +773,6 @@ void VID_ClearExtensions(void) vid.maxtexturesize_2d = 0; vid.maxtexturesize_3d = 0; vid.maxtexturesize_cubemap = 0; - vid.texunits = 1; - vid.teximageunits = 1; - vid.texarrayunits = 1; vid.max_anisotropy = 1; vid.maxdrawbuffers = 1; @@ -867,9 +864,6 @@ void VID_CheckExtensions(void) qglGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, (GLint*)&vid.maxtexturesize_cubemap); qglGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, (GLint*)&vid.maxtexturesize_3d); - vid.texunits = 4; - vid.teximageunits = 32; - vid.texarrayunits = 10; vid.renderpath = RENDERPATH_GL32; vid.sRGBcapable2D = false; vid.sRGBcapable3D = true; -- 2.39.2