/** * Lookup a GLSL shader object. */ struct gl_shader * _mesa_lookup_shader(struct gl_context *ctx, GLuint name) { if (name) { struct gl_shader *sh = (struct gl_shader *) _mesa_HashLookup(ctx->Shared->ShaderObjects, name); /* Note that both gl_shader and gl_shader_program objects are kept * in the same hash table. Check the object's type to be sure it's * what we're expecting. */ if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) { return NULL; } return sh; } return NULL; }
/** * Determine if id names a program. * \note Not compiled into display lists. * \note Called from the GL API dispatcher. * \param id is the program identifier * \return GL_TRUE if id is a program, else GL_FALSE. */ GLboolean _mesa_IsProgramNV(GLuint id) { struct vp_program *vprog; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); if (id == 0) return GL_FALSE; vprog = (struct vp_program *) _mesa_HashLookup(ctx->Shared->VertexPrograms, id); if (vprog && vprog->Target) return GL_TRUE; else return GL_FALSE; }
/** * Determine if a set of programs is resident in hardware. * \note Not compiled into display lists. * \note Called from the GL API dispatcher. */ GLboolean GLAPIENTRY _mesa_AreProgramsResidentNV(GLsizei n, const GLuint *ids, GLboolean *residences) { GLint i, j; GLboolean allResident = GL_TRUE; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV(n)"); return GL_FALSE; } for (i = 0; i < n; i++) { const struct program *prog; if (ids[i] == 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV"); return GL_FALSE; } prog = (const struct program *) _mesa_HashLookup(ctx->Shared->Programs, ids[i]); if (!prog) { _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV"); return GL_FALSE; } if (prog->Resident) { if (!allResident) residences[i] = GL_TRUE; } else { if (allResident) { allResident = GL_FALSE; for (j = 0; j < i; j++) residences[j] = GL_TRUE; } residences[i] = GL_FALSE; } } return allResident; }
/** * As above, but record an error if shader is not found. */ struct gl_shader * _mesa_lookup_shader_err(struct gl_context *ctx, GLuint name, const char *caller) { if (!name) { _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); return NULL; } else { struct gl_shader *sh = (struct gl_shader *) _mesa_HashLookup(ctx->Shared->ShaderObjects, name); if (!sh) { _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); return NULL; } if (sh->Type == GL_SHADER_PROGRAM_MESA) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); return NULL; } return sh; } }
void GLAPIENTRY _mesa_ProgramNamedParameter4fNV(GLuint id, GLsizei len, const GLubyte *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { struct program *prog; struct fragment_program *fragProg; GLfloat *v; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); FLUSH_VERTICES(ctx, _NEW_PROGRAM); prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id); if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) { _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramNamedParameterNV"); return; } if (len <= 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV(len)"); return; } fragProg = (struct fragment_program *) prog; v = _mesa_lookup_parameter_value(fragProg->Base.Parameters, len, (char *) name); if (v) { v[0] = x; v[1] = y; v[2] = z; v[3] = w; return; } _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV(name)"); }
void GLAPIENTRY _mesa_GetProgramNamedParameterfvNV(GLuint id, GLsizei len, const GLubyte *name, GLfloat *params) { struct program *prog; struct fragment_program *fragProg; const GLfloat *v; GET_CURRENT_CONTEXT(ctx); if (!ctx->_CurrentProgram) ASSERT_OUTSIDE_BEGIN_END(ctx); prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id); if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramNamedParameterNV"); return; } if (len <= 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV"); return; } fragProg = (struct fragment_program *) prog; v = _mesa_lookup_parameter_value(fragProg->Base.Parameters, len, (char *) name); if (v) { params[0] = v[0]; params[1] = v[1]; params[2] = v[2]; params[3] = v[3]; return; } _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV"); }
/** * Execute a vertex state program. * \note Called from the GL API dispatcher. */ void _mesa_ExecuteProgramNV(GLenum target, GLuint id, const GLfloat *params) { struct vp_program *vprog; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (target != GL_VERTEX_STATE_PROGRAM_NV) { _mesa_error(ctx, GL_INVALID_ENUM, "glExecuteProgramNV"); return; } vprog = (struct vp_program *) _mesa_HashLookup(ctx->Shared->VertexPrograms, id); if (!vprog || vprog->Target != GL_VERTEX_STATE_PROGRAM_NV) { _mesa_error(ctx, GL_INVALID_OPERATION, "glExecuteProgramNV"); return; } _mesa_init_vp_registers(ctx); _mesa_init_tracked_matrices(ctx); COPY_4V(ctx->VertexProgram.Machine.Registers[VP_INPUT_REG_START], params); _mesa_exec_program(ctx, vprog); }
/** * Test walking over all the entries in a hash table. */ static void test_hash_walking(void) { struct _mesa_HashTable *t = _mesa_NewHashTable(); const GLuint limit = 50000; GLuint i; /* create some entries */ for (i = 0; i < limit; i++) { GLuint dummy; GLuint k = (rand() % (limit * 10)) + 1; while (_mesa_HashLookup(t, k)) { /* id already in use, try another */ k = (rand() % (limit * 10)) + 1; } _mesa_HashInsert(t, k, &dummy); } /* walk over all entries */ { GLuint k = _mesa_HashFirstEntry(t); GLuint count = 0; while (k) { GLuint knext = _mesa_HashNextEntry(t, k); assert(knext != k); _mesa_HashRemove(t, k); count++; k = knext; } assert(count == limit); k = _mesa_HashFirstEntry(t); assert(k==0); } _mesa_DeleteHashTable(t); }
/** * Bind a program (make it current) * \note Called from the GL API dispatcher by both glBindProgramNV * and glBindProgramARB. */ void GLAPIENTRY _mesa_BindProgram(GLenum target, GLuint id) { struct program *prog; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); /* texture state is dependent on current fragment and vertex programs */ FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_TEXTURE); if ((target == GL_VERTEX_PROGRAM_NV && 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) return; /* decrement refcount on previously bound vertex program */ if (ctx->VertexProgram.Current) { ctx->VertexProgram.Current->Base.RefCount--; /* and delete if refcount goes below one */ if (ctx->VertexProgram.Current->Base.RefCount <= 0) { _mesa_delete_program(ctx, &(ctx->VertexProgram.Current->Base)); _mesa_HashRemove(ctx->Shared->Programs, id); } } } else if ((target == GL_FRAGMENT_PROGRAM_NV && 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) return; /* decrement refcount on previously bound fragment program */ if (ctx->FragmentProgram.Current) { ctx->FragmentProgram.Current->Base.RefCount--; /* and delete if refcount goes below one */ if (ctx->FragmentProgram.Current->Base.RefCount <= 0) { _mesa_delete_program(ctx, &(ctx->FragmentProgram.Current->Base)); _mesa_HashRemove(ctx->Shared->Programs, id); } } } else { _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)"); return; } /* NOTE: binding to a non-existant program is not an error. * That's supposed to be caught in glBegin. */ if (id == 0) { /* default program */ prog = NULL; if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB) prog = ctx->Shared->DefaultVertexProgram; else prog = ctx->Shared->DefaultFragmentProgram; } else { 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 { /* allocate a new program now */ prog = _mesa_alloc_program(ctx, target, id); if (!prog) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB"); return; } prog->Id = id; prog->Target = target; prog->Resident = GL_TRUE; prog->RefCount = 1; _mesa_HashInsert(ctx->Shared->Programs, id, prog); } } /* bind now */ if (target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_PROGRAM_ARB) { ctx->VertexProgram.Current = (struct vertex_program *) prog; } else if (target == GL_FRAGMENT_PROGRAM_NV || target == GL_FRAGMENT_PROGRAM_ARB) { ctx->FragmentProgram.Current = (struct fragment_program *) prog; } if (prog) prog->RefCount++; }
/** * Return the gl_texture_object for a given ID. */ struct gl_texture_object * _mesa_lookup_texture(struct gl_context *ctx, GLuint id) { return (struct gl_texture_object *) _mesa_HashLookup(ctx->Shared->TexObjects, id); }
static struct gl_query_object * lookup_query_object(GLcontext *ctx, GLuint id) { return (struct gl_query_object *) _mesa_HashLookup(ctx->Query.QueryObjects, id); }
/** * Delete named textures. * * \param n number of textures to be deleted. * \param texName array of textures names to be deleted. * * \sa glDeleteTextures(). * * For each texture checks if its bound to any of the texture units, unbinding * it and decrementing the reference count if so. If the texture reference * count is zero, delete its object. */ void GLAPIENTRY _mesa_DeleteTextures( GLsizei n, const GLuint *texName) { GET_CURRENT_CONTEXT(ctx); GLint i; ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */ if (!texName) return; for (i=0;i<n;i++) { if (texName[i] > 0) { struct gl_texture_object *delObj = (struct gl_texture_object *) _mesa_HashLookup(ctx->Shared->TexObjects, texName[i]); if (delObj) { /* First check if this texture is currently bound. * If so, unbind it and decrement the reference count. */ GLuint u; for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) { struct gl_texture_unit *unit = &ctx->Texture.Unit[u]; if (delObj == unit->Current1D) { unit->Current1D = ctx->Shared->Default1D; ctx->Shared->Default1D->RefCount++; delObj->RefCount--; if (delObj == unit->_Current) unit->_Current = unit->Current1D; } else if (delObj == unit->Current2D) { unit->Current2D = ctx->Shared->Default2D; ctx->Shared->Default2D->RefCount++; delObj->RefCount--; if (delObj == unit->_Current) unit->_Current = unit->Current2D; } else if (delObj == unit->Current3D) { unit->Current3D = ctx->Shared->Default3D; ctx->Shared->Default3D->RefCount++; delObj->RefCount--; if (delObj == unit->_Current) unit->_Current = unit->Current3D; } else if (delObj == unit->CurrentCubeMap) { unit->CurrentCubeMap = ctx->Shared->DefaultCubeMap; ctx->Shared->DefaultCubeMap->RefCount++; delObj->RefCount--; if (delObj == unit->_Current) unit->_Current = unit->CurrentCubeMap; } else if (delObj == unit->CurrentRect) { unit->CurrentRect = ctx->Shared->DefaultRect; ctx->Shared->DefaultRect->RefCount++; delObj->RefCount--; if (delObj == unit->_Current) unit->_Current = unit->CurrentRect; } } ctx->NewState |= _NEW_TEXTURE; /* Decrement reference count and delete if zero */ delObj->RefCount--; ASSERT(delObj->RefCount >= 0); if (delObj->RefCount == 0) { ASSERT(delObj->Name != 0); _mesa_remove_texture_object(ctx, delObj); ASSERT(ctx->Driver.DeleteTexture); (*ctx->Driver.DeleteTexture)(ctx, delObj); } } } } }
/** * Bind a named texture to a texturing target. * * \param target texture target. * \param texName texture name. * * \sa glBindTexture(). * * Determines the old texture object bound and returns immediately if rebinding * the same texture. Get the current texture which is either a default texture * if name is null, a named texture from the hash, or a new texture if the * given texture name is new. Increments its reference count, binds it, and * calls dd_function_table::BindTexture. Decrements the old texture reference * count and deletes it if it reaches zero. */ void GLAPIENTRY _mesa_BindTexture( GLenum target, GLuint texName ) { GET_CURRENT_CONTEXT(ctx); GLuint unit = ctx->Texture.CurrentUnit; struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; struct gl_texture_object *oldTexObj; struct gl_texture_object *newTexObj = NULL; ASSERT_OUTSIDE_BEGIN_END(ctx); if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) _mesa_debug(ctx, "glBindTexture %s %d\n", _mesa_lookup_enum_by_nr(target), (GLint) texName); /* * Get pointer to currently bound texture object (oldTexObj) */ switch (target) { case GL_TEXTURE_1D: oldTexObj = texUnit->Current1D; break; case GL_TEXTURE_2D: oldTexObj = texUnit->Current2D; break; case GL_TEXTURE_3D: oldTexObj = texUnit->Current3D; break; case GL_TEXTURE_CUBE_MAP_ARB: if (!ctx->Extensions.ARB_texture_cube_map) { _mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" ); return; } oldTexObj = texUnit->CurrentCubeMap; break; case GL_TEXTURE_RECTANGLE_NV: if (!ctx->Extensions.NV_texture_rectangle) { _mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" ); return; } oldTexObj = texUnit->CurrentRect; break; default: _mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" ); return; } if (oldTexObj->Name == texName) /* XXX this might be wrong. If the texobj is in use by another * context and a texobj parameter was changed, this might be our * only chance to update this context's hardware state. */ return; /* rebinding the same texture- no change */ /* * Get pointer to new texture object (newTexObj) */ if (texName == 0) { /* newTexObj = a default texture object */ switch (target) { case GL_TEXTURE_1D: newTexObj = ctx->Shared->Default1D; break; case GL_TEXTURE_2D: newTexObj = ctx->Shared->Default2D; break; case GL_TEXTURE_3D: newTexObj = ctx->Shared->Default3D; break; case GL_TEXTURE_CUBE_MAP_ARB: newTexObj = ctx->Shared->DefaultCubeMap; break; case GL_TEXTURE_RECTANGLE_NV: newTexObj = ctx->Shared->DefaultRect; break; default: ; /* Bad targets are caught above */ } } else { /* non-default texture object */ const struct _mesa_HashTable *hash = ctx->Shared->TexObjects; newTexObj = (struct gl_texture_object *) _mesa_HashLookup(hash, texName); if (newTexObj) { /* error checking */ if (newTexObj->Target != 0 && newTexObj->Target != target) { /* the named texture object's dimensions don't match the target */ _mesa_error( ctx, GL_INVALID_OPERATION, "glBindTexture(wrong dimensionality)" ); return; } if (newTexObj->Target == 0 && target == GL_TEXTURE_RECTANGLE_NV) { /* have to init wrap and filter state here - kind of klunky */ newTexObj->WrapS = GL_CLAMP_TO_EDGE; newTexObj->WrapT = GL_CLAMP_TO_EDGE; newTexObj->WrapR = GL_CLAMP_TO_EDGE; newTexObj->MinFilter = GL_LINEAR; if (ctx->Driver.TexParameter) { static const GLfloat fparam_wrap[1] = {(GLfloat) GL_CLAMP_TO_EDGE}; static const GLfloat fparam_filter[1] = {(GLfloat) GL_LINEAR}; (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_WRAP_S, fparam_wrap ); (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_WRAP_T, fparam_wrap ); (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_WRAP_R, fparam_wrap ); (*ctx->Driver.TexParameter)( ctx, target, newTexObj, GL_TEXTURE_MIN_FILTER, fparam_filter ); } } } else { /* if this is a new texture id, allocate a texture object now */ newTexObj = (*ctx->Driver.NewTextureObject)(ctx, texName, target); if (!newTexObj) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture"); return; } /* and insert it into hash table */ _glthread_LOCK_MUTEX(ctx->Shared->Mutex); _mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj); _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); } newTexObj->Target = target; } /* XXX all RefCount accesses should be protected by a mutex. */ newTexObj->RefCount++; /* do the actual binding, but first flush outstanding vertices: */ FLUSH_VERTICES(ctx, _NEW_TEXTURE); switch (target) { case GL_TEXTURE_1D: texUnit->Current1D = newTexObj; break; case GL_TEXTURE_2D: texUnit->Current2D = newTexObj; break; case GL_TEXTURE_3D: texUnit->Current3D = newTexObj; break; case GL_TEXTURE_CUBE_MAP_ARB: texUnit->CurrentCubeMap = newTexObj; break; case GL_TEXTURE_RECTANGLE_NV: texUnit->CurrentRect = newTexObj; break; default: _mesa_problem(ctx, "bad target in BindTexture"); return; } /* Pass BindTexture call to device driver */ if (ctx->Driver.BindTexture) (*ctx->Driver.BindTexture)( ctx, target, newTexObj ); /* Decrement the reference count on the old texture and check if it's * time to delete it. */ /* XXX all RefCount accesses should be protected by a mutex. */ oldTexObj->RefCount--; ASSERT(oldTexObj->RefCount >= 0); if (oldTexObj->RefCount == 0) { ASSERT(oldTexObj->Name != 0); ASSERT(ctx->Driver.DeleteTexture); (*ctx->Driver.DeleteTexture)( ctx, oldTexObj ); } }
/** * Delete named textures. * * \param n number of textures to be deleted. * \param textures array of texture IDs to be deleted. * * \sa glDeleteTextures(). * * If we're about to delete a texture that's currently bound to any * texture unit, unbind the texture first. Decrement the reference * count on the texture object and delete it if it's zero. * Recall that texture objects can be shared among several rendering * contexts. */ void GLAPIENTRY _mesa_DeleteTextures( GLsizei n, const GLuint *textures) { GET_CURRENT_CONTEXT(ctx); GLint i; ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); /* too complex */ if (!textures) return; for (i = 0; i < n; i++) { if (textures[i] > 0) { struct gl_texture_object *delObj = (struct gl_texture_object *) _mesa_HashLookup(ctx->Shared->TexObjects, textures[i]); if (delObj) { /* First check if this texture is currently bound. * If so, unbind it and decrement the reference count. * XXX all RefCount accesses should be protected by a mutex. */ GLuint u; for (u = 0; u < MAX_TEXTURE_IMAGE_UNITS; u++) { struct gl_texture_unit *unit = &ctx->Texture.Unit[u]; if (delObj == unit->Current1D) { unit->Current1D = ctx->Shared->Default1D; ctx->Shared->Default1D->RefCount++; delObj->RefCount--; if (delObj == unit->_Current) unit->_Current = unit->Current1D; } else if (delObj == unit->Current2D) { unit->Current2D = ctx->Shared->Default2D; ctx->Shared->Default2D->RefCount++; delObj->RefCount--; if (delObj == unit->_Current) unit->_Current = unit->Current2D; } else if (delObj == unit->Current3D) { unit->Current3D = ctx->Shared->Default3D; ctx->Shared->Default3D->RefCount++; delObj->RefCount--; if (delObj == unit->_Current) unit->_Current = unit->Current3D; } else if (delObj == unit->CurrentCubeMap) { unit->CurrentCubeMap = ctx->Shared->DefaultCubeMap; ctx->Shared->DefaultCubeMap->RefCount++; delObj->RefCount--; if (delObj == unit->_Current) unit->_Current = unit->CurrentCubeMap; } else if (delObj == unit->CurrentRect) { unit->CurrentRect = ctx->Shared->DefaultRect; ctx->Shared->DefaultRect->RefCount++; delObj->RefCount--; if (delObj == unit->_Current) unit->_Current = unit->CurrentRect; } } ctx->NewState |= _NEW_TEXTURE; /* The texture _name_ is now free for re-use. * Remove it from the hash table now. */ _glthread_LOCK_MUTEX(ctx->Shared->Mutex); _mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name); _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); /* The actual texture object will not be freed until it's no * longer bound in any context. * XXX all RefCount accesses should be protected by a mutex. */ delObj->RefCount--; if (delObj->RefCount == 0) { ASSERT(delObj->Name != 0); /* Never delete default tex objs */ ASSERT(ctx->Driver.DeleteTexture); (*ctx->Driver.DeleteTexture)(ctx, delObj); } } } } }
/** * Delete a set of buffer objects. * * \param n Number of buffer objects to delete. * \param ids Array of \c n buffer object IDs. */ void GLAPIENTRY _mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids) { GET_CURRENT_CONTEXT(ctx); GLsizei i; ASSERT_OUTSIDE_BEGIN_END(ctx); if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)"); return; } _glthread_LOCK_MUTEX(ctx->Shared->Mutex); for (i = 0; i < n; i++) { if (ids[i] != 0) { struct gl_buffer_object *bufObj = (struct gl_buffer_object *) _mesa_HashLookup(ctx->Shared->BufferObjects, ids[i]); if (bufObj) { /* unbind any vertex pointers bound to this buffer */ GLuint j; ASSERT(bufObj->Name == ids[i]); if (ctx->Array.Vertex.BufferObj == bufObj) { bufObj->RefCount--; ctx->Array.Vertex.BufferObj = ctx->Array.NullBufferObj; ctx->Array.NullBufferObj->RefCount++; } if (ctx->Array.Normal.BufferObj == bufObj) { bufObj->RefCount--; ctx->Array.Normal.BufferObj = ctx->Array.NullBufferObj; ctx->Array.NullBufferObj->RefCount++; } if (ctx->Array.Color.BufferObj == bufObj) { bufObj->RefCount--; ctx->Array.Color.BufferObj = ctx->Array.NullBufferObj; ctx->Array.NullBufferObj->RefCount++; } if (ctx->Array.SecondaryColor.BufferObj == bufObj) { bufObj->RefCount--; ctx->Array.SecondaryColor.BufferObj = ctx->Array.NullBufferObj; ctx->Array.NullBufferObj->RefCount++; } if (ctx->Array.FogCoord.BufferObj == bufObj) { bufObj->RefCount--; ctx->Array.FogCoord.BufferObj = ctx->Array.NullBufferObj; ctx->Array.NullBufferObj->RefCount++; } if (ctx->Array.Index.BufferObj == bufObj) { bufObj->RefCount--; ctx->Array.Index.BufferObj = ctx->Array.NullBufferObj; ctx->Array.NullBufferObj->RefCount++; } if (ctx->Array.EdgeFlag.BufferObj == bufObj) { bufObj->RefCount--; ctx->Array.EdgeFlag.BufferObj = ctx->Array.NullBufferObj; ctx->Array.NullBufferObj->RefCount++; } for (j = 0; j < MAX_TEXTURE_UNITS; j++) { if (ctx->Array.TexCoord[j].BufferObj == bufObj) { bufObj->RefCount--; ctx->Array.TexCoord[j].BufferObj = ctx->Array.NullBufferObj; ctx->Array.NullBufferObj->RefCount++; } } for (j = 0; j < VERT_ATTRIB_MAX; j++) { if (ctx->Array.VertexAttrib[j].BufferObj == bufObj) { bufObj->RefCount--; ctx->Array.VertexAttrib[j].BufferObj = ctx->Array.NullBufferObj; ctx->Array.NullBufferObj->RefCount++; } } if (ctx->Array.ArrayBufferObj == bufObj) { _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 ); } if (ctx->Array.ElementArrayBufferObj == bufObj) { _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 ); } if (ctx->Pack.BufferObj == bufObj) { _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 ); } if (ctx->Unpack.BufferObj == bufObj) { _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 ); } /* The ID is immediately freed for re-use */ _mesa_remove_buffer_object(ctx, bufObj); bufObj->RefCount--; if (bufObj->RefCount <= 0) { ASSERT(ctx->Array.ArrayBufferObj != bufObj); ASSERT(ctx->Array.ElementArrayBufferObj != bufObj); ASSERT(ctx->Array.Vertex.BufferObj != bufObj); ASSERT(ctx->Driver.DeleteBuffer); ctx->Driver.DeleteBuffer(ctx, bufObj); } } } } _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); }
void GLAPIENTRY _mesa_BindBufferARB(GLenum target, GLuint buffer) { GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *oldBufObj; struct gl_buffer_object *newBufObj = NULL; ASSERT_OUTSIDE_BEGIN_END(ctx); oldBufObj = buffer_object_get_target( ctx, target, "BindBufferARB" ); if (oldBufObj && oldBufObj->Name == buffer) return; /* rebinding the same buffer object- no change */ /* * Get pointer to new buffer object (newBufObj) */ if (buffer == 0) { /* The spec says there's not a buffer object named 0, but we use * one internally because it simplifies things. */ newBufObj = ctx->Array.NullBufferObj; } else { /* non-default buffer object */ const struct _mesa_HashTable *hash = ctx->Shared->BufferObjects; newBufObj = (struct gl_buffer_object *) _mesa_HashLookup(hash, buffer); if (!newBufObj) { /* if this is a new buffer object id, allocate a buffer object now */ newBufObj = (*ctx->Driver.NewBufferObject)(ctx, buffer, target); if (!newBufObj) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB"); return; } _mesa_save_buffer_object(ctx, newBufObj); } newBufObj->RefCount++; } switch (target) { case GL_ARRAY_BUFFER_ARB: ctx->Array.ArrayBufferObj = newBufObj; break; case GL_ELEMENT_ARRAY_BUFFER_ARB: ctx->Array.ElementArrayBufferObj = newBufObj; break; case GL_PIXEL_PACK_BUFFER_EXT: ctx->Pack.BufferObj = newBufObj; break; case GL_PIXEL_UNPACK_BUFFER_EXT: ctx->Unpack.BufferObj = newBufObj; break; default: _mesa_problem(ctx, "Bad target in _mesa_BindBufferARB"); return; } /* Pass BindBuffer call to device driver */ if (ctx->Driver.BindBuffer && newBufObj) (*ctx->Driver.BindBuffer)( ctx, target, newBufObj ); if (oldBufObj) { oldBufObj->RefCount--; assert(oldBufObj->RefCount >= 0); if (oldBufObj->RefCount == 0) { assert(oldBufObj->Name != 0); ASSERT(ctx->Driver.DeleteBuffer); ctx->Driver.DeleteBuffer( ctx, oldBufObj ); } } }
/** * Bind a named texture to a texturing target. * * \param target texture target. * \param texName texture name. * * \sa glBindTexture(). * * Determines the old texture object bound and returns immediately if rebinding * the same texture. Get the current texture which is either a default texture * if name is null, a named texture from the hash, or a new texture if the * given texture name is new. Increments its reference count, binds it, and * calls dd_function_table::BindTexture. Decrements the old texture reference * count and deletes it if it reaches zero. */ void GLAPIENTRY _mesa_BindTexture( GLenum target, GLuint texName ) { GET_CURRENT_CONTEXT(ctx); GLuint unit = ctx->Texture.CurrentUnit; struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; struct gl_texture_object *oldTexObj; struct gl_texture_object *newTexObj = 0; ASSERT_OUTSIDE_BEGIN_END(ctx); if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) _mesa_debug(ctx, "glBindTexture %s %d\n", _mesa_lookup_enum_by_nr(target), (GLint) texName); switch (target) { case GL_TEXTURE_1D: oldTexObj = texUnit->Current1D; break; case GL_TEXTURE_2D: oldTexObj = texUnit->Current2D; break; case GL_TEXTURE_3D: oldTexObj = texUnit->Current3D; break; case GL_TEXTURE_CUBE_MAP_ARB: if (!ctx->Extensions.ARB_texture_cube_map) { _mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" ); return; } oldTexObj = texUnit->CurrentCubeMap; break; case GL_TEXTURE_RECTANGLE_NV: if (!ctx->Extensions.NV_texture_rectangle) { _mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" ); return; } oldTexObj = texUnit->CurrentRect; break; default: _mesa_error( ctx, GL_INVALID_ENUM, "glBindTexture(target)" ); return; } if (oldTexObj->Name == texName) return; /* rebinding the same texture- no change */ /* * Get pointer to new texture object (newTexObj) */ if (texName == 0) { /* newTexObj = a default texture object */ switch (target) { case GL_TEXTURE_1D: newTexObj = ctx->Shared->Default1D; break; case GL_TEXTURE_2D: newTexObj = ctx->Shared->Default2D; break; case GL_TEXTURE_3D: newTexObj = ctx->Shared->Default3D; break; case GL_TEXTURE_CUBE_MAP_ARB: newTexObj = ctx->Shared->DefaultCubeMap; break; case GL_TEXTURE_RECTANGLE_NV: newTexObj = ctx->Shared->DefaultRect; break; default: ; /* Bad targets are caught above */ } } else { /* non-default texture object */ const struct _mesa_HashTable *hash = ctx->Shared->TexObjects; newTexObj = (struct gl_texture_object *) _mesa_HashLookup(hash, texName); if (newTexObj) { /* error checking */ if (newTexObj->Target != 0 && newTexObj->Target != target) { /* the named texture object's dimensions don't match the target */ _mesa_error( ctx, GL_INVALID_OPERATION, "glBindTexture(wrong dimensionality)" ); return; } if (newTexObj->Target == 0 && target == GL_TEXTURE_RECTANGLE_NV) { /* have to init wrap and filter state here - kind of klunky */ newTexObj->WrapS = GL_CLAMP_TO_EDGE; newTexObj->WrapT = GL_CLAMP_TO_EDGE; newTexObj->WrapR = GL_CLAMP_TO_EDGE; newTexObj->MinFilter = GL_LINEAR; } } else { /* if this is a new texture id, allocate a texture object now */ newTexObj = (*ctx->Driver.NewTextureObject)(ctx, texName, target); if (!newTexObj) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture"); return; } _mesa_save_texture_object(ctx, newTexObj); } newTexObj->Target = target; } newTexObj->RefCount++; /* do the actual binding, but first flush outstanding vertices: */ FLUSH_VERTICES(ctx, _NEW_TEXTURE); switch (target) { case GL_TEXTURE_1D: texUnit->Current1D = newTexObj; break; case GL_TEXTURE_2D: texUnit->Current2D = newTexObj; break; case GL_TEXTURE_3D: texUnit->Current3D = newTexObj; break; case GL_TEXTURE_CUBE_MAP_ARB: texUnit->CurrentCubeMap = newTexObj; break; case GL_TEXTURE_RECTANGLE_NV: texUnit->CurrentRect = newTexObj; break; default: _mesa_problem(ctx, "bad target in BindTexture"); return; } /* Pass BindTexture call to device driver */ if (ctx->Driver.BindTexture) (*ctx->Driver.BindTexture)( ctx, target, newTexObj ); oldTexObj->RefCount--; assert(oldTexObj->RefCount >= 0); if (oldTexObj->RefCount == 0) { assert(oldTexObj->Name != 0); _mesa_remove_texture_object(ctx, oldTexObj); ASSERT(ctx->Driver.DeleteTexture); (*ctx->Driver.DeleteTexture)( ctx, oldTexObj ); } }