diff options
Diffstat (limited to 'src/mesa/main/bufferobj.c')
-rw-r--r-- | src/mesa/main/bufferobj.c | 235 |
1 files changed, 225 insertions, 10 deletions
diff --git a/src/mesa/main/bufferobj.c b/src/mesa/main/bufferobj.c index 3e011ef5b23..6b228810720 100644 --- a/src/mesa/main/bufferobj.c +++ b/src/mesa/main/bufferobj.c @@ -40,9 +40,9 @@ #ifdef FEATURE_OES_mapbuffer -#define DEFAULT_ACCESS GL_WRITE_ONLY; +#define DEFAULT_ACCESS GL_MAP_WRITE_BIT #else -#define DEFAULT_ACCESS GL_READ_WRITE; +#define DEFAULT_ACCESS (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT) #endif @@ -96,6 +96,24 @@ get_buffer(GLcontext *ctx, GLenum target) /** + * Convert a GLbitfield describing the mapped buffer access flags + * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY. + */ +static GLenum +simplified_access_mode(GLbitfield access) +{ + const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; + if ((access & rwFlags) == rwFlags) + return GL_READ_WRITE; + if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT) + return GL_READ_ONLY; + if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT) + return GL_WRITE_ONLY; + return GL_READ_WRITE; /* this should never happen, but no big deal */ +} + + +/** * Tests the subdata range parameters and sets the GL error code for * \c glBufferSubDataARB and \c glGetBufferSubDataARB. * @@ -271,7 +289,7 @@ _mesa_initialize_buffer_object( struct gl_buffer_object *obj, obj->RefCount = 1; obj->Name = name; obj->Usage = GL_STATIC_DRAW_ARB; - obj->Access = DEFAULT_ACCESS; + obj->AccessFlags = DEFAULT_ACCESS; } @@ -410,6 +428,43 @@ _mesa_buffer_map( GLcontext *ctx, GLenum target, GLenum access, /** + * Default fallback for \c dd_function_table::MapBufferRange(). + * Called via glMapBufferRange(). + */ +void * +_mesa_buffer_map_range( GLcontext *ctx, GLenum target, GLintptr offset, + GLsizeiptr length, GLbitfield access, + struct gl_buffer_object *bufObj ) +{ + (void) ctx; + (void) target; + (void) access; + (void) length; + assert(!bufObj->Pointer); + /* Just return a direct pointer to the data */ + return bufObj->Data + offset; +} + + +/** + * Default fallback for \c dd_function_table::FlushMappedBufferRange(). + * Called via glFlushMappedBufferRange(). + */ +void +_mesa_buffer_flush_mapped_range( GLcontext *ctx, GLenum target, + GLintptr offset, GLsizeiptr length, + struct gl_buffer_object *obj ) +{ + (void) ctx; + (void) target; + (void) offset; + (void) length; + (void) obj; + /* no-op */ +} + + +/** * Default callback for \c dd_function_table::MapBuffer(). * * The input parameters will have been already tested for errors. @@ -845,7 +900,7 @@ _mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids) if (bufObj->Pointer) { /* if mapped, unmap it now */ ctx->Driver.UnmapBuffer(ctx, 0, bufObj); - bufObj->Access = DEFAULT_ACCESS; + bufObj->AccessFlags = DEFAULT_ACCESS; bufObj->Pointer = NULL; } @@ -1004,7 +1059,7 @@ _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size, if (bufObj->Pointer) { /* Unmap the existing buffer. We'll replace it now. Not an error. */ ctx->Driver.UnmapBuffer(ctx, target, bufObj); - bufObj->Access = DEFAULT_ACCESS; + bufObj->AccessFlags = DEFAULT_ACCESS; bufObj->Pointer = NULL; } @@ -1071,13 +1126,18 @@ _mesa_MapBufferARB(GLenum target, GLenum access) { GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object * bufObj; + GLbitfield accessFlags; ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); switch (access) { case GL_READ_ONLY_ARB: + accessFlags = GL_MAP_READ_BIT; + break; case GL_WRITE_ONLY_ARB: + accessFlags = GL_MAP_WRITE_BIT; + break; case GL_READ_WRITE_ARB: - /* OK */ + accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; break; default: _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)"); @@ -1104,7 +1164,10 @@ _mesa_MapBufferARB(GLenum target, GLenum access) _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(access)"); } - bufObj->Access = access; + bufObj->AccessFlags = accessFlags; + bufObj->Offset = 0; + bufObj->Length = bufObj->Size; + if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB) bufObj->Written = GL_TRUE; @@ -1146,7 +1209,7 @@ _mesa_UnmapBufferARB(GLenum target) } #ifdef VBO_DEBUG - if (bufObj->Access == GL_WRITE_ONLY_ARB) { + if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) { GLuint i, unchanged = 0; GLubyte *b = (GLubyte *) bufObj->Pointer; GLint pos = -1; @@ -1166,8 +1229,10 @@ _mesa_UnmapBufferARB(GLenum target) #endif status = ctx->Driver.UnmapBuffer( ctx, target, bufObj ); - bufObj->Access = DEFAULT_ACCESS; + bufObj->AccessFlags = DEFAULT_ACCESS; bufObj->Pointer = NULL; + bufObj->Offset = 0; + bufObj->Length = 0; return status; } @@ -1198,7 +1263,7 @@ _mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params) *params = bufObj->Usage; break; case GL_BUFFER_ACCESS_ARB: - *params = bufObj->Access; + *params = simplified_access_mode(bufObj->AccessFlags); break; case GL_BUFFER_MAPPED_ARB: *params = (bufObj->Pointer != NULL); @@ -1315,3 +1380,153 @@ _mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size); } + +/** + * See GL_ARB_map_buffer_range spec + */ +void * GLAPIENTRY +_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, + GLbitfield access) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); + + if (!ctx->Extensions.ARB_map_buffer_range) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapBufferRange(extension not supported)"); + return NULL; + } + + if (offset < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glMapBufferRange(offset = %ld)", offset); + return NULL; + } + + if (length < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glMapBufferRange(length = %ld)", length); + return NULL; + } + + if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapBufferRange(access indicates neither read or write)"); + return NULL; + } + + if (access & GL_MAP_READ_BIT) { + if ((access & GL_MAP_INVALIDATE_RANGE_BIT) || + (access & GL_MAP_INVALIDATE_BUFFER_BIT) || + (access & GL_MAP_UNSYNCHRONIZED_BIT)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapBufferRange(invalid access flags)"); + return NULL; + } + } + + if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) && + ((access & GL_MAP_WRITE_BIT) == 0)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapBufferRange(invalid access flags)"); + return NULL; + } + + bufObj = get_buffer(ctx, target); + if (!bufObj || bufObj->Name == 0) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glMapBufferRange(target = 0x%x)", target); + return NULL; + } + + if (offset + length > bufObj->Size) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glMapBufferRange(offset + length > size)"); + return NULL; + } + + if (bufObj->Pointer) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapBufferRange(buffer already mapped)"); + return NULL; + } + + ASSERT(ctx->Driver.MapBufferRange); + bufObj->Pointer = ctx->Driver.MapBufferRange(ctx, target, offset, length, + access, bufObj); + + bufObj->Offset = offset; + bufObj->Length = length; + bufObj->AccessFlags = access; + + return bufObj->Pointer; +} + + +/** + * See GL_ARB_map_buffer_range spec + */ +void GLAPIENTRY +_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_buffer_object *bufObj; + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (!ctx->Extensions.ARB_map_buffer_range) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapBufferRange(extension not supported)"); + return; + } + + if (offset < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glMapBufferRange(offset = %ld)", offset); + return; + } + + if (length < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glMapBufferRange(length = %ld)", length); + return; + } + + bufObj = get_buffer(ctx, target); + if (!bufObj) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glMapBufferRange(target = 0x%x)", target); + return; + } + + if (bufObj->Name == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapBufferRange(current buffer is 0)"); + return; + } + + if (!bufObj->Pointer) { + /* buffer is not mapped */ + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapBufferRange(buffer is not mapped)"); + return; + } + + if ((bufObj->AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)"); + return; + } + + if (offset + length > bufObj->Length) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glMapBufferRange(offset %ld + length %ld > mapped length %ld)", + offset, length, bufObj->Length); + return; + } + + ASSERT(bufObj->AccessFlags & GL_MAP_WRITE_BIT); + + if (ctx->Driver.FlushMappedBufferRange) + ctx->Driver.FlushMappedBufferRange(ctx, target, offset, length, bufObj); +} |