/** * Load/parse/compile a program. * \note Called from the GL API dispatcher. */ void GLAPIENTRY _mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len, const GLubyte *program) { struct gl_program *prog; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (id == 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(id)"); return; } if (len < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(len)"); return; } FLUSH_VERTICES(ctx, _NEW_PROGRAM); prog = _mesa_lookup_program(ctx, id); if (prog && prog->Target != 0 && prog->Target != target) { _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target)"); return; } if ((target == GL_VERTEX_PROGRAM_NV || target == GL_VERTEX_STATE_PROGRAM_NV) && ctx->Extensions.NV_vertex_program) { struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog; if (!vprog || prog == &_mesa_DummyProgram) { vprog = (struct gl_vertex_program *) ctx->Driver.NewProgram(ctx, target, id); if (!vprog) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); return; } _mesa_HashInsert(ctx->Shared->Programs, id, vprog); } _mesa_parse_nv_vertex_program(ctx, target, program, len, vprog); } else if (target == GL_FRAGMENT_PROGRAM_NV && ctx->Extensions.NV_fragment_program) { struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog; if (!fprog || prog == &_mesa_DummyProgram) { fprog = (struct gl_fragment_program *) ctx->Driver.NewProgram(ctx, target, id); if (!fprog) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); return; } _mesa_HashInsert(ctx->Shared->Programs, id, fprog); } _mesa_parse_nv_fragment_program(ctx, target, program, len, fprog); } else { _mesa_error(ctx, GL_INVALID_ENUM, "glLoadProgramNV(target)"); } }
/** * Create new transform feedback objects. Transform feedback objects * encapsulate the state related to transform feedback to allow quickly * switching state (and drawing the results, below). * Part of GL_ARB_transform_feedback2. */ void GLAPIENTRY _mesa_GenTransformFeedbacks(GLsizei n, GLuint *names) { GLuint first; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGenTransformFeedbacks(n < 0)"); return; } if (!names) return; /* we don't need contiguous IDs, but this might be faster */ first = _mesa_HashFindFreeKeyBlock(ctx->TransformFeedback.Objects, n); if (first) { GLsizei i; for (i = 0; i < n; i++) { struct gl_transform_feedback_object *obj = ctx->Driver.NewTransformFeedback(ctx, first + i); if (!obj) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTransformFeedbacks"); return; } names[i] = first + i; _mesa_HashInsert(ctx->TransformFeedback.Objects, first + i, obj); } } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTransformFeedbacks"); } }
static void create_samplers(struct gl_context *ctx, GLsizei count, GLuint *samplers, const char *caller) { GLuint first; GLint i; if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "%s(%d)\n", caller, count); if (count < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(n<0)", caller); return; } if (!samplers) return; first = _mesa_HashFindFreeKeyBlock(ctx->Shared->SamplerObjects, count); /* Insert the ID and pointer to new sampler object into hash table */ for (i = 0; i < count; i++) { struct gl_sampler_object *sampObj = ctx->Driver.NewSamplerObject(ctx, first + i); _mesa_HashInsert(ctx->Shared->SamplerObjects, first + i, sampObj); samplers[i] = first + i; } }
/** * Add the given pipeline object to the pipeline object pool. */ static void save_pipeline_object(struct gl_context *ctx, struct gl_pipeline_object *obj) { if (obj->Name > 0) { _mesa_HashInsert(ctx->Pipeline.Objects, obj->Name, obj); } }
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); } }
/** * Generate a list of new program identifiers. * \note Not compiled into display lists. * \note Called by both glGenProgramsNV and glGenProgramsARB. */ void GLAPIENTRY _mesa_GenPrograms(GLsizei n, GLuint *ids) { GLuint first; GLuint i; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGenPrograms"); return; } if (!ids) return; 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, &_mesa_DummyProgram); } /* Return the program names */ for (i = 0; i < (GLuint) n; i++) { ids[i] = first + i; } }
void GLAPIENTRY _mesa_GenQueriesARB(GLsizei n, GLuint *ids) { GLuint first; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGenQueriesARB(n < 0)"); return; } /* No query objects can be active at this time! */ if (ctx->Query.CurrentOcclusionObject || ctx->Query.CurrentTimerObject) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGenQueriesARB"); return; } first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n); if (first) { GLsizei i; for (i = 0; i < n; i++) { struct gl_query_object *q = ctx->Driver.NewQueryObject(ctx, first + i); if (!q) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB"); return; } ids[i] = first + i; _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q); } } }
void GLAPIENTRY _mesa_GenSamplers(GLsizei count, GLuint *samplers) { GET_CURRENT_CONTEXT(ctx); GLuint first; GLint i; if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glGenSamplers(%d)\n", count); if (count < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGenSamplers"); return; } if (!samplers) return; first = _mesa_HashFindFreeKeyBlock(ctx->Shared->SamplerObjects, count); /* Insert the ID and pointer to new sampler object into hash table */ for (i = 0; i < count; i++) { struct gl_sampler_object *sampObj = ctx->Driver.NewSamplerObject(ctx, first + i); _mesa_HashInsert(ctx->Shared->SamplerObjects, first + i, sampObj); samplers[i] = first + i; } }
/** * Generate a list of new program identifiers. * \note Not compiled into display lists. * \note Called from the GL API dispatcher. */ void _mesa_GenProgramsNV(GLsizei n, GLuint *ids) { GLuint first; GLuint i; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGenProgramsNV"); return; } if (!ids) return; first = _mesa_HashFindFreeKeyBlock(ctx->Shared->VertexPrograms, n); for (i = 0; i < (GLuint) n; i++) { struct vp_program *vprog = CALLOC_STRUCT(vp_program); if (!vprog) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenProgramsNV"); return; } vprog->RefCount = 1; _mesa_HashInsert(ctx->Shared->VertexPrograms, first + i, vprog); } /* Return the program names */ for (i = 0; i < (GLuint) n; i++) { ids[i] = first + i; } }
void GLAPIENTRY _mesa_QueryCounter(GLuint id, GLenum target) { struct gl_query_object *q; GET_CURRENT_CONTEXT(ctx); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id, _mesa_lookup_enum_by_nr(target)); /* error checking */ if (target != GL_TIMESTAMP) { _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)"); return; } if (id == 0) { _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)"); return; } q = _mesa_lookup_query_object(ctx, id); if (!q) { /* XXX the Core profile should throw INVALID_OPERATION here */ /* create new object */ q = ctx->Driver.NewQueryObject(ctx, id); if (!q) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter"); return; } _mesa_HashInsert(ctx->Query.QueryObjects, id, q); } else { if (q->Target && q->Target != GL_TIMESTAMP) { _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id has an invalid target)"); return; } } if (q->Active) { _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)"); return; } q->Target = target; q->Result = 0; q->Ready = GL_FALSE; if (ctx->Driver.QueryCounter) { ctx->Driver.QueryCounter(ctx, q); } else { /* QueryCounter is implemented using EndQuery without BeginQuery * in drivers. This is actually Direct3D and Gallium convention. */ ctx->Driver.EndQuery(ctx, q); } }
/** * Add the given array object to the array object pool. */ static void save_array_object( struct gl_context *ctx, struct gl_array_object *obj ) { if (obj->Name > 0) { /* insert into hash table */ _mesa_HashInsert(ctx->Array.Objects, obj->Name, obj); } }
/** * Add the given buffer object to the buffer object pool. */ void _mesa_save_buffer_object( GLcontext *ctx, struct gl_buffer_object *obj ) { if (obj->Name > 0) { /* insert into hash table */ _mesa_HashInsert(ctx->Shared->BufferObjects, obj->Name, obj); } }
void _mesa_test_hash_functions(void) { int a, b, c; struct _mesa_HashTable *t; t = _mesa_NewHashTable(); _mesa_HashInsert(t, 501, &a); _mesa_HashInsert(t, 10, &c); _mesa_HashInsert(t, 0xfffffff8, &b); /*_mesa_HashPrint(t);*/ assert(_mesa_HashLookup(t,501)); assert(!_mesa_HashLookup(t,1313)); assert(_mesa_HashFindFreeKeyBlock(t, 100)); _mesa_DeleteHashTable(t); test_hash_walking(); }
/** * Load a vertex program. * \note Called from the GL API dispatcher. */ void _mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len, const GLubyte *program) { struct vp_program *vprog; GLboolean newProgram = GL_FALSE; GLubyte *programCopy; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (id == 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(id)"); return; } vprog = (struct vp_program *) _mesa_HashLookup(ctx->Shared->VertexPrograms, id); if (vprog && vprog->Target != 0 && vprog->Target != target) { _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target)"); return; } /* make a copy of the program string so that we can null-terminate it */ /* if we change the parser to stop after <len> characters, instead of */ /* looking for '\0' we can eliminate this. */ programCopy = (GLubyte *) MALLOC(len + 1); if (!programCopy) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); return; } MEMCPY(programCopy, program, len); programCopy[len] = 0; if (!vprog) { newProgram = GL_TRUE; vprog = CALLOC_STRUCT(vp_program); if (!vprog) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV"); return; } } _mesa_parse_program(ctx, target, programCopy, vprog); if (ctx->VertexProgram.ErrorPos == -1) { /* loaded and parsed w/out errors */ if (newProgram) { _mesa_HashInsert(ctx->Shared->VertexPrograms, id, vprog); } vprog->RefCount = 1; vprog->Resident = GL_TRUE; } FREE(programCopy); }
/** * Bind a program (make it current) * \note Called from the GL API dispatcher. */ void _mesa_BindProgramNV(GLenum target, GLuint id) { struct vp_program *vprog; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (target != GL_VERTEX_PROGRAM_NV) { _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV"); return; } if (id == ctx->VertexProgram.CurrentID) return; /* decrement refcount on previously bound vertex program */ if (ctx->VertexProgram.Current) { ctx->VertexProgram.Current->RefCount--; /* and delete if refcount goes below one */ if (ctx->VertexProgram.Current->RefCount <= 0) _mesa_delete_program(ctx, ctx->VertexProgram.CurrentID); } /* NOTE: binding to a non-existant program is not an error. * That's supposed to be caught in glBegin. */ if (id == 0) { /* OK, the null program object */ vprog = NULL; } else { vprog = (struct vp_program *) _mesa_HashLookup(ctx->Shared->VertexPrograms, id); if (!vprog && id > 0){ /* new program ID */ vprog = CALLOC_STRUCT(vp_program); if (!vprog) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV"); return; } vprog->Target = target; vprog->Resident = GL_TRUE; vprog->RefCount = 1; _mesa_HashInsert(ctx->Shared->VertexPrograms, id, vprog); } } ctx->VertexProgram.CurrentID = id; ctx->VertexProgram.Current = vprog; if (vprog) vprog->RefCount++; }
int main(int argc, char *argv[]) { int a, b, c; struct HashTable *t; _mesa_printf("&a = %p\n", &a); _mesa_printf("&b = %p\n", &b); t = _mesa_NewHashTable(); _mesa_HashInsert(t, 501, &a); _mesa_HashInsert(t, 10, &c); _mesa_HashInsert(t, 0xfffffff8, &b); _mesa_HashPrint(t); _mesa_printf("Find 501: %p\n", _mesa_HashLookup(t,501)); _mesa_printf("Find 1313: %p\n", _mesa_HashLookup(t,1313)); _mesa_printf("Find block of 100: %d\n", _mesa_HashFindFreeKeyBlock(t, 100)); _mesa_DeleteHashTable(t); return 0; }
/** * Bind the specified target to buffer for the specified context. * Called by glBindBuffer() and other functions. */ static void bind_buffer_object(struct gl_context *ctx, GLenum target, GLuint buffer) { struct gl_buffer_object *oldBufObj; struct gl_buffer_object *newBufObj = NULL; struct gl_buffer_object **bindTarget = NULL; bindTarget = get_buffer_target(ctx, target); if (!bindTarget) { _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)", target); return; } /* Get pointer to old buffer object (to be unbound) */ oldBufObj = *bindTarget; if (oldBufObj && oldBufObj->Name == buffer && !oldBufObj->DeletePending) 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->Shared->NullBufferObj; } else { /* non-default buffer object */ newBufObj = _mesa_lookup_bufferobj(ctx, buffer); if (!newBufObj || newBufObj == &DummyBufferObject) { /* If this is a new buffer object id, or one which was generated but * never used before, allocate a buffer object now. */ ASSERT(ctx->Driver.NewBufferObject); newBufObj = ctx->Driver.NewBufferObject(ctx, buffer, target); if (!newBufObj) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB"); return; } _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, newBufObj); } } /* bind new buffer */ _mesa_reference_buffer_object(ctx, bindTarget, newBufObj); /* Pass BindBuffer call to device driver */ if (ctx->Driver.BindBuffer) ctx->Driver.BindBuffer( ctx, target, newBufObj ); }
/** * 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); } }
GLuint _mesa_create_program(GLcontext *ctx) { GLuint name; struct gl_shader_program *shProg; name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1); shProg = _mesa_new_shader_program(ctx, name); _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg); assert(shProg->RefCount == 1); return name; }
void GLAPIENTRY _mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer) { struct gl_renderbuffer *newRb; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (target != GL_RENDERBUFFER_EXT) { _mesa_error(ctx, GL_INVALID_ENUM, "glBindRenderbufferEXT(target)"); return; } FLUSH_VERTICES(ctx, _NEW_BUFFERS); /* The above doesn't fully flush the drivers in the way that a * glFlush does, but that is required here: */ if (ctx->Driver.Flush) ctx->Driver.Flush(ctx); if (renderbuffer) { newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer); if (newRb == &DummyRenderbuffer) { /* ID was reserved, but no real renderbuffer object made yet */ newRb = NULL; } if (!newRb) { /* create new renderbuffer object */ newRb = ctx->Driver.NewRenderbuffer(ctx, renderbuffer); if (!newRb) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT"); return; } ASSERT(newRb->AllocStorage); _mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb); newRb->RefCount = 1; /* referenced by hash table */ } } else { newRb = NULL; } ASSERT(newRb != &DummyRenderbuffer); _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb); }
static GLuint create_shader_program(struct gl_context *ctx) { GLuint name; struct gl_shader_program *shProg; name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1); shProg = ctx->Driver.NewShaderProgram(ctx, name); _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg); assert(shProg->RefCount == 1); return name; }
static GLuint create_shader(struct gl_context *ctx, GLenum type) { struct gl_shader *sh; GLuint name; if (!validate_shader_target(ctx, type)) { _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)"); return 0; } name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1); sh = ctx->Driver.NewShader(ctx, name, type); _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh); return name; }
/** * 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); }
static void create_transform_feedbacks(struct gl_context *ctx, GLsizei n, GLuint *ids, bool dsa) { GLuint first; const char* func; if (dsa) func = "glCreateTransformFeedbacks"; else func = "glGenTransformFeedbacks"; if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func); return; } if (!ids) return; /* we don't need contiguous IDs, but this might be faster */ first = _mesa_HashFindFreeKeyBlock(ctx->TransformFeedback.Objects, n); if (first) { GLsizei i; for (i = 0; i < n; i++) { struct gl_transform_feedback_object *obj = ctx->Driver.NewTransformFeedback(ctx, first + i); if (!obj) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); return; } ids[i] = first + i; _mesa_HashInsert(ctx->TransformFeedback.Objects, first + i, obj); if (dsa) { /* this is normally done at bind time in the non-dsa case */ obj->EverBound = GL_TRUE; } } } else { _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); } }
void bmGenBuffers(struct bufmgr *bm, unsigned n, unsigned *buffers, unsigned flags) { LOCK(bm); { unsigned i; unsigned bFlags = (flags) ? flags : DRM_MM_TT | DRM_MM_VRAM | DRM_MM_SYSTEM; for (i = 0; i < n; i++) { drmMMBuf *buf = calloc(sizeof(*buf), 1); BM_CKFATAL(drmMMInitBuffer(bm->driFd, bFlags, 12, buf)); buf->client_priv = ++bm->buf_nr; buffers[i] = buf->client_priv; _mesa_HashInsert(bm->hash, buffers[i], buf); } } UNLOCK(bm); }
/** * 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); }
GLuint _mesa_create_shader(GLcontext *ctx, GLenum type) { struct gl_shader *sh; GLuint name; name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1); switch (type) { case GL_FRAGMENT_SHADER: case GL_VERTEX_SHADER: sh = _mesa_new_shader(ctx, name, type); break; default: _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)"); return 0; } _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh); return name; }
/** * 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); }
/** * Generate a list of new program identifiers. * \note Not compiled into display lists. * \note Called by both glGenProgramsNV and glGenProgramsARB. */ void GLAPIENTRY _mesa_GenPrograms(GLsizei n, GLuint *ids) { GLuint first; GLuint i; GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); if (n < 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glGenPrograms"); return; } if (!ids) return; first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n); for (i = 0; i < (GLuint) n; i++) { const int bytes = MAX2(sizeof(struct vertex_program), sizeof(struct fragment_program)); struct program *prog = (struct program *) _mesa_calloc(bytes); if (!prog) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenPrograms"); return; } prog->RefCount = 1; prog->Id = first + i; _mesa_HashInsert(ctx->Shared->Programs, first + i, prog); } /* Return the program names */ for (i = 0; i < (GLuint) n; i++) { ids[i] = first + i; } }
/** * 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); }