/** * 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; }
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); } }
/** * 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; }
static void finish_or_flush( GLcontext *ctx ) { #ifdef XFree86Server /* NOT_NEEDED */ #else const XMesaContext xmesa = XMESA_CONTEXT(ctx); if (xmesa) { _glthread_LOCK_MUTEX(_xmesa_lock); XSync( xmesa->display, False ); _glthread_UNLOCK_MUTEX(_xmesa_lock); } #endif }
void _mesa_exec_free(void *addr) { _glthread_LOCK_MUTEX(exec_mutex); if (exec_heap) { struct mem_block *block = mmFindBlock(exec_heap, (unsigned char *)addr - exec_mem); if (block) mmFreeMem(block); } _glthread_UNLOCK_MUTEX(exec_mutex); }
/** * Add the given texture object to the texture object pool. */ void _mesa_save_texture_object( GLcontext *ctx, struct gl_texture_object *texObj ) { /* insert into linked list */ _glthread_LOCK_MUTEX(ctx->Shared->Mutex); texObj->Next = ctx->Shared->TexObjectList; ctx->Shared->TexObjectList = texObj; _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); if (texObj->Name > 0) { /* insert into hash table */ _mesa_HashInsert(ctx->Shared->TexObjects, texObj->Name, texObj); } }
/** * 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) { GET_CURRENT_CONTEXT(ctx); if (ctx) oldRb->Delete(ctx, oldRb); else _mesa_problem(NULL, "Unable to delete renderbuffer, no context"); } *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; } }
/** * 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 = _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 an array object. * * \param id ID of the potential array object. * \return \c GL_TRUE if \c id is the name of a array object, * \c GL_FALSE otherwise. */ GLboolean GLAPIENTRY _mesa_IsVertexArrayAPPLE( GLuint id ) { struct gl_array_object * obj; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); if (id == 0) return GL_FALSE; _glthread_LOCK_MUTEX(ctx->Shared->Mutex); obj = lookup_arrayobj(ctx, id); _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); return (obj != NULL) ? GL_TRUE : GL_FALSE; }
GLsync GLAPIENTRY _mesa_FenceSync(GLenum condition, GLbitfield flags) { GET_CURRENT_CONTEXT(ctx); struct gl_sync_object *syncObj; ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); if (condition != GL_SYNC_GPU_COMMANDS_COMPLETE) { _mesa_error(ctx, GL_INVALID_ENUM, "glFenceSync(condition=0x%x)", condition); return 0; } if (flags != 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glFenceSync(flags=0x%x)", condition); return 0; } syncObj = ctx->Driver.NewSyncObject(ctx, GL_SYNC_FENCE); if (syncObj != NULL) { syncObj->Type = GL_SYNC_FENCE; /* The name is not currently used, and it is never visible to * applications. If sync support is extended to provide support for * NV_fence, this field will be used. We'll also need to add an object * ID hashtable. */ syncObj->Name = 1; syncObj->RefCount = 1; syncObj->DeletePending = GL_FALSE; syncObj->SyncCondition = condition; syncObj->Flags = flags; syncObj->StatusFlag = 0; ctx->Driver.FenceSync(ctx, syncObj, condition, flags); _glthread_LOCK_MUTEX(ctx->Shared->Mutex); _mesa_set_add(ctx->Shared->SyncObjects, _mesa_hash_pointer(syncObj), syncObj); _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); return (GLsync) syncObj; } return NULL; }
/** * Return the size of the window (or pixmap) that corresponds to the * given XMesaBuffer. * \param width returns width in pixels * \param height returns height in pixels */ void xmesa_get_window_size(XMesaDisplay *dpy, XMesaBuffer b, GLuint *width, GLuint *height) { Status stat; _glthread_LOCK_MUTEX(_xmesa_lock); XSync(b->xm_visual->display, 0); /* added for Chromium */ stat = get_drawable_size(dpy, b->frontxrb->pixmap, width, height); _glthread_UNLOCK_MUTEX(_xmesa_lock); if (!stat) { /* probably querying a window that's recently been destroyed */ _mesa_warning(NULL, "XGetGeometry failed!\n"); *width = *height = 1; } }
/** * Calls all the various one-time-init functions in Mesa. * * While holding a global mutex lock, calls several initialization functions, * and sets the glapi callbacks if the \c MESA_DEBUG environment variable is * defined. * * \sa _math_init(). */ static void one_time_init( GLcontext *ctx ) { static GLboolean alreadyCalled = GL_FALSE; (void) ctx; _glthread_LOCK_MUTEX(OneTimeLock); if (!alreadyCalled) { GLuint i; /* do some implementation tests */ assert( sizeof(GLbyte) == 1 ); assert( sizeof(GLubyte) == 1 ); assert( sizeof(GLshort) == 2 ); assert( sizeof(GLushort) == 2 ); assert( sizeof(GLint) == 4 ); assert( sizeof(GLuint) == 4 ); _mesa_get_cpu_features(); _mesa_init_remap_table(); _mesa_init_sqrt_table(); for (i = 0; i < 256; i++) { _mesa_ubyte_to_float_color_tab[i] = (float) i / 255.0F; } if (_mesa_getenv("MESA_DEBUG")) { _glapi_noop_enable_warnings(GL_TRUE); _glapi_set_warning_func( (_glapi_warning_func) _mesa_warning ); } else { _glapi_noop_enable_warnings(GL_FALSE); } #if defined(DEBUG) && defined(__DATE__) && defined(__TIME__) _mesa_debug(ctx, "Mesa %s DEBUG build %s %s\n", MESA_VERSION_STRING, __DATE__, __TIME__); #endif alreadyCalled = GL_TRUE; } _glthread_UNLOCK_MUTEX(OneTimeLock); dummy_enum_func(); }
/** * 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(). * * 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; if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) _mesa_debug(ctx, "glGenTextures %d\n", n); 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(ctx->Shared->Mutex); 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(ctx->Shared->Mutex); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTextures"); return; } /* insert into hash table */ _mesa_HashInsert(ctx->Shared->TexObjects, texObj->Name, texObj); textures[i] = name; } _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); }
/** * Set *ptr to point to fb, with refcounting and locking. */ void _mesa_reference_framebuffer(struct gl_framebuffer **ptr, struct gl_framebuffer *fb) { assert(ptr); if (*ptr == fb) { /* no change */ return; } if (*ptr) { _mesa_unreference_framebuffer(ptr); } assert(!*ptr); assert(fb); _glthread_LOCK_MUTEX(fb->Mutex); fb->RefCount++; _glthread_UNLOCK_MUTEX(fb->Mutex); *ptr = fb; }
/** * Fallback for ctx->Driver.FramebufferRenderbuffer() * Attach a renderbuffer object to a framebuffer object. */ void _mesa_framebuffer_renderbuffer(GLcontext *ctx, struct gl_framebuffer *fb, GLenum attachment, struct gl_renderbuffer *rb) { struct gl_renderbuffer_attachment *att; _glthread_LOCK_MUTEX(fb->Mutex); att = _mesa_get_attachment(ctx, fb, attachment); ASSERT(att); if (rb) { _mesa_set_renderbuffer_attachment(ctx, att, rb); } else { _mesa_remove_attachment(ctx, att); } _glthread_UNLOCK_MUTEX(fb->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); }
/** * Undo/remove a reference to a framebuffer object. * Decrement the framebuffer object's reference count and delete it when * the refcount hits zero. * Note: we pass the address of a pointer and set it to NULL. */ void _mesa_unreference_framebuffer(struct gl_framebuffer **fb) { assert(fb); if (*fb) { GLboolean deleteFlag = GL_FALSE; _glthread_LOCK_MUTEX((*fb)->Mutex); ASSERT((*fb)->RefCount > 0); (*fb)->RefCount--; deleteFlag = ((*fb)->RefCount == 0); _glthread_UNLOCK_MUTEX((*fb)->Mutex); if (deleteFlag) (*fb)->Delete(*fb); *fb = NULL; } }
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 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); }
/** * 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); }
/** * Walk over all entries in a hash table, calling callback function for each. * Note: we use a separate mutex in this function to avoid a recursive * locking deadlock (in case the callback calls _mesa_HashRemove()) and to * prevent multiple threads/contexts from getting tangled up. * A lock-less version of this function could be used when the table will * not be modified. * \param table the hash table to walk * \param callback the callback function * \param userData arbitrary pointer to pass along to the callback * (this is typically a struct gl_context pointer) */ void _mesa_HashWalk(const struct _mesa_HashTable *table, void (*callback)(GLuint key, void *data, void *userData), void *userData) { /* cast-away const */ struct _mesa_HashTable *table2 = (struct _mesa_HashTable *) table; GLuint pos; ASSERT(table); ASSERT(callback); _glthread_LOCK_MUTEX(table2->WalkMutex); for (pos = 0; pos < TABLE_SIZE; pos++) { struct HashEntry *entry, *next; for (entry = table->Table[pos]; entry; entry = next) { /* save 'next' pointer now in case the callback deletes the entry */ next = entry->Next; callback(entry->Key, entry->Data, userData); } } _glthread_UNLOCK_MUTEX(table2->WalkMutex); }
/** * 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 all entries in a hash table, but don't delete the table itself. * Invoke the given callback function for each table entry. * * \param table the hash table to delete * \param callback the callback function * \param userData arbitrary pointer to pass along to the callback * (this is typically a struct gl_context pointer) */ void _mesa_HashDeleteAll(struct _mesa_HashTable *table, void (*callback)(GLuint key, void *data, void *userData), void *userData) { GLuint pos; ASSERT(table); ASSERT(callback); _glthread_LOCK_MUTEX(table->Mutex); table->InDeleteAll = GL_TRUE; for (pos = 0; pos < TABLE_SIZE; pos++) { struct HashEntry *entry, *next; for (entry = table->Table[pos]; entry; entry = next) { callback(entry->Key, entry->Data, userData); next = entry->Next; free(entry); } table->Table[pos] = NULL; } table->InDeleteAll = GL_FALSE; _glthread_UNLOCK_MUTEX(table->Mutex); }
/** * Generate texture names. * * \param n number of texture names to be generated. * \param texName 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 texName. * Corresponding empty texture objects are also generated. */ void GLAPIENTRY _mesa_GenTextures( GLsizei n, GLuint *texName ) { 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 (!texName) 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) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTextures"); return; } _mesa_save_texture_object(ctx, texObj); texName[i] = name; } _glthread_UNLOCK_MUTEX(GenTexturesLock); }
static void clear_color( GLcontext *ctx, const GLfloat color[4] ) { if (ctx->DrawBuffer->Name == 0) { const XMesaContext xmesa = XMESA_CONTEXT(ctx); XMesaBuffer xmbuf = XMESA_BUFFER(ctx->DrawBuffer); CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[0], color[0]); CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[1], color[1]); CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[2], color[2]); CLAMPED_FLOAT_TO_UBYTE(xmesa->clearcolor[3], color[3]); xmesa->clearpixel = xmesa_color_to_pixel( ctx, xmesa->clearcolor[0], xmesa->clearcolor[1], xmesa->clearcolor[2], xmesa->clearcolor[3], xmesa->xm_visual->undithered_pf ); _glthread_LOCK_MUTEX(_xmesa_lock); XMesaSetForeground( xmesa->display, xmbuf->cleargc, xmesa->clearpixel ); _glthread_UNLOCK_MUTEX(_xmesa_lock); } }
/** * 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 (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glGenBuffers(%d)\n", n); 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); /* Insert the ID and pointer to dummy buffer object into hash table */ for (i = 0; i < n; i++) { _mesa_HashInsert(ctx->Shared->BufferObjects, first + i, &DummyBufferObject); buffer[i] = first + i; } _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); }
/** * 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); struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); struct gl_texture_object *newTexObj = NULL; GLint targetIndex; 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); targetIndex = target_enum_to_index(ctx, target); if (targetIndex < 0) { _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target)"); return; } assert(targetIndex < NUM_TEXTURE_TARGETS); /* * Get pointer to new texture object (newTexObj) */ if (texName == 0) { /* Use a default texture object */ newTexObj = ctx->Shared->DefaultTex[targetIndex]; } else { /* non-default texture object */ newTexObj = _mesa_lookup_texture(ctx, texName); if (newTexObj) { /* error checking */ if (newTexObj->Target != 0 && newTexObj->Target != target) { /* the named texture object's target doesn't match the given target */ _mesa_error( ctx, GL_INVALID_OPERATION, "glBindTexture(target mismatch)" ); return; } if (newTexObj->Target == 0) { finish_texture_init(ctx, target, newTexObj); } } else { if (ctx->API == API_OPENGL_CORE) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBindTexture"); return; } /* 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; } assert(valid_texture_object(newTexObj)); /* Check if this texture is only used by this context and is already bound. * If so, just return. */ { GLboolean early_out; _glthread_LOCK_MUTEX(ctx->Shared->Mutex); early_out = ((ctx->Shared->RefCount == 1) && (newTexObj == texUnit->CurrentTex[targetIndex])); _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); if (early_out) { return; } } /* flush before changing binding */ FLUSH_VERTICES(ctx, _NEW_TEXTURE); /* Do the actual binding. The refcount on the previously bound * texture object will be decremented. It'll be deleted if the * count hits zero. */ _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex], newTexObj); ASSERT(texUnit->CurrentTex[targetIndex]); /* Pass BindTexture call to device driver */ if (ctx->Driver.BindTexture) ctx->Driver.BindTexture(ctx, target, newTexObj); }
/** * Free the data associated with the given context. * * But doesn't free the GLcontext struct itself. * * \sa _mesa_initialize_context() and init_attrib_groups(). */ void _mesa_free_context_data( GLcontext *ctx ) { GLint RefCount; if (!_mesa_get_current_context()){ /* No current context, but we may need one in order to delete * texture objs, etc. So temporarily bind the context now. */ _mesa_make_current(ctx, NULL, NULL); } /* unreference WinSysDraw/Read buffers */ _mesa_reference_framebuffer(&ctx->WinSysDrawBuffer, NULL); _mesa_reference_framebuffer(&ctx->WinSysReadBuffer, NULL); _mesa_reference_framebuffer(&ctx->DrawBuffer, NULL); _mesa_reference_framebuffer(&ctx->ReadBuffer, NULL); _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current, NULL); _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current, NULL); _mesa_reference_vertprog(ctx, &ctx->VertexProgram._TnlProgram, NULL); _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL); _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, NULL); _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._TexEnvProgram, NULL); _mesa_free_attrib_data(ctx); _mesa_free_lighting_data( ctx ); _mesa_free_eval_data( ctx ); _mesa_free_texture_data( ctx ); _mesa_free_matrix_data( ctx ); _mesa_free_viewport_data( ctx ); _mesa_free_colortables_data( ctx ); _mesa_free_program_data(ctx); _mesa_free_shader_state(ctx); _mesa_free_queryobj_data(ctx); #if FEATURE_ARB_sync _mesa_free_sync_data(ctx); #endif _mesa_free_varray_data(ctx); _mesa_delete_array_object(ctx, ctx->Array.DefaultArrayObj); #if FEATURE_ARB_pixel_buffer_object _mesa_reference_buffer_object(ctx, &ctx->Pack.BufferObj, NULL); _mesa_reference_buffer_object(ctx, &ctx->Unpack.BufferObj, NULL); #endif #if FEATURE_ARB_vertex_buffer_object _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL); _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, NULL); #endif /* free dispatch tables */ _mesa_free(ctx->Exec); _mesa_free(ctx->Save); /* Shared context state (display lists, textures, etc) */ _glthread_LOCK_MUTEX(ctx->Shared->Mutex); RefCount = --ctx->Shared->RefCount; _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); assert(RefCount >= 0); if (RefCount == 0) { /* free shared state */ _mesa_free_shared_state( ctx, ctx->Shared ); } /* needs to be after freeing shared state */ _mesa_free_display_list_data(ctx); if (ctx->Extensions.String) _mesa_free((void *) ctx->Extensions.String); /* unbind the context if it's currently bound */ if (ctx == _mesa_get_current_context()) { _mesa_make_current(NULL, NULL, NULL); } }
/** * Initialize a GLcontext struct (rendering context). * * This includes allocating all the other structs and arrays which hang off of * the context by pointers. * Note that the driver needs to pass in its dd_function_table here since * we need to at least call driverFunctions->NewTextureObject to create the * default texture objects. * * Called by _mesa_create_context(). * * Performs the imports and exports callback tables initialization, and * miscellaneous one-time initializations. If no shared context is supplied one * is allocated, and increase its reference count. Setups the GL API dispatch * tables. Initialize the TNL module. Sets the maximum Z buffer depth. * Finally queries the \c MESA_DEBUG and \c MESA_VERBOSE environment variables * for debug flags. * * \param ctx the context to initialize * \param visual describes the visual attributes for this context * \param share_list points to context to share textures, display lists, * etc with, or NULL * \param driverFunctions table of device driver functions for this context * to use * \param driverContext pointer to driver-specific context data */ GLboolean _mesa_initialize_context(GLcontext *ctx, const GLvisual *visual, GLcontext *share_list, const struct dd_function_table *driverFunctions, void *driverContext) { struct gl_shared_state *shared; /*ASSERT(driverContext);*/ assert(driverFunctions->NewTextureObject); assert(driverFunctions->FreeTexImageData); /* misc one-time initializations */ one_time_init(ctx); ctx->Visual = *visual; ctx->DrawBuffer = NULL; ctx->ReadBuffer = NULL; ctx->WinSysDrawBuffer = NULL; ctx->WinSysReadBuffer = NULL; /* Plug in driver functions and context pointer here. * This is important because when we call alloc_shared_state() below * we'll call ctx->Driver.NewTextureObject() to create the default * textures. */ ctx->Driver = *driverFunctions; ctx->DriverCtx = driverContext; if (share_list) { /* share state with another context */ shared = share_list->Shared; } else { /* allocate new, unshared state */ shared = _mesa_alloc_shared_state(ctx); if (!shared) return GL_FALSE; } _glthread_LOCK_MUTEX(shared->Mutex); ctx->Shared = shared; shared->RefCount++; _glthread_UNLOCK_MUTEX(shared->Mutex); if (!init_attrib_groups( ctx )) { _mesa_free_shared_state(ctx, ctx->Shared); return GL_FALSE; } /* setup the API dispatch tables */ ctx->Exec = alloc_dispatch_table(); ctx->Save = alloc_dispatch_table(); if (!ctx->Exec || !ctx->Save) { _mesa_free_shared_state(ctx, ctx->Shared); if (ctx->Exec) _mesa_free(ctx->Exec); return GL_FALSE; } #if FEATURE_dispatch _mesa_init_exec_table(ctx->Exec); #endif ctx->CurrentDispatch = ctx->Exec; #if FEATURE_dlist _mesa_init_save_table(ctx->Save); _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); #endif /* Neutral tnl module stuff */ _mesa_init_exec_vtxfmt( ctx ); ctx->TnlModule.Current = NULL; ctx->TnlModule.SwapCount = 0; ctx->FragmentProgram._MaintainTexEnvProgram = (_mesa_getenv("MESA_TEX_PROG") != NULL); ctx->VertexProgram._MaintainTnlProgram = (_mesa_getenv("MESA_TNL_PROG") != NULL); if (ctx->VertexProgram._MaintainTnlProgram) { /* this is required... */ ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE; } #ifdef FEATURE_extra_context_init _mesa_initialize_context_extra(ctx); #endif ctx->FirstTimeCurrent = GL_TRUE; return GL_TRUE; }