also fix possible delete bugs with buffer objects and vertex/fragment programs
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
+75
-50
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user