/** * Insert into the hash table. If an entry with this key already exists * we'll replace the existing entry. * \param table - the hash table * \param key - the key (not zero) * \param data - pointer to user data */ void _mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data) { /* search for existing entry with this key */ GLuint pos; struct HashEntry *entry; assert(table); assert(key); _glthread_LOCK_MUTEX(table->Mutex); if (key > table->MaxKey) table->MaxKey = key; pos = key & (TABLE_SIZE-1); entry = table->Table[pos]; while (entry) { if (entry->Key == key) { /* replace entry's data */ entry->Data = data; _glthread_UNLOCK_MUTEX(table->Mutex); return; } entry = entry->Next; } /* alloc and insert new table entry */ entry = MALLOC_STRUCT(HashEntry); entry->Key = key; entry->Data = data; entry->Next = table->Table[pos]; table->Table[pos] = entry; _glthread_UNLOCK_MUTEX(table->Mutex); }
/** * Remove an entry from the hash table. * \param table - the hash table * \param key - key of entry to remove */ void _mesa_HashRemove(struct _mesa_HashTable *table, GLuint key) { GLuint pos; struct HashEntry *entry, *prev; assert(table); assert(key); _glthread_LOCK_MUTEX(table->Mutex); pos = key & (TABLE_SIZE-1); prev = NULL; entry = table->Table[pos]; while (entry) { if (entry->Key == key) { /* found it! */ if (prev) { prev->Next = entry->Next; } else { table->Table[pos] = entry->Next; } FREE(entry); _glthread_UNLOCK_MUTEX(table->Mutex); return; } prev = entry; entry = entry->Next; } _glthread_UNLOCK_MUTEX(table->Mutex); }
/** * Make context 'ctx' share the display lists, textures and programs * that are associated with 'ctxToShare'. * Any display lists, textures or programs associated with 'ctx' will * be deleted if nobody else is sharing them. */ GLboolean _mesa_share_state(GLcontext *ctx, GLcontext *ctxToShare) { if (ctx && ctxToShare && ctx->Shared && ctxToShare->Shared) { struct gl_shared_state *oldSharedState = ctx->Shared; GLint RefCount; ctx->Shared = ctxToShare->Shared; _glthread_LOCK_MUTEX(ctx->Shared->Mutex); ctx->Shared->RefCount++; _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); update_default_objects(ctx); _glthread_LOCK_MUTEX(oldSharedState->Mutex); RefCount = --oldSharedState->RefCount; _glthread_UNLOCK_MUTEX(oldSharedState->Mutex); if (RefCount == 0) { _mesa_free_shared_state(ctx, oldSharedState); } return GL_TRUE; } else { return GL_FALSE; } }
/** * Set *ptr to point to rb. If *ptr points to another renderbuffer, * dereference that buffer first. The new renderbuffer's refcount will * be incremented. The old renderbuffer's refcount will be decremented. * This is normally only called from the _mesa_reference_renderbuffer() macro * when there's a real pointer change. */ void _mesa_reference_renderbuffer_(struct gl_renderbuffer **ptr, struct gl_renderbuffer *rb) { if (*ptr) { /* Unreference the old renderbuffer */ GLboolean deleteFlag = GL_FALSE; struct gl_renderbuffer *oldRb = *ptr; _glthread_LOCK_MUTEX(oldRb->Mutex); ASSERT(oldRb->RefCount > 0); oldRb->RefCount--; /*printf("RB DECR %p (%d) to %d\n", (void*) oldRb, oldRb->Name, oldRb->RefCount);*/ deleteFlag = (oldRb->RefCount == 0); _glthread_UNLOCK_MUTEX(oldRb->Mutex); if (deleteFlag) { oldRb->Delete(oldRb); } *ptr = NULL; } assert(!*ptr); if (rb) { /* reference new renderbuffer */ _glthread_LOCK_MUTEX(rb->Mutex); rb->RefCount++; /*printf("RB INCR %p (%d) to %d\n", (void*) rb, rb->Name, rb->RefCount);*/ _glthread_UNLOCK_MUTEX(rb->Mutex); *ptr = rb; } }
/** * Find a block of 'numKeys' adjacent unused hash keys. * \param table - the hash table * \param numKeys - number of keys needed * \return Starting key of free block or 0 if failure */ GLuint _mesa_HashFindFreeKeyBlock(struct _mesa_HashTable *table, GLuint numKeys) { GLuint maxKey = ~((GLuint) 0); _glthread_LOCK_MUTEX(table->Mutex); if (maxKey - numKeys > table->MaxKey) { /* the quick solution */ _glthread_UNLOCK_MUTEX(table->Mutex); return table->MaxKey + 1; } else { /* the slow solution */ GLuint freeCount = 0; GLuint freeStart = 1; GLuint key; for (key=1; key!=maxKey; key++) { if (_mesa_HashLookup(table, key)) { /* darn, this key is already in use */ freeCount = 0; freeStart = key+1; } else { /* this key not in use, check if we've found enough */ freeCount++; if (freeCount == numKeys) { _glthread_UNLOCK_MUTEX(table->Mutex); return freeStart; } } } /* cannot allocate a block of numKeys consecutive keys */ _glthread_UNLOCK_MUTEX(table->Mutex); return 0; } }
/** * Set *ptr to point to fb, with refcounting and locking. * This is normally only called from the _mesa_reference_framebuffer() macro * when there's a real pointer change. */ void _mesa_reference_framebuffer_(struct gl_framebuffer **ptr, struct gl_framebuffer *fb) { if (*ptr) { /* unreference old renderbuffer */ GLboolean deleteFlag = GL_FALSE; struct gl_framebuffer *oldFb = *ptr; _glthread_LOCK_MUTEX(oldFb->Mutex); ASSERT(oldFb->RefCount > 0); oldFb->RefCount--; deleteFlag = (oldFb->RefCount == 0); _glthread_UNLOCK_MUTEX(oldFb->Mutex); if (deleteFlag) oldFb->Delete(oldFb); *ptr = NULL; } assert(!*ptr); if (fb) { _glthread_LOCK_MUTEX(fb->Mutex); fb->RefCount++; _glthread_UNLOCK_MUTEX(fb->Mutex); *ptr = fb; } }
/** * Set ptr to bufObj w/ reference counting. * This is normally only called from the _mesa_reference_buffer_object() macro * when there's a real pointer change. */ void _mesa_reference_buffer_object_(struct gl_context *ctx, struct gl_buffer_object **ptr, struct gl_buffer_object *bufObj) { if (*ptr) { /* Unreference the old buffer */ GLboolean deleteFlag = GL_FALSE; struct gl_buffer_object *oldObj = *ptr; _glthread_LOCK_MUTEX(oldObj->Mutex); ASSERT(oldObj->RefCount > 0); oldObj->RefCount--; #if 0 printf("BufferObj %p %d DECR to %d\n", (void *) oldObj, oldObj->Name, oldObj->RefCount); #endif deleteFlag = (oldObj->RefCount == 0); _glthread_UNLOCK_MUTEX(oldObj->Mutex); if (deleteFlag) { /* some sanity checking: don't delete a buffer still in use */ #if 0 /* unfortunately, these tests are invalid during context tear-down */ ASSERT(ctx->Array.ArrayBufferObj != bufObj); ASSERT(ctx->Array.ArrayObj->ElementArrayBufferObj != bufObj); ASSERT(ctx->Array.ArrayObj->Vertex.BufferObj != bufObj); #endif ASSERT(ctx->Driver.DeleteBuffer); ctx->Driver.DeleteBuffer(ctx, oldObj); } *ptr = NULL; } ASSERT(!*ptr); if (bufObj) { /* reference new buffer */ _glthread_LOCK_MUTEX(bufObj->Mutex); if (bufObj->RefCount == 0) { /* this buffer's being deleted (look just above) */ /* Not sure this can every really happen. Warn if it does. */ _mesa_problem(NULL, "referencing deleted buffer object"); *ptr = NULL; } else { bufObj->RefCount++; #if 0 printf("BufferObj %p %d INCR to %d\n", (void *) bufObj, bufObj->Name, bufObj->RefCount); #endif *ptr = bufObj; } _glthread_UNLOCK_MUTEX(bufObj->Mutex); } }
/** * Set ptr to arrayObj w/ reference counting. */ void _mesa_reference_array_object(struct gl_context *ctx, struct gl_array_object **ptr, struct gl_array_object *arrayObj) { if (*ptr == arrayObj) return; if (*ptr) { /* Unreference the old array object */ GLboolean deleteFlag = GL_FALSE; struct gl_array_object *oldObj = *ptr; _glthread_LOCK_MUTEX(oldObj->Mutex); ASSERT(oldObj->RefCount > 0); oldObj->RefCount--; #if 0 printf("ArrayObj %p %d DECR to %d\n", (void *) oldObj, oldObj->Name, oldObj->RefCount); #endif deleteFlag = (oldObj->RefCount == 0); _glthread_UNLOCK_MUTEX(oldObj->Mutex); if (deleteFlag) { ASSERT(ctx->Driver.DeleteArrayObject); ctx->Driver.DeleteArrayObject(ctx, oldObj); } *ptr = NULL; } ASSERT(!*ptr); if (arrayObj) { /* reference new array object */ _glthread_LOCK_MUTEX(arrayObj->Mutex); if (arrayObj->RefCount == 0) { /* this array's being deleted (look just above) */ /* Not sure this can every really happen. Warn if it does. */ _mesa_problem(NULL, "referencing deleted array object"); *ptr = NULL; } else { arrayObj->RefCount++; #if 0 printf("ArrayObj %p %d INCR to %d\n", (void *) arrayObj, arrayObj->Name, arrayObj->RefCount); #endif *ptr = arrayObj; } _glthread_UNLOCK_MUTEX(arrayObj->Mutex); } }
void _mesa_unref_sync_object(GLcontext *ctx, struct gl_sync_object *syncObj) { _glthread_LOCK_MUTEX(ctx->Shared->Mutex); syncObj->RefCount--; if (syncObj->RefCount == 0) { remove_from_list(& syncObj->link); _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); ctx->Driver.DeleteSyncObject(ctx, syncObj); } else { _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); } }
/** * Reference (or unreference) a texture object. * If '*ptr', decrement *ptr's refcount (and delete if it becomes zero). * If 'tex' is non-null, increment its refcount. * This is normally only called from the _mesa_reference_texobj() macro * when there's a real pointer change. */ void _mesa_reference_texobj_(struct gl_texture_object **ptr, struct gl_texture_object *tex) { assert(ptr); if (*ptr) { /* Unreference the old texture */ GLboolean deleteFlag = GL_FALSE; struct gl_texture_object *oldTex = *ptr; ASSERT(valid_texture_object(oldTex)); (void) valid_texture_object; /* silence warning in release builds */ _glthread_LOCK_MUTEX(oldTex->Mutex); ASSERT(oldTex->RefCount > 0); oldTex->RefCount--; deleteFlag = (oldTex->RefCount == 0); _glthread_UNLOCK_MUTEX(oldTex->Mutex); if (deleteFlag) { GET_CURRENT_CONTEXT(ctx); if (ctx) ctx->Driver.DeleteTexture(ctx, oldTex); else _mesa_problem(NULL, "Unable to delete texture, no context"); } *ptr = NULL; } assert(!*ptr); if (tex) { /* reference new texture */ ASSERT(valid_texture_object(tex)); _glthread_LOCK_MUTEX(tex->Mutex); if (tex->RefCount == 0) { /* this texture's being deleted (look just above) */ /* Not sure this can every really happen. Warn if it does. */ _mesa_problem(NULL, "referencing deleted texture object"); *ptr = NULL; } else { tex->RefCount++; *ptr = tex; } _glthread_UNLOCK_MUTEX(tex->Mutex); } }
/** * Get the key of the "first" entry in the hash table. * This is used in the course of deleting all display lists when * a context is destroyed. * \param table - the hash table * \return key for the "first" entry in the hash table. */ GLuint _mesa_HashFirstEntry(struct _mesa_HashTable *table) { GLuint pos; assert(table); _glthread_LOCK_MUTEX(table->Mutex); for (pos=0; pos < TABLE_SIZE; pos++) { if (table->Table[pos]) { _glthread_UNLOCK_MUTEX(table->Mutex); return table->Table[pos]->Key; } } _glthread_UNLOCK_MUTEX(table->Mutex); return 0; }
void GLAPIENTRY _mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers) { GET_CURRENT_CONTEXT(ctx); GLuint first; GLint i; ASSERT_OUTSIDE_BEGIN_END(ctx); if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGenRenderbuffersEXT(n)"); return; } if (!renderbuffers) return; first = _mesa_HashFindFreeKeyBlock(ctx->Shared->RenderBuffers, n); for (i = 0; i < n; i++) { GLuint name = first + i; renderbuffers[i] = name; /* insert dummy placeholder into hash table */ _glthread_LOCK_MUTEX(ctx->Shared->Mutex); _mesa_HashInsert(ctx->Shared->RenderBuffers, name, &DummyRenderbuffer); _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); } }
/* * Allocate and initialize a new MemRange struct. * Try to allocate it from the pool of free MemRange nodes rather than malloc. */ static tdfxMemRange * NewRangeNode(tdfxContextPtr fxMesa, FxU32 start, FxU32 end) { struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared; struct tdfxSharedState *shared = (struct tdfxSharedState *) mesaShared->DriverData; tdfxMemRange *result; _glthread_LOCK_MUTEX(mesaShared->Mutex); if (shared && shared->tmPool) { result = shared->tmPool; shared->tmPool = shared->tmPool->next; } else { result = MALLOC(sizeof(tdfxMemRange)); } _glthread_UNLOCK_MUTEX(mesaShared->Mutex); if (!result) { /*fprintf(stderr, "fxDriver: out of memory!\n");*/ return NULL; } result->startAddr = start; result->endAddr = end; result->next = NULL; return result; }
void _mesa_ref_sync_object(GLcontext *ctx, struct gl_sync_object *syncObj) { _glthread_LOCK_MUTEX(ctx->Shared->Mutex); syncObj->RefCount++; _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); }
/** * Remove the given texture object from the texture object pool. * Do not deallocate the texture object though. */ void _mesa_remove_texture_object( GLcontext *ctx, struct gl_texture_object *texObj ) { struct gl_texture_object *tprev, *tcurr; _glthread_LOCK_MUTEX(ctx->Shared->Mutex); /* unlink from the linked list */ tprev = NULL; tcurr = ctx->Shared->TexObjectList; while (tcurr) { if (tcurr == texObj) { if (tprev) { tprev->Next = texObj->Next; } else { ctx->Shared->TexObjectList = texObj->Next; } break; } tprev = tcurr; tcurr = tcurr->Next; } _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); if (texObj->Name > 0) { /* remove from hash table */ _mesa_HashRemove(ctx->Shared->TexObjects, texObj->Name); } }
void * _mesa_exec_malloc(GLuint size) { struct mem_block *block = NULL; void *addr = NULL; _glthread_LOCK_MUTEX(exec_mutex); if (!init_heap()) goto bail; if (exec_heap) { size = (size + 31) & ~31; block = mmAllocMem( exec_heap, size, 32, 0 ); } if (block) addr = exec_mem + block->ofs; else printf("_mesa_exec_malloc failed\n"); bail: _glthread_UNLOCK_MUTEX(exec_mutex); return addr; }
/* Combine */ prev->endAddr = range->endAddr; prev->next = range->next; DELETE_RANGE_NODE(shared, range); } else { prev->next = range; } } else { shared->tmFree[tmu] = range; } } #if 0 /* NOT USED */ static void RemoveRange(tdfxContextPtr fxMesa, FxU32 tmu, tdfxMemRange *range) { struct gl_shared_state *mesaShared = fxMesa->glCtx->Shared; _glthread_LOCK_MUTEX(mesaShared->Mutex); RemoveRange_NoLock(fxMesa, tmu, range); _glthread_UNLOCK_MUTEX(mesaShared->Mutex); }
/** * Generate texture names. * * \param n number of texture names to be generated. * \param textures an array in which will hold the generated texture names. * * \sa glGenTextures(). * * While holding the GenTexturesLock lock, calls _mesa_HashFindFreeKeyBlock() * to find a block of free texture IDs which are stored in \p textures. * Corresponding empty texture objects are also generated. */ void GLAPIENTRY _mesa_GenTextures( GLsizei n, GLuint *textures ) { GET_CURRENT_CONTEXT(ctx); GLuint first; GLint i; ASSERT_OUTSIDE_BEGIN_END(ctx); if (n < 0) { _mesa_error( ctx, GL_INVALID_VALUE, "glGenTextures" ); return; } if (!textures) return; /* * This must be atomic (generation and allocation of texture IDs) */ _glthread_LOCK_MUTEX(GenTexturesLock); first = _mesa_HashFindFreeKeyBlock(ctx->Shared->TexObjects, n); /* Allocate new, empty texture objects */ for (i = 0; i < n; i++) { struct gl_texture_object *texObj; GLuint name = first + i; GLenum target = 0; texObj = (*ctx->Driver.NewTextureObject)( ctx, name, target); if (!texObj) { _glthread_UNLOCK_MUTEX(GenTexturesLock); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTextures"); return; } /* insert into hash table */ _glthread_LOCK_MUTEX(ctx->Shared->Mutex); _mesa_HashInsert(ctx->Shared->TexObjects, texObj->Name, texObj); _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); textures[i] = name; } _glthread_UNLOCK_MUTEX(GenTexturesLock); }
/** * 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); FLUSH_VERTICES(ctx, 0); if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)"); return; } _glthread_LOCK_MUTEX(ctx->Shared->Mutex); for (i = 0; i < n; i++) { struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]); if (bufObj) { GLuint j; ASSERT(bufObj->Name == ids[i] || bufObj == &DummyBufferObject); if (_mesa_bufferobj_mapped(bufObj)) { /* if mapped, unmap it now */ ctx->Driver.UnmapBuffer(ctx, bufObj); bufObj->AccessFlags = default_access_mode(ctx); bufObj->Pointer = NULL; } /* unbind any vertex pointers bound to this buffer */ for (j = 0; j < Elements(ctx->Array.VertexAttrib); j++) { unbind(ctx, &ctx->Array.VertexAttrib[j].BufferObj, bufObj); } if (ctx->Array.ElementArrayBufferObj == bufObj) { _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 ); } /* The ID is immediately freed for re-use */ _mesa_HashRemove(ctx->Shared->BufferObjects, ids[i]); /* Make sure we do not run into the classic ABA problem on bind. * We don't want to allow re-binding a buffer object that's been * "deleted" by glDeleteBuffers(). * * The explicit rebinding to the default object in the current context * prevents the above in the current context, but another context * sharing the same objects might suffer from this problem. * The alternative would be to do the hash lookup in any case on bind * which would introduce more runtime overhead than this. */ bufObj->DeletePending = GL_TRUE; _mesa_reference_buffer_object(ctx, &bufObj, NULL); } } _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); }
/** * Delete a set of array objects. * * \param n Number of array objects to delete. * \param ids Array of \c n array object IDs. */ void GLAPIENTRY _mesa_DeleteVertexArraysAPPLE(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, "glDeleteVertexArrayAPPLE(n)"); return; } _glthread_LOCK_MUTEX(ctx->Shared->Mutex); for (i = 0; i < n; i++) { struct gl_array_object *obj = lookup_arrayobj(ctx, ids[i]); if ( obj != NULL ) { ASSERT( obj->Name == ids[i] ); /* If the array object is currently bound, the spec says "the binding * for that object reverts to zero and the default vertex array * becomes current." */ if ( obj == ctx->Array.ArrayObj ) { CALL_BindVertexArrayAPPLE( ctx->Exec, (0) ); } #if FEATURE_ARB_vertex_buffer_object /* Unbind any buffer objects that might be bound to arrays in * this array object. */ unbind_buffer_object( ctx, obj->Vertex.BufferObj ); unbind_buffer_object( ctx, obj->Normal.BufferObj ); unbind_buffer_object( ctx, obj->Color.BufferObj ); unbind_buffer_object( ctx, obj->SecondaryColor.BufferObj ); unbind_buffer_object( ctx, obj->FogCoord.BufferObj ); unbind_buffer_object( ctx, obj->Index.BufferObj ); for (i = 0; i < MAX_TEXTURE_UNITS; i++) { unbind_buffer_object( ctx, obj->TexCoord[i].BufferObj ); } unbind_buffer_object( ctx, obj->EdgeFlag.BufferObj ); for (i = 0; i < VERT_ATTRIB_MAX; i++) { unbind_buffer_object( ctx, obj->VertexAttrib[i].BufferObj ); } #endif /* The ID is immediately freed for re-use */ _mesa_remove_array_object(ctx, obj); ctx->Driver.DeleteArrayObject(ctx, obj); } } _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); }
/** * Insert a key/pointer pair into the hash table. * If an entry with this key already exists we'll replace the existing entry. * * \param table the hash table. * \param key the key (not zero). * \param data pointer to user data. */ void _mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data) { /* search for existing entry with this key */ GLuint pos; struct HashEntry *entry; assert(table); assert(key); _glthread_LOCK_MUTEX(table->Mutex); if (key > table->MaxKey) table->MaxKey = key; pos = HASH_FUNC(key); /* check if replacing an existing entry with same key */ for (entry = table->Table[pos]; entry; entry = entry->Next) { if (entry->Key == key) { /* replace entry's data */ #if 0 /* not sure this check is always valid */ if (entry->Data) { _mesa_problem(NULL, "Memory leak detected in _mesa_HashInsert"); } #endif entry->Data = data; _glthread_UNLOCK_MUTEX(table->Mutex); return; } } /* alloc and insert new table entry */ entry = MALLOC_STRUCT(HashEntry); if (entry) { entry->Key = key; entry->Data = data; entry->Next = table->Table[pos]; table->Table[pos] = entry; } _glthread_UNLOCK_MUTEX(table->Mutex); }
static void finish_or_flush( struct gl_context *ctx ) { const XMesaContext xmesa = XMESA_CONTEXT(ctx); if (xmesa) { _glthread_LOCK_MUTEX(_xmesa_lock); XSync( xmesa->display, False ); _glthread_UNLOCK_MUTEX(_xmesa_lock); } }
/** * Lookup an entry in the hash table. * * \param table the hash table. * \param key the key. * * \return pointer to user's data or NULL if key not in table */ void * _mesa_HashLookup(struct _mesa_HashTable *table, GLuint key) { void *res; assert(table); _glthread_LOCK_MUTEX(table->Mutex); res = _mesa_HashLookup_unlocked(table, key); _glthread_UNLOCK_MUTEX(table->Mutex); return res; }
void _mesa_unref_sync_object(struct gl_context *ctx, struct gl_sync_object *syncObj) { struct set_entry *entry; _glthread_LOCK_MUTEX(ctx->Shared->Mutex); syncObj->RefCount--; if (syncObj->RefCount == 0) { entry = _mesa_set_search(ctx->Shared->SyncObjects, _mesa_hash_pointer(syncObj), syncObj); assert (entry != NULL); _mesa_set_remove(ctx->Shared->SyncObjects, entry); _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); ctx->Driver.DeleteSyncObject(ctx, syncObj); } else { _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); } }
/** * Generate a set of unique array object IDs and store them in \c arrays. * * \param n Number of IDs to generate. * \param arrays Array of \c n locations to store the IDs. */ void GLAPIENTRY _mesa_GenVertexArraysAPPLE(GLsizei n, GLuint *arrays) { GET_CURRENT_CONTEXT(ctx); GLuint first; GLint i; ASSERT_OUTSIDE_BEGIN_END(ctx); if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGenVertexArraysAPPLE"); return; } if (!arrays) { return; } /* * This must be atomic (generation and allocation of array object IDs) */ _glthread_LOCK_MUTEX(ctx->Shared->Mutex); first = _mesa_HashFindFreeKeyBlock(ctx->Shared->ArrayObjects, n); /* Allocate new, empty array objects and return identifiers */ for (i = 0; i < n; i++) { struct gl_array_object *obj; GLuint name = first + i; obj = (*ctx->Driver.NewArrayObject)( ctx, name ); if (!obj) { _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenVertexArraysAPPLE"); return; } _mesa_save_array_object(ctx, obj); arrays[i] = first + i; } _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); }
/** * Generate a set of unique buffer object IDs and store them in \c buffer. * * \param n Number of IDs to generate. * \param buffer Array of \c n locations to store the IDs. */ void GLAPIENTRY _mesa_GenBuffersARB(GLsizei n, GLuint *buffer) { GET_CURRENT_CONTEXT(ctx); GLuint first; GLint i; ASSERT_OUTSIDE_BEGIN_END(ctx); if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB"); return; } if (!buffer) { return; } /* * This must be atomic (generation and allocation of buffer object IDs) */ _glthread_LOCK_MUTEX(ctx->Shared->Mutex); first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n); /* Allocate new, empty buffer objects and return identifiers */ for (i = 0; i < n; i++) { struct gl_buffer_object *bufObj; GLuint name = first + i; GLenum target = 0; bufObj = ctx->Driver.NewBufferObject( ctx, name, target ); if (!bufObj) { _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenBuffersARB"); return; } _mesa_HashInsert(ctx->Shared->BufferObjects, first + i, bufObj); buffer[i] = first + i; } _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); }
/** * Remove an entry from the hash table. * * \param table the hash table. * \param key key of entry to remove. * * While holding the hash table's lock, searches the entry with the matching * key and unlinks it. */ void _mesa_HashRemove(struct _mesa_HashTable *table, GLuint key) { GLuint pos; struct HashEntry *entry, *prev; assert(table); assert(key); /* have to check this outside of mutex lock */ if (table->InDeleteAll) { _mesa_problem(NULL, "_mesa_HashRemove illegally called from " "_mesa_HashDeleteAll callback function"); return; } _glthread_LOCK_MUTEX(table->Mutex); pos = HASH_FUNC(key); prev = NULL; entry = table->Table[pos]; while (entry) { if (entry->Key == key) { /* found it! */ if (prev) { prev->Next = entry->Next; } else { table->Table[pos] = entry->Next; } free(entry); _glthread_UNLOCK_MUTEX(table->Mutex); return; } prev = entry; entry = entry->Next; } _glthread_UNLOCK_MUTEX(table->Mutex); }
/** * 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; if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) _mesa_debug(ctx, "glDeleteTextures %d\n", n); FLUSH_VERTICES(ctx, 0); /* too complex */ if (!textures) return; for (i = 0; i < n; i++) { if (textures[i] > 0) { struct gl_texture_object *delObj = _mesa_lookup_texture(ctx, textures[i]); if (delObj) { _mesa_lock_texture(ctx, delObj); /* Check if texture is bound to any framebuffer objects. * If so, unbind. * See section 4.4.2.3 of GL_EXT_framebuffer_object. */ unbind_texobj_from_fbo(ctx, delObj); /* Check if this texture is currently bound to any texture units. * If so, unbind it. */ unbind_texobj_from_texunits(ctx, delObj); _mesa_unlock_texture(ctx, delObj); 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); /* Unreference the texobj. If refcount hits zero, the texture * will be deleted. */ _mesa_reference_texobj(&delObj, NULL); } } } }
/** * Determine if ID is the name of a buffer object. * * \param id ID of the potential buffer object. * \return \c GL_TRUE if \c id is the name of a buffer object, * \c GL_FALSE otherwise. */ GLboolean GLAPIENTRY _mesa_IsBufferARB(GLuint id) { struct gl_buffer_object *bufObj; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); _glthread_LOCK_MUTEX(ctx->Shared->Mutex); bufObj = _mesa_lookup_bufferobj(ctx, id); _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); return bufObj ? GL_TRUE : GL_FALSE; }
/** * Returns an error code specified by GL_ARB_robustness, or GL_NO_ERROR. * \return current context status */ GLenum GLAPIENTRY _mesa_GetGraphicsResetStatusARB( void ) { GET_CURRENT_CONTEXT(ctx); GLenum status = GL_NO_ERROR; /* The ARB_robustness specification says: * * "If the reset notification behavior is NO_RESET_NOTIFICATION_ARB, * then the implementation will never deliver notification of reset * events, and GetGraphicsResetStatusARB will always return NO_ERROR." */ if (ctx->Const.ResetStrategy == GL_NO_RESET_NOTIFICATION_ARB) { if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glGetGraphicsResetStatusARB always returns GL_NO_ERROR " "because reset notifictation was not requested at context " "creation.\n"); return GL_NO_ERROR; } if (ctx->Driver.GetGraphicsResetStatus) { /* Query the reset status of this context from the driver core. */ status = ctx->Driver.GetGraphicsResetStatus(ctx); _glthread_LOCK_MUTEX(ctx->Shared->Mutex); /* If this context has not been affected by a GPU reset, check to see if * some other context in the share group has been affected by a reset. * If another context saw a reset but this context did not, assume that * this context was not guilty. */ if (status != GL_NO_ERROR) { ctx->Shared->ShareGroupReset = true; } else if (ctx->Shared->ShareGroupReset && !ctx->ShareGroupReset) { status = GL_INNOCENT_CONTEXT_RESET_ARB; } ctx->ShareGroupReset = ctx->Shared->ShareGroupReset; _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); } if (!ctx->Driver.GetGraphicsResetStatus && (MESA_VERBOSE & VERBOSE_API)) _mesa_debug(ctx, "glGetGraphicsResetStatusARB always returns GL_NO_ERROR " "because the driver doesn't track reset status.\n"); return status; }