📄 bufferobj.c
字号:
/*
* Mesa 3-D graphics library
* Version: 6.3
*
* Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* \file bufferobj.c
* \brief Functions for the GL_ARB_vertex_buffer_object extension.
* \author Brian Paul, Ian Romanick
*/
#include "glheader.h"
#include "hash.h"
#include "imports.h"
#include "image.h"
#include "context.h"
#include "bufferobj.h"
/**
* Get the buffer object bound to the specified target in a GL context.
*
* \param ctx GL context
* \param target Buffer object target to be retrieved. Currently this must
* be either \c GL_ARRAY_BUFFER or \c GL_ELEMENT_ARRAY_BUFFER.
* \param str Name of caller for logging errors.
* \return A pointer to the buffer object bound to \c target in the
* specified context or \c NULL if \c target is invalid or no
* buffer object is bound.
*/
static INLINE struct gl_buffer_object *
buffer_object_get_target( GLcontext *ctx, GLenum target, const char * str )
{
struct gl_buffer_object * bufObj = NULL;
switch (target) {
case GL_ARRAY_BUFFER_ARB:
bufObj = ctx->Array.ArrayBufferObj;
break;
case GL_ELEMENT_ARRAY_BUFFER_ARB:
bufObj = ctx->Array.ElementArrayBufferObj;
break;
case GL_PIXEL_PACK_BUFFER_EXT:
bufObj = ctx->Pack.BufferObj;
break;
case GL_PIXEL_UNPACK_BUFFER_EXT:
bufObj = ctx->Unpack.BufferObj;
break;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "gl%s(target)", str);
return NULL;
}
if (bufObj->Name == 0)
return NULL;
return bufObj;
}
/**
* Tests the subdata range parameters and sets the GL error code for
* \c glBufferSubDataARB and \c glGetBufferSubDataARB.
*
* \param ctx GL context.
* \param target Buffer object target on which to operate.
* \param offset Offset of the first byte of the subdata range.
* \param size Size, in bytes, of the subdata range.
* \param str Name of caller for logging errors.
* \return A pointer to the buffer object bound to \c target in the
* specified context or \c NULL if any of the parameter or state
* conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB
* are invalid.
*
* \sa glBufferSubDataARB, glGetBufferSubDataARB
*/
static struct gl_buffer_object *
buffer_object_subdata_range_good( GLcontext * ctx, GLenum target,
GLintptrARB offset, GLsizeiptrARB size,
const char * str )
{
struct gl_buffer_object *bufObj;
if (size < 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", str);
return NULL;
}
if (offset < 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", str);
return NULL;
}
bufObj = buffer_object_get_target( ctx, target, str );
if (!bufObj || bufObj->Name == 0) {
return NULL;
}
if ((GLuint) (offset + size) > bufObj->Size) {
_mesa_error(ctx, GL_INVALID_VALUE,
"%s(size + offset > buffer size)", str);
return NULL;
}
if (bufObj->Pointer) {
/* Buffer is currently mapped */
_mesa_error(ctx, GL_INVALID_OPERATION, "%s", str);
return NULL;
}
return bufObj;
}
/**
* Allocate and initialize a new buffer object.
*
* This function is intended to be called via
* \c dd_function_table::NewBufferObject.
*/
struct gl_buffer_object *
_mesa_new_buffer_object( GLcontext *ctx, GLuint name, GLenum target )
{
struct gl_buffer_object *obj;
(void) ctx;
obj = MALLOC_STRUCT(gl_buffer_object);
_mesa_initialize_buffer_object(obj, name, target);
return obj;
}
/**
* Delete a buffer object.
*
* This function is intended to be called via
* \c dd_function_table::DeleteBuffer.
*/
void
_mesa_delete_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj )
{
(void) ctx;
if (bufObj->Data)
_mesa_free(bufObj->Data);
_mesa_free(bufObj);
}
/**
* Initialize a buffer object to default values.
*/
void
_mesa_initialize_buffer_object( struct gl_buffer_object *obj,
GLuint name, GLenum target )
{
(void) target;
_mesa_bzero(obj, sizeof(struct gl_buffer_object));
obj->RefCount = 1;
obj->Name = name;
obj->Usage = GL_STATIC_DRAW_ARB;
obj->Access = GL_READ_WRITE_ARB;
}
/**
* 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);
}
}
/**
* Remove the given buffer object from the buffer object pool.
* Do not deallocate the buffer object though.
*/
void
_mesa_remove_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj )
{
if (bufObj->Name > 0) {
/* remove from hash table */
_mesa_HashRemove(ctx->Shared->BufferObjects, bufObj->Name);
}
}
/**
* Allocate space for and store data in a buffer object. Any data that was
* previously stored in the buffer object is lost. If \c data is \c NULL,
* memory will be allocated, but no copy will occur.
*
* This function is intended to be called via
* \c dd_function_table::BufferData. This function need not set GL error
* codes. The input parameters will have been tested before calling.
*
* \param ctx GL context.
* \param target Buffer object target on which to operate.
* \param size Size, in bytes, of the new data store.
* \param data Pointer to the data to store in the buffer object. This
* pointer may be \c NULL.
* \param usage Hints about how the data will be used.
* \param bufObj Object to be used.
*
* \sa glBufferDataARB, dd_function_table::BufferData.
*/
void
_mesa_buffer_data( GLcontext *ctx, GLenum target, GLsizeiptrARB size,
const GLvoid * data, GLenum usage,
struct gl_buffer_object * bufObj )
{
void * new_data;
(void) ctx; (void) target;
new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size );
if (new_data) {
bufObj->Data = (GLubyte *) new_data;
bufObj->Size = size;
bufObj->Usage = usage;
if (data) {
_mesa_memcpy( bufObj->Data, data, size );
}
}
}
/**
* Replace data in a subrange of buffer object. If the data range
* specified by \c size + \c offset extends beyond the end of the buffer or
* if \c data is \c NULL, no copy is performed.
*
* This function is intended to be called by
* \c dd_function_table::BufferSubData. This function need not set GL error
* codes. The input parameters will have been tested before calling.
*
* \param ctx GL context.
* \param target Buffer object target on which to operate.
* \param offset Offset of the first byte to be modified.
* \param size Size, in bytes, of the data range.
* \param data Pointer to the data to store in the buffer object.
* \param bufObj Object to be used.
*
* \sa glBufferSubDataARB, dd_function_table::BufferSubData.
*/
void
_mesa_buffer_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset,
GLsizeiptrARB size, const GLvoid * data,
struct gl_buffer_object * bufObj )
{
(void) ctx; (void) target;
if (bufObj->Data && ((GLuint) (size + offset) <= bufObj->Size)) {
_mesa_memcpy( (GLubyte *) bufObj->Data + offset, data, size );
}
}
/**
* Retrieve data from a subrange of buffer object. If the data range
* specified by \c size + \c offset extends beyond the end of the buffer or
* if \c data is \c NULL, no copy is performed.
*
* This function is intended to be called by
* \c dd_function_table::BufferGetSubData. This function need not set GL error
* codes. The input parameters will have been tested before calling.
*
* \param ctx GL context.
* \param target Buffer object target on which to operate.
* \param offset Offset of the first byte to be modified.
* \param size Size, in bytes, of the data range.
* \param data Pointer to the data to store in the buffer object.
* \param bufObj Object to be used.
*
* \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
*/
void
_mesa_buffer_get_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset,
GLsizeiptrARB size, GLvoid * data,
struct gl_buffer_object * bufObj )
{
(void) ctx; (void) target;
if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) {
_mesa_memcpy( data, (GLubyte *) bufObj->Data + offset, size );
}
}
/**
* Fallback function called via ctx->Driver.MapBuffer().
* Hardware drivers that really implement buffer objects should never use
* function.
*
* The input parameters will have been already tested for errors.
*
* \param ctx GL context.
* \param target Buffer object target on which to operate.
* \param access Information about how the buffer will be accessed.
* \param bufObj Object to be mapped.
* \return A pointer to the object's internal data store that can be accessed
* by the processor
*
* \sa glMapBufferARB, dd_function_table::MapBuffer
*/
void *
_mesa_buffer_map( GLcontext *ctx, GLenum target, GLenum access,
struct gl_buffer_object *bufObj )
{
(void) ctx;
(void) target;
(void) access;
ASSERT(!bufObj->OnCard);
/* Just return a direct pointer to the data */
if (bufObj->Pointer) {
/* already mapped! */
return NULL;
}
bufObj->Pointer = bufObj->Data;
return bufObj->Pointer;
}
/**
* Fallback function called via ctx->Driver.MapBuffer().
* Hardware drivers that really implement buffer objects should never use
* function.
*
* The input parameters will have been already tested for errors.
*
* \sa glUnmapBufferARB, dd_function_table::UnmapBuffer
*/
GLboolean
_mesa_buffer_unmap( GLcontext *ctx, GLenum target,
struct gl_buffer_object *bufObj )
{
(void) ctx;
(void) target;
ASSERT(!bufObj->OnCard);
/* XXX we might assert here that bufObj->Pointer is non-null */
bufObj->Pointer = NULL;
return GL_TRUE;
}
/**
* Initialize the state associated with buffer objects
*/
void
_mesa_init_buffer_objects( GLcontext *ctx )
{
GLuint i;
/* Allocate the default buffer object and set refcount so high that
* it never gets deleted.
*/
ctx->Array.NullBufferObj = _mesa_new_buffer_object(ctx, 0, 0);
if (ctx->Array.NullBufferObj)
ctx->Array.NullBufferObj->RefCount = 1000;
ctx->Array.ArrayBufferObj = ctx->Array.NullBufferObj;
ctx->Array.ElementArrayBufferObj = ctx->Array.NullBufferObj;
/* Vertex array buffers */
ctx->Array.Vertex.BufferObj = ctx->Array.NullBufferObj;
ctx->Array.Normal.BufferObj = ctx->Array.NullBufferObj;
ctx->Array.Color.BufferObj = ctx->Array.NullBufferObj;
ctx->Array.SecondaryColor.BufferObj = ctx->Array.NullBufferObj;
ctx->Array.FogCoord.BufferObj = ctx->Array.NullBufferObj;
ctx->Array.Index.BufferObj = ctx->Array.NullBufferObj;
for (i = 0; i < MAX_TEXTURE_UNITS; i++) {
ctx->Array.TexCoord[i].BufferObj = ctx->Array.NullBufferObj;
}
ctx->Array.EdgeFlag.BufferObj = ctx->Array.NullBufferObj;
for (i = 0; i < VERT_ATTRIB_MAX; i++) {
ctx->Array.VertexAttrib[i].BufferObj = ctx->Array.NullBufferObj;
}
}
/**
* When we're about to read pixel data out of a PBO (via glDrawPixels,
* glTexImage, etc) or write data into a PBO (via glReadPixels,
* glGetTexImage, etc) we call this function to check that we're not
* going to read out of bounds.
*
* XXX This would also be a convenient time to check that the PBO isn't
* currently mapped. Whoever calls this function should check for that.
* Remember, we can't use a PBO when it's mapped!
*
* \param width width of image to read/write
* \param height height of image to read/write
* \param depth depth of image to read/write
* \param format format of image to read/write
* \param type datatype of image to read/write
* \param ptr the user-provided pointer/offset
* \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would
* go out of bounds.
*/
GLboolean
_mesa_validate_pbo_access(GLuint dimensions,
const struct gl_pixelstore_attrib *pack,
GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLenum type, const GLvoid *ptr)
{
GLvoid *start, *end;
ASSERT(pack->BufferObj->Name != 0);
if (pack->BufferObj->Size == 0)
/* no buffer! */
return GL_FALSE;
/* get address of first pixel we'll read */
start = _mesa_image_address(dimensions, pack, ptr, width, height,
format, type, 0, 0, 0);
/* get address just past the last pixel we'll read */
end = _mesa_image_address(dimensions, pack, ptr, width, height,
format, type, depth-1, height-1, width);
if ((const GLubyte *) start > (const GLubyte *)(uintptr_t) pack->BufferObj->Size) {
/* This will catch negative values / wrap-around */
return GL_FALSE;
}
if ((const GLubyte *) end > (const GLubyte *)(uintptr_t) pack->BufferObj->Size) {
/* Image read goes beyond end of buffer */
return GL_FALSE;
}
/* OK! */
return GL_TRUE;
}
/**********************************************************************/
/* API Functions */
/**********************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -