diff options
| author | Brian Paul <brian.paul@tungstengraphics.com> | 2004-09-14 22:28:27 +0000 | 
|---|---|---|
| committer | Brian Paul <brian.paul@tungstengraphics.com> | 2004-09-14 22:28:27 +0000 | 
| commit | 765f1a12c6256282fe175ec92a0d01b45e4322c7 (patch) | |
| tree | 0f338633fea0bcf7f84abecb201f83949602d87e /src | |
| parent | 8de924dbb0447579fa455c94a1e410c69e5ce4b5 (diff) | |
also fix possible delete bugs with buffer objects and vertex/fragment programs
Diffstat (limited to 'src')
| -rw-r--r-- | src/mesa/main/bufferobj.c | 9 | ||||
| -rw-r--r-- | src/mesa/main/mtypes.h | 7 | ||||
| -rw-r--r-- | 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 998228e800..84af8158ad 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 3e5c04415d..be6882f203 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 c451fede92..7ec09b0256 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 | 
