From 765f1a12c6256282fe175ec92a0d01b45e4322c7 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Tue, 14 Sep 2004 22:28:27 +0000 Subject: [PATCH] also fix possible delete bugs with buffer objects and vertex/fragment programs --- src/mesa/main/bufferobj.c | 9 ++- src/mesa/main/mtypes.h | 7 ++- src/mesa/shader/program.c | 125 +++++++++++++++++++++++--------------- 3 files changed, 85 insertions(+), 56 deletions(-) diff --git a/src/mesa/main/bufferobj.c b/src/mesa/main/bufferobj.c index 998228e8008..84af8158ad2 100644 --- a/src/mesa/main/bufferobj.c +++ b/src/mesa/main/bufferobj.c @@ -1,6 +1,6 @@ /* * Mesa 3-D graphics library - * Version: 6.1 + * Version: 6.2 * * Copyright (C) 1999-2004 Brian Paul All Rights Reserved. * @@ -592,8 +592,11 @@ _mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids) } /* decrement refcount and delete if <= 0 */ - bufObj->DeletePending = GL_TRUE; - bufObj->RefCount--; + if (!bufObj->DeletePending) { + bufObj->DeletePending = GL_TRUE; + bufObj->RefCount--; + } + if (bufObj->RefCount <= 0) { /* buffer should not be bound anymore! */ ASSERT(ctx->Array.ArrayBufferObj != bufObj); diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 3e5c04415d2..be6882f203f 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -1574,10 +1574,11 @@ struct program_parameter_list; struct program { GLuint Id; - GLubyte *String; /* Null-terminated program text */ - GLenum Target; - GLenum Format; /* String encoding format */ + GLubyte *String; /**< Null-terminated program text */ + GLboolean DeletePending; /**< User called glDeletePrograms? */ GLint RefCount; + GLenum Target; + GLenum Format; /**< String encoding format */ GLboolean Resident; GLfloat LocalParams[MAX_PROGRAM_LOCAL_PARAMS][4]; GLuint NumInstructions; /* GL_ARB_vertex/fragment_program */ diff --git a/src/mesa/shader/program.c b/src/mesa/shader/program.c index c451fede923..7ec09b02563 100644 --- a/src/mesa/shader/program.c +++ b/src/mesa/shader/program.c @@ -1,6 +1,6 @@ /* * Mesa 3-D graphics library - * Version: 6.1 + * Version: 6.2 * * Copyright (C) 1999-2004 Brian Paul All Rights Reserved. * @@ -46,6 +46,12 @@ /**********************************************************************/ +/* A pointer to this dummy program is put into the hash table when + * glGenPrograms is called. + */ +static struct program DummyProgram; + + /** * Init context's vertex/fragment program state */ @@ -163,9 +169,12 @@ _mesa_find_line_column(const GLubyte *string, const GLubyte *pos, } -static struct program * _mesa_init_program_struct( GLcontext *ctx, - struct program *prog, - GLenum target, GLuint id) +/** + * Initialize a new vertex/fragment program object. + */ +static struct program * +_mesa_init_program_struct( GLcontext *ctx, struct program *prog, + GLenum target, GLuint id) { (void) ctx; if (prog) { @@ -178,9 +187,13 @@ static struct program * _mesa_init_program_struct( GLcontext *ctx, return prog; } -struct program * _mesa_init_fragment_program( GLcontext *ctx, - struct fragment_program *prog, - GLenum target, GLuint id) + +/** + * Initialize a new fragment program object. + */ +struct program * +_mesa_init_fragment_program( GLcontext *ctx, struct fragment_program *prog, + GLenum target, GLuint id) { if (prog) return _mesa_init_program_struct( ctx, &prog->Base, target, id ); @@ -188,9 +201,13 @@ struct program * _mesa_init_fragment_program( GLcontext *ctx, return NULL; } -struct program * _mesa_init_vertex_program( GLcontext *ctx, - struct vertex_program *prog, - GLenum target, GLuint id) + +/** + * Initialize a new vertex program object. + */ +struct program * +_mesa_init_vertex_program( GLcontext *ctx, struct vertex_program *prog, + GLenum target, GLuint id) { if (prog) return _mesa_init_program_struct( ctx, &prog->Base, target, id ); @@ -218,12 +235,10 @@ _mesa_new_program(GLcontext *ctx, GLenum target, GLuint id) case GL_VERTEX_PROGRAM_ARB: /* == GL_VERTEX_PROGRAM_NV */ return _mesa_init_vertex_program( ctx, CALLOC_STRUCT(vertex_program), target, id ); - case GL_FRAGMENT_PROGRAM_NV: case GL_FRAGMENT_PROGRAM_ARB: return _mesa_init_fragment_program( ctx, CALLOC_STRUCT(fragment_program), target, id ); - default: _mesa_problem(ctx, "bad target in _mesa_new_program"); return NULL; @@ -866,15 +881,19 @@ _mesa_BindProgram(GLenum target, GLuint id) && ctx->Extensions.NV_vertex_program) || (target == GL_VERTEX_PROGRAM_ARB && ctx->Extensions.ARB_vertex_program)) { - if (ctx->VertexProgram.Current && - ctx->VertexProgram.Current->Base.Id == id) + /*** Vertex program binding ***/ + struct vertex_program *curProg = ctx->VertexProgram.Current; + if (curProg->Base.Id == id) { + /* binding same program - no change */ return; - /* decrement refcount on previously bound vertex program */ - if (ctx->VertexProgram.Current) { - ctx->VertexProgram.Current->Base.RefCount--; + } + if (curProg->Base.Id != 0) { + /* decrement refcount on previously bound vertex program */ + curProg->Base.RefCount--; /* and delete if refcount goes below one */ - if (ctx->VertexProgram.Current->Base.RefCount <= 0) { - ctx->Driver.DeleteProgram(ctx, &(ctx->VertexProgram.Current->Base)); + if (curProg->Base.RefCount <= 0) { + ASSERT(curProg->Base.DeletePending); + ctx->Driver.DeleteProgram(ctx, &(curProg->Base)); _mesa_HashRemove(ctx->Shared->Programs, id); } } @@ -883,15 +902,19 @@ _mesa_BindProgram(GLenum target, GLuint id) && ctx->Extensions.NV_fragment_program) || (target == GL_FRAGMENT_PROGRAM_ARB && ctx->Extensions.ARB_fragment_program)) { - if (ctx->FragmentProgram.Current && - ctx->FragmentProgram.Current->Base.Id == id) + /*** Fragment program binding ***/ + struct fragment_program *curProg = ctx->FragmentProgram.Current; + if (curProg->Base.Id == id) { + /* binding same program - no change */ return; - /* decrement refcount on previously bound fragment program */ - if (ctx->FragmentProgram.Current) { - ctx->FragmentProgram.Current->Base.RefCount--; + } + if (curProg->Base.Id != 0) { + /* decrement refcount on previously bound fragment program */ + curProg->Base.RefCount--; /* and delete if refcount goes below one */ - if (ctx->FragmentProgram.Current->Base.RefCount <= 0) { - ctx->Driver.DeleteProgram(ctx, &(ctx->FragmentProgram.Current->Base)); + if (curProg->Base.RefCount <= 0) { + ASSERT(curProg->Base.DeletePending); + ctx->Driver.DeleteProgram(ctx, &(curProg->Base)); _mesa_HashRemove(ctx->Shared->Programs, id); } } @@ -905,7 +928,7 @@ _mesa_BindProgram(GLenum target, GLuint id) * That's supposed to be caught in glBegin. */ if (id == 0) { - /* default program */ + /* Bind default program */ prog = NULL; if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB) prog = ctx->Shared->DefaultVertexProgram; @@ -913,19 +936,9 @@ _mesa_BindProgram(GLenum target, GLuint id) prog = ctx->Shared->DefaultFragmentProgram; } else { + /* Bind user program */ prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id); - if (prog) { - if (prog->Target == 0) { - /* prog was allocated with glGenProgramsNV */ - prog->Target = target; - } - else if (prog->Target != target) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glBindProgramNV/ARB(target mismatch)"); - return; - } - } - else { + if (!prog || prog == &DummyProgram) { /* allocate a new program now */ prog = ctx->Driver.NewProgram(ctx, target, id); if (!prog) { @@ -934,6 +947,11 @@ _mesa_BindProgram(GLenum target, GLuint id) } _mesa_HashInsert(ctx->Shared->Programs, id, prog); } + else if (prog->Target != target) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindProgramNV/ARB(target mismatch)"); + return; + } } /* bind now */ @@ -944,6 +962,10 @@ _mesa_BindProgram(GLenum target, GLuint id) ctx->FragmentProgram.Current = (struct fragment_program *) prog; } + /* Never null pointers */ + ASSERT(ctx->VertexProgram.Current); + ASSERT(ctx->FragmentProgram.Current); + if (prog) prog->RefCount++; @@ -973,7 +995,11 @@ _mesa_DeletePrograms(GLsizei n, const GLuint *ids) if (ids[i] != 0) { struct program *prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, ids[i]); - if (prog) { + if (prog == &DummyProgram) { + _mesa_HashRemove(ctx->Shared->Programs, ids[i]); + } + else if (prog) { + /* Unbind program if necessary */ if (prog->Target == GL_VERTEX_PROGRAM_NV || prog->Target == GL_VERTEX_STATE_PROGRAM_NV) { if (ctx->VertexProgram.Current && @@ -994,18 +1020,16 @@ _mesa_DeletePrograms(GLsizei n, const GLuint *ids) _mesa_problem(ctx, "bad target in glDeleteProgramsNV"); return; } - prog->RefCount--; + /* Decrement reference count if not already marked for delete */ + if (!prog->DeletePending) { + prog->DeletePending = GL_TRUE; + prog->RefCount--; + } if (prog->RefCount <= 0) { + _mesa_HashRemove(ctx->Shared->Programs, ids[i]); ctx->Driver.DeleteProgram(ctx, prog); } } - /* Always remove entry from hash table. - * This is necessary as we can't tell from HashLookup - * whether the entry exists with data == 0, or if it - * doesn't exist at all. As GenPrograms creates the first - * case below, need to call Remove() to avoid memory leak: - */ - _mesa_HashRemove(ctx->Shared->Programs, ids[i]); } } } @@ -1034,8 +1058,9 @@ _mesa_GenPrograms(GLsizei n, GLuint *ids) first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n); + /* Insert pointer to dummy program as placeholder */ for (i = 0; i < (GLuint) n; i++) { - _mesa_HashInsert(ctx->Shared->Programs, first + i, 0); + _mesa_HashInsert(ctx->Shared->Programs, first + i, &DummyProgram); } /* Return the program names */ @@ -1046,7 +1071,7 @@ _mesa_GenPrograms(GLsizei n, GLuint *ids) /** - * Determine if id names a program. + * Determine if id names a vertex or fragment program. * \note Not compiled into display lists. * \note Called from both glIsProgramNV and glIsProgramARB. * \param id is the program identifier -- 2.30.2