/** * 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); }
/** * Specify a buffer object to receive vertex shader results, plus the * offset in the buffer to start placing results. * This function is part of GL_EXT_transform_feedback, but not GL3. */ void GLAPIENTRY _mesa_BindBufferOffsetEXT(GLenum target, GLuint index, GLuint buffer, GLintptr offset) { struct gl_transform_feedback_object *obj; struct gl_buffer_object *bufObj; GET_CURRENT_CONTEXT(ctx); GLsizeiptr size; if (target != GL_TRANSFORM_FEEDBACK_BUFFER) { _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferOffsetEXT(target)"); return; } obj = ctx->TransformFeedback.CurrentObject; if (obj->Active) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBindBufferOffsetEXT(transform feedback active)"); return; } if (index >= ctx->Const.MaxTransformFeedbackBuffers) { _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferOffsetEXT(index=%d)", index); return; } if (offset & 0x3) { /* must be multiple of four */ _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferOffsetEXT(offset=%d)", (int) offset); return; } if (buffer == 0) { bufObj = ctx->Shared->NullBufferObj; } else { bufObj = _mesa_lookup_bufferobj(ctx, buffer); } if (!bufObj) { _mesa_error(ctx, GL_INVALID_OPERATION, "glBindBufferOffsetEXT(invalid buffer=%u)", buffer); return; } /* default size is the buffer size rounded down to nearest * multiple of four. */ size = (bufObj->Size - offset) & ~0x3; bind_buffer_range(ctx, index, bufObj, offset, size); }
/** * 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; }
/** * 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 ); }
/** * Wrapper around _mesa_lookup_bufferobj that throws GL_INVALID_VALUE if id * is not in the hash table. Specialised version for the * transform-feedback-related functions. After calling _mesa_error, it * returns NULL. */ static struct gl_buffer_object * lookup_transform_feedback_bufferobj_err(struct gl_context *ctx, GLuint buffer, const char* func) { struct gl_buffer_object *bufObj; /* OpenGL 4.5 core profile, 13.2, pdf page 444: buffer must be zero or the * name of an existing buffer object. */ if (buffer == 0) { bufObj = ctx->Shared->NullBufferObj; } else { bufObj = _mesa_lookup_bufferobj(ctx, buffer); if (!bufObj) { _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid buffer=%u)", func, buffer); } } return bufObj; }
/** * 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++) { struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]); if (bufObj) { struct gl_array_object *arrayObj = ctx->Array.ArrayObj; GLuint j; ASSERT(bufObj->Name == ids[i]); if (bufObj->Pointer) { /* if mapped, unmap it now */ ctx->Driver.UnmapBuffer(ctx, 0, bufObj); bufObj->AccessFlags = DEFAULT_ACCESS; bufObj->Pointer = NULL; } /* unbind any vertex pointers bound to this buffer */ unbind(ctx, &arrayObj->Vertex.BufferObj, bufObj); unbind(ctx, &arrayObj->Weight.BufferObj, bufObj); unbind(ctx, &arrayObj->Normal.BufferObj, bufObj); unbind(ctx, &arrayObj->Color.BufferObj, bufObj); unbind(ctx, &arrayObj->SecondaryColor.BufferObj, bufObj); unbind(ctx, &arrayObj->FogCoord.BufferObj, bufObj); unbind(ctx, &arrayObj->Index.BufferObj, bufObj); unbind(ctx, &arrayObj->EdgeFlag.BufferObj, bufObj); for (j = 0; j < Elements(arrayObj->TexCoord); j++) { unbind(ctx, &arrayObj->TexCoord[j].BufferObj, bufObj); } for (j = 0; j < Elements(arrayObj->VertexAttrib); j++) { unbind(ctx, &arrayObj->VertexAttrib[j].BufferObj, bufObj); } 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 ); } /* unbind any pixel pack/unpack pointers bound to this buffer */ 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_HashRemove(ctx->Shared->BufferObjects, bufObj->Name); _mesa_reference_buffer_object(ctx, &bufObj, NULL); } } _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); }
/** * Bind the specified target to buffer for the specified context. */ static void bind_buffer_object(GLcontext *ctx, GLenum target, GLuint buffer) { struct gl_buffer_object *oldBufObj; struct gl_buffer_object *newBufObj = NULL; struct gl_buffer_object **bindTarget = NULL; switch (target) { case GL_ARRAY_BUFFER_ARB: bindTarget = &ctx->Array.ArrayBufferObj; break; case GL_ELEMENT_ARRAY_BUFFER_ARB: bindTarget = &ctx->Array.ElementArrayBufferObj; break; case GL_PIXEL_PACK_BUFFER_EXT: bindTarget = &ctx->Pack.BufferObj; break; case GL_PIXEL_UNPACK_BUFFER_EXT: bindTarget = &ctx->Unpack.BufferObj; break; case GL_COPY_READ_BUFFER: if (ctx->Extensions.ARB_copy_buffer) { bindTarget = &ctx->CopyReadBuffer; } break; case GL_COPY_WRITE_BUFFER: if (ctx->Extensions.ARB_copy_buffer) { bindTarget = &ctx->CopyWriteBuffer; } break; default: ; /* no-op / we'll hit the follow error test next */ } if (!bindTarget) { _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)"); return; } /* Get pointer to old buffer object (to be unbound) */ oldBufObj = get_buffer(ctx, target); 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->Shared->NullBufferObj; } else { /* non-default buffer object */ newBufObj = _mesa_lookup_bufferobj(ctx, buffer); if (!newBufObj) { /* if this is a new buffer object id, 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 ); }