summaryrefslogtreecommitdiffstats
path: root/src/mesa/main/bufferobj.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/main/bufferobj.c')
-rw-r--r--src/mesa/main/bufferobj.c274
1 files changed, 242 insertions, 32 deletions
diff --git a/src/mesa/main/bufferobj.c b/src/mesa/main/bufferobj.c
index c8d160baa9a..a49da3d3b58 100644
--- a/src/mesa/main/bufferobj.c
+++ b/src/mesa/main/bufferobj.c
@@ -1,9 +1,9 @@
/*
* Mesa 3-D graphics library
- * Version: 7.5
+ * Version: 7.6
*
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
- * Copyright (C) 1999-2009 VMware, Inc. All Rights Reserved.
+ * Copyright (C) 2009 VMware, Inc. 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"),
@@ -39,6 +39,11 @@
#include "bufferobj.h"
+/* Debug flags */
+/*#define VBO_DEBUG*/
+/*#define BOUNDS_CHECK*/
+
+
#ifdef FEATURE_OES_mapbuffer
#define DEFAULT_ACCESS GL_WRITE_ONLY;
#else
@@ -73,6 +78,16 @@ get_buffer(GLcontext *ctx, GLenum target)
case GL_PIXEL_UNPACK_BUFFER_EXT:
bufObj = ctx->Unpack.BufferObj;
break;
+ case GL_COPY_READ_BUFFER:
+ if (ctx->Extensions.ARB_copy_buffer) {
+ bufObj = ctx->CopyReadBuffer;
+ }
+ break;
+ case GL_COPY_WRITE_BUFFER:
+ if (ctx->Extensions.ARB_copy_buffer) {
+ bufObj = ctx->CopyWriteBuffer;
+ }
+ break;
default:
/* error must be recorded by caller */
return NULL;
@@ -194,7 +209,7 @@ _mesa_reference_buffer_object(GLcontext *ctx,
return;
if (*ptr) {
- /* Unreference the old texture */
+ /* Unreference the old buffer */
GLboolean deleteFlag = GL_FALSE;
struct gl_buffer_object *oldObj = *ptr;
@@ -227,7 +242,7 @@ _mesa_reference_buffer_object(GLcontext *ctx,
ASSERT(!*ptr);
if (bufObj) {
- /* reference new texture */
+ /* reference new buffer */
/*_glthread_LOCK_MUTEX(tex->Mutex);*/
if (bufObj->RefCount == 0) {
/* this buffer's being deleted (look just above) */
@@ -389,7 +404,6 @@ _mesa_buffer_map( GLcontext *ctx, GLenum target, GLenum access,
(void) ctx;
(void) target;
(void) access;
- ASSERT(!bufObj->OnCard);
/* Just return a direct pointer to the data */
if (bufObj->Pointer) {
/* already mapped! */
@@ -413,7 +427,6 @@ _mesa_buffer_unmap( GLcontext *ctx, GLenum target,
{
(void) ctx;
(void) target;
- ASSERT(!bufObj->OnCard);
/* XXX we might assert here that bufObj->Pointer is non-null */
bufObj->Pointer = NULL;
return GL_TRUE;
@@ -421,21 +434,47 @@ _mesa_buffer_unmap( GLcontext *ctx, GLenum target,
/**
+ * Default fallback for \c dd_function_table::CopyBufferSubData().
+ * Called via glCopyBuffserSubData().
+ */
+void
+_mesa_copy_buffer_subdata(GLcontext *ctx,
+ struct gl_buffer_object *src,
+ struct gl_buffer_object *dst,
+ GLintptr readOffset, GLintptr writeOffset,
+ GLsizeiptr size)
+{
+ GLubyte *srcPtr, *dstPtr;
+
+ /* buffer should not already be mapped */
+ assert(!src->Pointer);
+ assert(!dst->Pointer);
+
+ srcPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_READ_BUFFER,
+ GL_READ_ONLY, src);
+ dstPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_WRITE_BUFFER,
+ GL_WRITE_ONLY, dst);
+
+ if (srcPtr && dstPtr)
+ _mesa_memcpy(dstPtr + writeOffset, srcPtr + readOffset, size);
+
+ ctx->Driver.UnmapBuffer(ctx, GL_COPY_READ_BUFFER, src);
+ ctx->Driver.UnmapBuffer(ctx, GL_COPY_WRITE_BUFFER, dst);
+}
+
+
+
+/**
* Initialize the state associated with buffer objects
*/
void
_mesa_init_buffer_objects( GLcontext *ctx )
{
- /* Allocate the default buffer object and set refcount so high that
- * it never gets deleted.
- * XXX with recent/improved refcounting this may not longer be needed.
- */
- ctx->Array.NullBufferObj = _mesa_new_buffer_object(ctx, 0, 0);
- if (ctx->Array.NullBufferObj)
- ctx->Array.NullBufferObj->RefCount = 1000;
+ ctx->Array.ArrayBufferObj = ctx->Shared->NullBufferObj;
+ ctx->Array.ElementArrayBufferObj = ctx->Shared->NullBufferObj;
- ctx->Array.ArrayBufferObj = ctx->Array.NullBufferObj;
- ctx->Array.ElementArrayBufferObj = ctx->Array.NullBufferObj;
+ ctx->CopyReadBuffer = ctx->Shared->NullBufferObj;
+ ctx->CopyWriteBuffer = ctx->Shared->NullBufferObj;
}
@@ -462,8 +501,22 @@ bind_buffer_object(GLcontext *ctx, GLenum target, GLuint buffer)
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:
- _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target)");
+ ; /* no-op / we'll hit the follow error test next */
+ }
+
+ if (!bindTarget) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)");
return;
}
@@ -479,7 +532,7 @@ bind_buffer_object(GLcontext *ctx, GLenum target, GLuint buffer)
/* The spec says there's not a buffer object named 0, but we use
* one internally because it simplifies things.
*/
- newBufObj = ctx->Array.NullBufferObj;
+ newBufObj = ctx->Shared->NullBufferObj;
}
else {
/* non-default buffer object */
@@ -500,7 +553,7 @@ bind_buffer_object(GLcontext *ctx, GLenum target, GLuint buffer)
_mesa_reference_buffer_object(ctx, bindTarget, newBufObj);
/* Pass BindBuffer call to device driver */
- if (ctx->Driver.BindBuffer && newBufObj)
+ if (ctx->Driver.BindBuffer)
ctx->Driver.BindBuffer( ctx, target, newBufObj );
}
@@ -746,7 +799,7 @@ unbind(GLcontext *ctx,
struct gl_buffer_object *obj)
{
if (*ptr == obj) {
- _mesa_reference_buffer_object(ctx, ptr, ctx->Array.NullBufferObj);
+ _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj);
}
}
@@ -789,6 +842,7 @@ _mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids)
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]);
@@ -801,18 +855,19 @@ _mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids)
}
/* unbind any vertex pointers bound to this buffer */
- unbind(ctx, &ctx->Array.ArrayObj->Vertex.BufferObj, bufObj);
- unbind(ctx, &ctx->Array.ArrayObj->Normal.BufferObj, bufObj);
- unbind(ctx, &ctx->Array.ArrayObj->Color.BufferObj, bufObj);
- unbind(ctx, &ctx->Array.ArrayObj->SecondaryColor.BufferObj, bufObj);
- unbind(ctx, &ctx->Array.ArrayObj->FogCoord.BufferObj, bufObj);
- unbind(ctx, &ctx->Array.ArrayObj->Index.BufferObj, bufObj);
- unbind(ctx, &ctx->Array.ArrayObj->EdgeFlag.BufferObj, bufObj);
- for (j = 0; j < MAX_TEXTURE_COORD_UNITS; j++) {
- unbind(ctx, &ctx->Array.ArrayObj->TexCoord[j].BufferObj, bufObj);
+ 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 < VERT_ATTRIB_MAX; j++) {
- unbind(ctx, &ctx->Array.ArrayObj->VertexAttrib[j].BufferObj, bufObj);
+ for (j = 0; j < Elements(arrayObj->VertexAttrib); j++) {
+ unbind(ctx, &arrayObj->VertexAttrib[j].BufferObj, bufObj);
}
if (ctx->Array.ArrayBufferObj == bufObj) {
@@ -947,7 +1002,7 @@ _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
return;
}
if (bufObj->Name == 0) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB" );
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB(buffer 0)" );
return;
}
@@ -958,8 +1013,20 @@ _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size,
bufObj->Pointer = NULL;
}
+ FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT);
+
ASSERT(ctx->Driver.BufferData);
+ bufObj->Written = GL_TRUE;
+
+#ifdef VBO_DEBUG
+ _mesa_printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n",
+ bufObj->Name, size, data, usage);
+#endif
+
+#ifdef BOUNDS_CHECK
+ size += 100;
+#endif
/* Give the buffer object to the driver! <data> may be null! */
ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj );
}
@@ -980,6 +1047,8 @@ _mesa_BufferSubDataARB(GLenum target, GLintptrARB offset,
return;
}
+ bufObj->Written = GL_TRUE;
+
ASSERT(ctx->Driver.BufferSubData);
ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj );
}
@@ -1029,7 +1098,7 @@ _mesa_MapBufferARB(GLenum target, GLenum access)
return NULL;
}
if (bufObj->Name == 0) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB" );
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(buffer 0)" );
return NULL;
}
if (bufObj->Pointer) {
@@ -1044,6 +1113,30 @@ _mesa_MapBufferARB(GLenum target, GLenum access)
}
bufObj->Access = access;
+ if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB)
+ bufObj->Written = GL_TRUE;
+
+#ifdef VBO_DEBUG
+ _mesa_printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n",
+ bufObj->Name, bufObj->Size, access);
+ if (access == GL_WRITE_ONLY_ARB) {
+ GLuint i;
+ GLubyte *b = (GLubyte *) bufObj->Pointer;
+ for (i = 0; i < bufObj->Size; i++)
+ b[i] = i & 0xff;
+ }
+#endif
+
+#ifdef BOUNDS_CHECK
+ {
+ GLubyte *buf = (GLubyte *) bufObj->Pointer;
+ GLuint i;
+ /* buffer is 100 bytes larger than requested, fill with magic value */
+ for (i = 0; i < 100; i++) {
+ buf[bufObj->Size - i - 1] = 123;
+ }
+ }
+#endif
return bufObj->Pointer;
}
@@ -1071,6 +1164,42 @@ _mesa_UnmapBufferARB(GLenum target)
return GL_FALSE;
}
+#ifdef BOUNDS_CHECK
+ if (bufObj->Access != GL_READ_ONLY_ARB) {
+ GLubyte *buf = (GLubyte *) bufObj->Pointer;
+ GLuint i;
+ /* check that last 100 bytes are still = magic value */
+ for (i = 0; i < 100; i++) {
+ GLuint pos = bufObj->Size - i - 1;
+ if (buf[pos] != 123) {
+ _mesa_warning(ctx, "Out of bounds buffer object write detected"
+ " at position %d (value = %u)\n",
+ pos, buf[pos]);
+ }
+ }
+ }
+#endif
+
+#ifdef VBO_DEBUG
+ if (bufObj->Access == GL_WRITE_ONLY_ARB) {
+ GLuint i, unchanged = 0;
+ GLubyte *b = (GLubyte *) bufObj->Pointer;
+ GLint pos = -1;
+ /* check which bytes changed */
+ for (i = 0; i < bufObj->Size - 1; i++) {
+ if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) {
+ unchanged++;
+ if (pos == -1)
+ pos = i;
+ }
+ }
+ if (unchanged) {
+ _mesa_printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n",
+ bufObj->Name, unchanged, bufObj->Size, pos);
+ }
+ }
+#endif
+
status = ctx->Driver.UnmapBuffer( ctx, target, bufObj );
bufObj->Access = DEFAULT_ACCESS;
bufObj->Pointer = NULL;
@@ -1140,3 +1269,84 @@ _mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
*params = bufObj->Pointer;
}
+
+
+void GLAPIENTRY
+_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
+ GLintptr readOffset, GLintptr writeOffset,
+ GLsizeiptr size)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_buffer_object *src, *dst;
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ src = get_buffer(ctx, readTarget);
+ if (!src || src->Name == 0) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glCopyBuffserSubData(readTarget = 0x%x)", readTarget);
+ return;
+ }
+
+ dst = get_buffer(ctx, writeTarget);
+ if (!dst || dst->Name == 0) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glCopyBuffserSubData(writeTarget = 0x%x)", writeTarget);
+ return;
+ }
+
+ if (src->Pointer) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glCopyBuffserSubData(readBuffer is mapped)");
+ return;
+ }
+
+ if (dst->Pointer) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glCopyBuffserSubData(writeBuffer is mapped)");
+ return;
+ }
+
+ if (readOffset < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glCopyBuffserSubData(readOffset = %d)", readOffset);
+ return;
+ }
+
+ if (writeOffset < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glCopyBuffserSubData(writeOffset = %d)", writeOffset);
+ return;
+ }
+
+ if (readOffset + size > src->Size) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glCopyBuffserSubData(readOffset + size = %d)",
+ readOffset, size);
+ return;
+ }
+
+ if (writeOffset + size > dst->Size) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glCopyBuffserSubData(writeOffset + size = %d)",
+ writeOffset, size);
+ return;
+ }
+
+ if (src == dst) {
+ if (readOffset + size <= writeOffset) {
+ /* OK */
+ }
+ else if (writeOffset + size <= readOffset) {
+ /* OK */
+ }
+ else {
+ /* overlapping src/dst is illegal */
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glCopyBuffserSubData(overlapping src/dst)");
+ return;
+ }
+ }
+
+ ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size);
+}
+