summaryrefslogtreecommitdiffstats
path: root/src/VBox/GuestHost/OpenGL/state_tracker/state_bufferobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/GuestHost/OpenGL/state_tracker/state_bufferobject.c')
-rw-r--r--src/VBox/GuestHost/OpenGL/state_tracker/state_bufferobject.c1126
1 files changed, 1126 insertions, 0 deletions
diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_bufferobject.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_bufferobject.c
new file mode 100644
index 00000000..373b24f8
--- /dev/null
+++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_bufferobject.c
@@ -0,0 +1,1126 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "state.h"
+#include "state/cr_statetypes.h"
+#include "state/cr_statefuncs.h"
+#include "state_internals.h"
+#include "cr_mem.h"
+#include "cr_string.h"
+
+
+static CRBufferObject *AllocBufferObject(GLuint name)
+{
+ CRBufferObject *b = crCalloc(sizeof(CRBufferObject));
+ if (b) {
+ b->refCount = 1;
+ b->id = name;
+ b->hwid = name;
+ b->usage = GL_STATIC_DRAW_ARB;
+ b->access = GL_READ_WRITE_ARB;
+ b->bResyncOnRead = GL_FALSE;
+ CR_STATE_SHAREDOBJ_USAGE_INIT(b);
+ }
+ return b;
+}
+
+void STATE_APIENTRY crStateGenBuffersARB(GLsizei n, GLuint *buffers)
+{
+ CRContext *g = GetCurrentContext();
+ crStateGenNames(g, g->shared->buffersTable, n, buffers);
+}
+
+void crStateRegBuffers(GLsizei n, GLuint *buffers)
+{
+ CRContext *g = GetCurrentContext();
+ crStateRegNames(g, g->shared->buffersTable, n, buffers);
+}
+
+GLboolean crStateIsBufferBoundForCtx(CRContext *g, GLenum target)
+{
+ CRBufferObjectState *b = &(g->bufferobject);
+
+ switch (target)
+ {
+ case GL_ARRAY_BUFFER_ARB:
+ return b->arrayBuffer->id!=0;
+ case GL_ELEMENT_ARRAY_BUFFER_ARB:
+ return b->elementsBuffer->id!=0;
+#ifdef CR_ARB_pixel_buffer_object
+ case GL_PIXEL_PACK_BUFFER_ARB:
+ return b->packBuffer->id!=0;
+ case GL_PIXEL_UNPACK_BUFFER_ARB:
+ return b->unpackBuffer->id!=0;
+#endif
+ default:
+ return GL_FALSE;
+ }
+}
+
+GLboolean crStateIsBufferBound(GLenum target)
+{
+ CRContext *g = GetCurrentContext();
+ return crStateIsBufferBoundForCtx(g, target);
+}
+
+CRBufferObject *crStateGetBoundBufferObject(GLenum target, CRBufferObjectState *b)
+{
+ switch (target)
+ {
+ case GL_ARRAY_BUFFER_ARB:
+ return b->arrayBuffer;
+ case GL_ELEMENT_ARRAY_BUFFER_ARB:
+ return b->elementsBuffer;
+#ifdef CR_ARB_pixel_buffer_object
+ case GL_PIXEL_PACK_BUFFER_ARB:
+ return b->packBuffer;
+ case GL_PIXEL_UNPACK_BUFFER_ARB:
+ return b->unpackBuffer;
+#endif
+ default:
+ return NULL;
+ }
+}
+
+DECLEXPORT(GLboolean) STATE_APIENTRY crStateIsBufferARB( GLuint buffer )
+{
+ CRContext *g = GetCurrentContext();
+
+ FLUSH();
+
+ if (g->current.inBeginEnd) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
+ "glIsBufferARB called in begin/end");
+ return GL_FALSE;
+ }
+
+ return buffer ? crHashtableIsKeyUsed(g->shared->buffersTable, buffer) : GL_FALSE;
+}
+
+void crStateBufferObjectInit (CRContext *ctx)
+{
+ CRStateBits *sb = GetCurrentBits();
+ CRBufferObjectBits *bb = &sb->bufferobject;
+ CRBufferObjectState *b = &ctx->bufferobject;
+
+ RESET(bb->dirty, ctx->bitid);
+ RESET(bb->arrayBinding, ctx->bitid);
+ RESET(bb->elementsBinding, ctx->bitid);
+#ifdef CR_ARB_pixel_buffer_object
+ RESET(bb->unpackBinding, ctx->bitid);
+ RESET(bb->packBinding, ctx->bitid);
+#endif
+
+#ifdef IN_GUEST
+ b->retainBufferData = GL_TRUE;
+#else
+ b->retainBufferData = GL_FALSE;
+#endif
+
+ b->nullBuffer = AllocBufferObject(0);
+ b->arrayBuffer = b->nullBuffer;
+ b->elementsBuffer = b->nullBuffer;
+ b->nullBuffer->refCount += 2;
+#ifdef CR_ARB_pixel_buffer_object
+ b->packBuffer = b->nullBuffer;
+ b->unpackBuffer = b->nullBuffer;
+ b->nullBuffer->refCount += 2;
+#endif
+
+ ctx->shared->bVBOResyncNeeded = GL_FALSE;
+}
+
+void crStateFreeBufferObject(void *data)
+{
+ CRBufferObject *pObj = (CRBufferObject *)data;
+ if (pObj->data) crFree(pObj->data);
+
+#ifndef IN_GUEST
+ if (diff_api.DeleteBuffersARB)
+ {
+ diff_api.DeleteBuffersARB(1, &pObj->hwid);
+ }
+#endif
+
+ crFree(pObj);
+}
+
+void crStateBufferObjectDestroy (CRContext *ctx)
+{
+ CRBufferObjectState *b = &ctx->bufferobject;
+ crFree(b->nullBuffer);
+}
+
+static void crStateCheckBufferHWIDCB(unsigned long key, void *data1, void *data2)
+{
+ CRBufferObject *pObj = (CRBufferObject *) data1;
+ crCheckIDHWID_t *pParms = (crCheckIDHWID_t*) data2;
+ (void) key;
+
+ if (pObj->hwid==pParms->hwid)
+ pParms->id = pObj->id;
+}
+
+DECLEXPORT(GLuint) STATE_APIENTRY crStateBufferHWIDtoID(GLuint hwid)
+{
+ CRContext *g = GetCurrentContext();
+ crCheckIDHWID_t parms;
+
+ parms.id = hwid;
+ parms.hwid = hwid;
+
+ crHashtableWalk(g->shared->buffersTable, crStateCheckBufferHWIDCB, &parms);
+ return parms.id;
+}
+
+DECLEXPORT(GLuint) STATE_APIENTRY crStateGetBufferHWID(GLuint id)
+{
+ CRContext *g = GetCurrentContext();
+ CRBufferObject *pObj = (CRBufferObject *) crHashtableSearch(g->shared->buffersTable, id);
+
+ return pObj ? pObj->hwid : 0;
+}
+
+void STATE_APIENTRY
+crStateBindBufferARB (GLenum target, GLuint buffer)
+{
+ CRContext *g = GetCurrentContext();
+ CRBufferObjectState *b = &(g->bufferobject);
+ CRStateBits *sb = GetCurrentBits();
+ CRBufferObjectBits *bb = &(sb->bufferobject);
+ CRBufferObject *oldObj, *newObj;
+
+ if (g->current.inBeginEnd) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
+ "glBindBufferARB called in begin/end");
+ return;
+ }
+
+ FLUSH();
+
+ oldObj = crStateGetBoundBufferObject(target, b);
+ if (!oldObj)
+ {
+ crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glBindBufferARB(target)");
+ return;
+ }
+
+ if (buffer == 0) {
+ newObj = b->nullBuffer;
+ }
+ else {
+ newObj = (CRBufferObject *) crHashtableSearch(g->shared->buffersTable, buffer);
+ if (!newObj) {
+ CRSTATE_CHECKERR(!crHashtableIsKeyUsed(g->shared->buffersTable, buffer), GL_INVALID_OPERATION, "name is not a buffer object");
+ newObj = AllocBufferObject(buffer);
+ CRSTATE_CHECKERR(!newObj, GL_OUT_OF_MEMORY, "glBindBuffer");
+#ifndef IN_GUEST
+ diff_api.GenBuffersARB(1, &newObj->hwid);
+ if (!newObj->hwid)
+ {
+ crWarning("GenBuffersARB failed!");
+ crFree(newObj);
+ return;
+ }
+#endif
+ crHashtableAdd( g->shared->buffersTable, buffer, newObj );
+ }
+
+ CR_STATE_SHAREDOBJ_USAGE_SET(newObj, g);
+ }
+
+ newObj->refCount++;
+ oldObj->refCount--;
+
+ switch (target)
+ {
+ case GL_ARRAY_BUFFER_ARB:
+ b->arrayBuffer = newObj;
+ DIRTY(bb->dirty, g->neg_bitid);
+ DIRTY(bb->arrayBinding, g->neg_bitid);
+ break;
+ case GL_ELEMENT_ARRAY_BUFFER_ARB:
+ b->elementsBuffer = newObj;
+ DIRTY(bb->dirty, g->neg_bitid);
+ DIRTY(bb->elementsBinding, g->neg_bitid);
+ break;
+#ifdef CR_ARB_pixel_buffer_object
+ case GL_PIXEL_PACK_BUFFER_ARB:
+ b->packBuffer = newObj;
+ DIRTY(bb->dirty, g->neg_bitid);
+ DIRTY(bb->packBinding, g->neg_bitid);
+ break;
+ case GL_PIXEL_UNPACK_BUFFER_ARB:
+ b->unpackBuffer = newObj;
+ DIRTY(bb->dirty, g->neg_bitid);
+ DIRTY(bb->unpackBinding, g->neg_bitid);
+ break;
+#endif
+ default: /*can't get here*/
+ CRASSERT(false);
+ return;
+ }
+
+ if (oldObj->refCount <= 0) {
+ /*we shouldn't reach this point*/
+ CRASSERT(false);
+ crHashtableDelete(g->shared->buffersTable, (unsigned long) oldObj->id, crStateFreeBufferObject);
+ }
+
+#ifdef IN_GUEST
+ if (target == GL_PIXEL_PACK_BUFFER_ARB)
+ {
+ newObj->bResyncOnRead = GL_TRUE;
+ }
+#endif
+}
+
+static void ctStateBuffersRefsCleanup(CRContext *ctx, CRBufferObject *obj, CRbitvalue *neg_bitid)
+{
+ CRBufferObjectState *b = &(ctx->bufferobject);
+ CRStateBits *sb = GetCurrentBits();
+ CRBufferObjectBits *bb = &(sb->bufferobject);
+ int j, k;
+
+ if (obj == b->arrayBuffer)
+ {
+ b->arrayBuffer = b->nullBuffer;
+ b->arrayBuffer->refCount++;
+ DIRTY(bb->dirty, neg_bitid);
+ DIRTY(bb->arrayBinding, neg_bitid);
+ }
+ if (obj == b->elementsBuffer)
+ {
+ b->elementsBuffer = b->nullBuffer;
+ b->elementsBuffer->refCount++;
+ DIRTY(bb->dirty, neg_bitid);
+ DIRTY(bb->elementsBinding, neg_bitid);
+ }
+#ifdef CR_ARB_pixel_buffer_object
+ if (obj == b->packBuffer)
+ {
+ b->packBuffer = b->nullBuffer;
+ b->packBuffer->refCount++;
+ DIRTY(bb->dirty, neg_bitid);
+ DIRTY(bb->packBinding, neg_bitid);
+ }
+ if (obj == b->unpackBuffer)
+ {
+ b->unpackBuffer = b->nullBuffer;
+ b->unpackBuffer->refCount++;
+ DIRTY(bb->dirty, neg_bitid);
+ DIRTY(bb->unpackBinding, neg_bitid);
+ }
+#endif
+
+#ifdef CR_ARB_vertex_buffer_object
+ for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j)
+ {
+ CRClientPointer *cp = crStateGetClientPointerByIndex(j, &ctx->client.array);
+ if (obj == cp->buffer)
+ {
+ cp->buffer = b->nullBuffer;
+ ++b->nullBuffer->refCount;
+ }
+ }
+
+ for (k=0; k<ctx->client.vertexArrayStackDepth; ++k)
+ {
+ CRVertexArrays *pArray = &ctx->client.vertexArrayStack[k];
+ for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j)
+ {
+ CRClientPointer *cp = crStateGetClientPointerByIndex(j, pArray);
+ if (obj == cp->buffer)
+ {
+ cp->buffer = b->nullBuffer;
+ ++b->nullBuffer->refCount;
+ }
+ }
+ }
+#endif
+
+ CR_STATE_SHAREDOBJ_USAGE_CLEAR(obj, ctx);
+}
+
+void STATE_APIENTRY
+crStateDeleteBuffersARB(GLsizei n, const GLuint *buffers)
+{
+ CRContext *g = GetCurrentContext();
+ int i;
+
+ FLUSH();
+
+ if (g->current.inBeginEnd) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
+ "glDeleteBuffersARB called in Begin/End");
+ return;
+ }
+
+ if (n < 0) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_VALUE,
+ "glDeleteBuffersARB(n < 0)");
+ return;
+ }
+
+ for (i = 0; i < n; i++) {
+ if (buffers[i]) {
+ CRBufferObject *obj = (CRBufferObject *)
+ crHashtableSearch(g->shared->buffersTable, buffers[i]);
+ if (obj) {
+ int j;
+
+ ctStateBuffersRefsCleanup(g, obj, g->neg_bitid);
+
+ CR_STATE_SHAREDOBJ_USAGE_FOREACH_USED_IDX(obj, j)
+ {
+ /* saved state version <= SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS does not have usage bits info,
+ * so on restore, we set mark bits as used.
+ * This is why g_pAvailableContexts[j] could be NULL
+ * also g_pAvailableContexts[0] will hold default context, which we should discard */
+ CRContext *ctx = g_pAvailableContexts[j];
+ if (j && ctx)
+ {
+ ctStateBuffersRefsCleanup(ctx, obj, g->neg_bitid); /* <- yes, use g->neg_bitid, i.e. neg_bitid of the current context to ensure others bits get dirtified,
+ * but not the current context ones*/
+ }
+ else
+ CR_STATE_SHAREDOBJ_USAGE_CLEAR_IDX(obj, j);
+ }
+
+ crHashtableDelete(g->shared->buffersTable, buffers[i], crStateFreeBufferObject);
+ }
+ }
+ }
+}
+
+void STATE_APIENTRY
+crStateBufferDataARB(GLenum target, GLsizeiptrARB size, const GLvoid * data, GLenum usage)
+{
+ CRContext *g = GetCurrentContext();
+ CRBufferObjectState *b = &g->bufferobject;
+ CRBufferObject *obj;
+ CRStateBits *sb = GetCurrentBits();
+ CRBufferObjectBits *bb = &sb->bufferobject;
+
+ FLUSH();
+
+ if (g->current.inBeginEnd) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
+ "glBufferDataARB called in begin/end");
+ return;
+ }
+
+ if (size < 0) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_VALUE,
+ "glBufferDataARB(size < 0)");
+ return;
+ }
+
+ switch (usage) {
+ case GL_STREAM_DRAW_ARB:
+ case GL_STREAM_READ_ARB:
+ case GL_STREAM_COPY_ARB:
+ case GL_STATIC_DRAW_ARB:
+ case GL_STATIC_READ_ARB:
+ case GL_STATIC_COPY_ARB:
+ case GL_DYNAMIC_DRAW_ARB:
+ case GL_DYNAMIC_READ_ARB:
+ case GL_DYNAMIC_COPY_ARB:
+ /* OK */
+ break;
+ default:
+ crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
+ "glBufferDataARB(usage)");
+ return;
+ }
+
+ obj = crStateGetBoundBufferObject(target, b);
+ if (!obj)
+ {
+ crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glBufferDataARB(target)");
+ return;
+ }
+
+ if (obj->id == 0) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glBufferDataARB");
+ return;
+ }
+
+ if (obj->pointer) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
+ "glBufferDataARB(buffer is mapped)");
+ return;
+ }
+
+ obj->usage = usage;
+ obj->size = size;
+
+ /* The user of the state tracker should set the retainBufferData field
+ * during context initialization, if needed.
+ */
+ if (b->retainBufferData) {
+ if (obj->data) {
+ crFree(obj->data);
+ }
+
+ obj->data = crAlloc(size);
+ if (!obj->data) {
+ crStateError(__LINE__, __FILE__, GL_OUT_OF_MEMORY, "glBufferDataARB");
+ return;
+ }
+ if (data)
+ crMemcpy(obj->data, data, size);
+ }
+
+ DIRTY(bb->dirty, g->neg_bitid);
+ DIRTY(obj->dirty, g->neg_bitid);
+ obj->dirtyStart = 0;
+ obj->dirtyLength = size;
+}
+
+
+void STATE_APIENTRY
+crStateBufferSubDataARB(GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid * data)
+{
+ CRContext *g = GetCurrentContext();
+ CRBufferObjectState *b = &g->bufferobject;
+ CRBufferObject *obj;
+ CRStateBits *sb = GetCurrentBits();
+ CRBufferObjectBits *bb = &sb->bufferobject;
+
+ FLUSH();
+
+ if (g->current.inBeginEnd) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
+ "glBufferSubDataARB called in begin/end");
+ return;
+ }
+
+ obj = crStateGetBoundBufferObject(target, b);
+ if (!obj)
+ {
+ crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glBufferSubDataARB(target)");
+ return;
+ }
+
+ if (obj->id == 0) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
+ "glBufferSubDataARB");
+ return;
+ }
+
+ if (obj->pointer) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
+ "glBufferSubDataARB(buffer is mapped)");
+ return;
+ }
+
+ if (size < 0 || offset < 0 || (unsigned int)offset + size > obj->size) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
+ "glBufferSubDataARB(bad offset and/or size)");
+ return;
+ }
+
+ if (b->retainBufferData && obj->data) {
+ crMemcpy((char *) obj->data + offset, data, size);
+ }
+
+ DIRTY(bb->dirty, g->neg_bitid);
+ DIRTY(obj->dirty, g->neg_bitid);
+ /* grow dirty region */
+ if (offset + size > obj->dirtyStart + obj->dirtyLength)
+ obj->dirtyLength = offset + size;
+ if (offset < obj->dirtyStart)
+ obj->dirtyStart = offset;
+}
+
+
+void STATE_APIENTRY
+crStateGetBufferSubDataARB(GLenum target, GLintptrARB offset, GLsizeiptrARB size, void * data)
+{
+ CRContext *g = GetCurrentContext();
+ CRBufferObjectState *b = &g->bufferobject;
+ CRBufferObject *obj;
+
+ FLUSH();
+
+ if (g->current.inBeginEnd) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
+ "glGetBufferSubDataARB called in begin/end");
+ return;
+ }
+
+ obj = crStateGetBoundBufferObject(target, b);
+ if (!obj)
+ {
+ crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glGetBufferSubDataARB(target)");
+ return;
+ }
+
+ if (obj->id == 0) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
+ "glGetBufferSubDataARB");
+ return;
+ }
+
+ if (obj->pointer) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
+ "glGetBufferSubDataARB(buffer is mapped)");
+ return;
+ }
+
+ if (size < 0 || offset < 0 || (unsigned int)offset + size > obj->size) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
+ "glGetBufferSubDataARB(bad offset and/or size)");
+ return;
+ }
+
+ if (b->retainBufferData && obj->data) {
+ crMemcpy(data, (char *) obj->data + offset, size);
+ }
+}
+
+
+void * STATE_APIENTRY
+crStateMapBufferARB(GLenum target, GLenum access)
+{
+ CRContext *g = GetCurrentContext();
+ CRBufferObjectState *b = &g->bufferobject;
+ CRBufferObject *obj;
+
+ FLUSH();
+
+ if (g->current.inBeginEnd) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
+ "glMapBufferARB called in begin/end");
+ return NULL;
+ }
+
+ obj = crStateGetBoundBufferObject(target, b);
+ if (!obj)
+ {
+ crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glMapBufferARB(target)");
+ return NULL;
+ }
+
+ if (obj->id == 0) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glMapBufferARB");
+ return GL_FALSE;
+ }
+
+ switch (access) {
+ case GL_READ_ONLY_ARB:
+ case GL_WRITE_ONLY_ARB:
+ case GL_READ_WRITE_ARB:
+ obj->access = access;
+ break;
+ default:
+ crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
+ "glMapBufferARB(access)");
+ return NULL;
+ }
+
+ if (b->retainBufferData && obj->data)
+ obj->pointer = obj->data;
+
+ return obj->pointer;
+}
+
+
+GLboolean STATE_APIENTRY
+crStateUnmapBufferARB(GLenum target)
+{
+ CRContext *g = GetCurrentContext();
+ CRBufferObjectState *b = &g->bufferobject;
+ CRBufferObject *obj;
+ CRStateBits *sb = GetCurrentBits();
+ CRBufferObjectBits *bb = &sb->bufferobject;
+
+ FLUSH();
+
+ if (g->current.inBeginEnd) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
+ "glUnmapBufferARB called in begin/end");
+ return GL_FALSE;
+ }
+
+ obj = crStateGetBoundBufferObject(target, b);
+ if (!obj)
+ {
+ crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glUnmapBufferARB(target)");
+ return GL_FALSE;
+ }
+
+ if (obj->id == 0) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glUnmapBufferARB");
+ return GL_FALSE;
+ }
+
+ if (!obj->pointer) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, "glUnmapBufferARB");
+ return GL_FALSE;
+ }
+
+ obj->pointer = NULL;
+
+ if (obj->access != GL_READ_ONLY_ARB) {
+ /* the data was most likely modified */
+ DIRTY(bb->dirty, g->neg_bitid);
+ DIRTY(obj->dirty, g->neg_bitid);
+ obj->dirtyStart = 0;
+ obj->dirtyLength = obj->size;
+ }
+
+ return GL_TRUE;
+}
+
+
+void STATE_APIENTRY
+crStateGetBufferParameterivARB(GLenum target, GLenum pname, GLint *params)
+{
+ CRContext *g = GetCurrentContext();
+ CRBufferObjectState *b = &g->bufferobject;
+ CRBufferObject *obj;
+
+ FLUSH();
+
+ if (g->current.inBeginEnd) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
+ "glGetBufferParameterivARB called in begin/end");
+ return;
+ }
+
+ obj = crStateGetBoundBufferObject(target, b);
+ if (!obj)
+ {
+ crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glGetBufferParameterivARB(target)");
+ return;
+ }
+
+ switch (pname) {
+ case GL_BUFFER_SIZE_ARB:
+ *params = obj->size;
+ break;
+ case GL_BUFFER_USAGE_ARB:
+ *params = obj->usage;
+ break;
+ case GL_BUFFER_ACCESS_ARB:
+ *params = obj->access;
+ break;
+ case GL_BUFFER_MAPPED_ARB:
+ *params = (obj->pointer != NULL);
+ break;
+ default:
+ crStateError(__LINE__, __FILE__, GL_INVALID_ENUM,
+ "glGetBufferParameterivARB(pname)");
+ return;
+ }
+}
+
+
+void STATE_APIENTRY
+crStateGetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
+{
+ CRContext *g = GetCurrentContext();
+ CRBufferObjectState *b = &g->bufferobject;
+ CRBufferObject *obj;
+
+ FLUSH();
+
+ if (g->current.inBeginEnd) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION,
+ "glGetBufferPointervARB called in begin/end");
+ return;
+ }
+
+ obj = crStateGetBoundBufferObject(target, b);
+ if (!obj)
+ {
+ crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glGetBufferPointervARB(target)");
+ return;
+ }
+
+ if (pname != GL_BUFFER_MAP_POINTER_ARB) {
+ crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)");
+ return;
+ }
+
+ *params = obj->pointer;
+}
+
+
+/**
+ * We need to check if the GL_EXT_vertex/pixel_buffer_object extensions
+ * are supported before calling any of the diff_api functions.
+ * This flag indicates if the extensions is available (1), not available (0)
+ * or needs to be tested for (-1).
+ * If we don't do this, we can segfault inside OpenGL.
+ * Ideally, the render SPU should no-op unsupported GL functions, but
+ * that's a bit complicated.
+ */
+static GLboolean
+HaveBufferObjectExtension(void)
+{
+ static GLint haveBufferObjectExt = -1;
+
+ if (haveBufferObjectExt == -1) {
+ const char *ext;
+ /* XXX this check is temporary. We need to make the tilesort SPU plug
+ * GetString into the diff'ing table in order for this to really work.
+ */
+ if (!diff_api.GetString) {
+ haveBufferObjectExt = 0;
+ return 0;
+ }
+ CRASSERT(diff_api.GetString);
+ ext = (const char *) diff_api.GetString(GL_EXTENSIONS);
+ if (crStrstr(ext, "GL_ARB_vertex_buffer_object") ||
+ crStrstr(ext, "GL_ARB_pixel_buffer_object")) {
+ haveBufferObjectExt = 1;
+ }
+ else {
+ haveBufferObjectExt = 0;
+ }
+ }
+ return haveBufferObjectExt;
+}
+
+static void crStateBufferObjectIntCmp(CRBufferObjectBits *bb, CRbitvalue *bitID,
+ CRContext *fromCtx, CRContext *toCtx,
+ GLboolean bSwitch)
+{
+ CRBufferObjectState *from = &(fromCtx->bufferobject);
+ const CRBufferObjectState *to = &(toCtx->bufferobject);
+
+ /* ARRAY_BUFFER */
+ if (CHECKDIRTY(bb->arrayBinding, bitID))
+ {
+ if (from->arrayBuffer != to->arrayBuffer)
+ {
+ GLuint bufferID = to->arrayBuffer ? to->arrayBuffer->hwid : 0;
+ diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, bufferID);
+ if (bSwitch)
+ {
+ FILLDIRTY(bb->arrayBinding);
+ FILLDIRTY(bb->dirty);
+ }
+ else
+ {
+ CLEARDIRTY2(bb->arrayBinding, bitID);
+ from->arrayBuffer = to->arrayBuffer;
+ }
+ }
+ if (bSwitch) CLEARDIRTY2(bb->arrayBinding, bitID);
+ }
+
+ if (to->arrayBuffer && CHECKDIRTY(to->arrayBuffer->dirty, bitID))
+ {
+ /* update array buffer data */
+ CRBufferObject *bufObj = to->arrayBuffer;
+ CRASSERT(bufObj);
+ if (bufObj->dirtyStart == 0 && bufObj->dirtyLength == (int) bufObj->size)
+ {
+ /* update whole buffer */
+ diff_api.BufferDataARB(GL_ARRAY_BUFFER_ARB, bufObj->size,
+ bufObj->data, bufObj->usage);
+ }
+ else
+ {
+ /* update sub buffer */
+ diff_api.BufferSubDataARB(GL_ARRAY_BUFFER_ARB,
+ bufObj->dirtyStart, bufObj->dirtyLength,
+ (char *) bufObj->data + bufObj->dirtyStart);
+ }
+ if (bSwitch) FILLDIRTY(bufObj->dirty);
+ CLEARDIRTY2(bufObj->dirty, bitID);
+ }
+
+ /* ELEMENTS_BUFFER */
+ if (CHECKDIRTY(bb->elementsBinding, bitID))
+ {
+ if (from->elementsBuffer != to->elementsBuffer)
+ {
+ GLuint bufferID = to->elementsBuffer ? to->elementsBuffer->hwid : 0;
+ diff_api.BindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, bufferID);
+ if (bSwitch)
+ {
+ FILLDIRTY(bb->elementsBinding);
+ FILLDIRTY(bb->dirty);
+ }
+ else
+ {
+ CLEARDIRTY2(bb->elementsBinding, bitID);
+ from->elementsBuffer = to->elementsBuffer;
+ }
+ }
+ if (bSwitch) CLEARDIRTY2(bb->elementsBinding, bitID);
+ }
+
+ if (to->elementsBuffer && CHECKDIRTY(to->elementsBuffer->dirty, bitID))
+ {
+ /* update array buffer data */
+ CRBufferObject *bufObj = to->elementsBuffer;
+ CRASSERT(bufObj);
+ if (bufObj->dirtyStart == 0 && bufObj->dirtyLength == (int) bufObj->size)
+ {
+ /* update whole buffer */
+ diff_api.BufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, bufObj->size,
+ bufObj->data, bufObj->usage);
+ }
+ else
+ {
+ /* update sub buffer */
+ diff_api.BufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
+ bufObj->dirtyStart, bufObj->dirtyLength,
+ (char *) bufObj->data + bufObj->dirtyStart);
+ }
+ if (bSwitch) FILLDIRTY(bufObj->dirty);
+ CLEARDIRTY2(bufObj->dirty, bitID);
+ }
+
+#ifdef CR_ARB_pixel_buffer_object
+ /* PIXEL_PACK_BUFFER */
+ if (CHECKDIRTY(bb->packBinding, bitID))
+ {
+ if (from->packBuffer != to->packBuffer)
+ {
+ GLuint bufferID = to->packBuffer ? to->packBuffer->hwid : 0;
+ diff_api.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, bufferID);
+ if (bSwitch)
+ {
+ FILLDIRTY(bb->packBinding);
+ FILLDIRTY(bb->dirty);
+ }
+ else
+ {
+ CLEARDIRTY2(bb->packBinding, bitID);
+ from->packBuffer = to->packBuffer;
+ }
+ }
+ if (bSwitch) CLEARDIRTY2(bb->packBinding, bitID);
+ }
+
+ if (to->packBuffer && CHECKDIRTY(to->packBuffer->dirty, bitID))
+ {
+ /* update array buffer data */
+ CRBufferObject *bufObj = to->packBuffer;
+ CRASSERT(bufObj);
+ if (bufObj->dirtyStart == 0 && bufObj->dirtyLength == (int) bufObj->size)
+ {
+ /* update whole buffer */
+ diff_api.BufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, bufObj->size,
+ bufObj->data, bufObj->usage);
+ }
+ else
+ {
+ /* update sub buffer */
+ diff_api.BufferSubDataARB(GL_PIXEL_PACK_BUFFER_ARB,
+ bufObj->dirtyStart, bufObj->dirtyLength,
+ (char *) bufObj->data + bufObj->dirtyStart);
+ }
+ if (bSwitch) FILLDIRTY(bufObj->dirty);
+ CLEARDIRTY2(bufObj->dirty, bitID);
+ }
+
+ /* PIXEL_UNPACK_BUFFER */
+ if (CHECKDIRTY(bb->unpackBinding, bitID))
+ {
+ if (from->unpackBuffer != to->unpackBuffer)
+ {
+ GLuint bufferID = to->unpackBuffer ? to->unpackBuffer->hwid : 0;
+ diff_api.BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, bufferID);
+ if (bSwitch)
+ {
+ FILLDIRTY(bb->unpackBinding);
+ FILLDIRTY(bb->dirty);
+ }
+ else
+ {
+ CLEARDIRTY2(bb->unpackBinding, bitID);
+ from->unpackBuffer = to->unpackBuffer;
+ }
+ }
+ if (bSwitch) CLEARDIRTY2(bb->unpackBinding, bitID);
+ }
+
+ if (to->unpackBuffer && CHECKDIRTY(to->unpackBuffer->dirty, bitID))
+ {
+ /* update array buffer data */
+ CRBufferObject *bufObj = to->unpackBuffer;
+ CRASSERT(bufObj);
+ if (bufObj->dirtyStart == 0 && bufObj->dirtyLength == (int) bufObj->size)
+ {
+ /* update whole buffer */
+ diff_api.BufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, bufObj->size,
+ bufObj->data, bufObj->usage);
+ }
+ else
+ {
+ /* update sub buffer */
+ diff_api.BufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB,
+ bufObj->dirtyStart, bufObj->dirtyLength,
+ (char *) bufObj->data + bufObj->dirtyStart);
+ }
+ if (bSwitch) FILLDIRTY(bufObj->dirty);
+ CLEARDIRTY2(bufObj->dirty, bitID);
+ }
+#endif /*ifdef CR_ARB_pixel_buffer_object*/
+}
+
+void crStateBufferObjectDiff(CRBufferObjectBits *bb, CRbitvalue *bitID,
+ CRContext *fromCtx, CRContext *toCtx)
+{
+ /*CRBufferObjectState *from = &(fromCtx->bufferobject); - unused
+ const CRBufferObjectState *to = &(toCtx->bufferobject); - unused */
+
+ if (!HaveBufferObjectExtension())
+ return;
+
+ crStateBufferObjectIntCmp(bb, bitID, fromCtx, toCtx, GL_FALSE);
+}
+
+static void crStateBufferObjectSyncCB(unsigned long key, void *data1, void *data2)
+{
+ CRBufferObject *pBufferObj = (CRBufferObject *) data1;
+ CRBufferObjectState *pState = (CRBufferObjectState *) data2;
+ (void)key;
+
+ if (pBufferObj->id && !pBufferObj->hwid)
+ {
+ diff_api.GenBuffersARB(1, &pBufferObj->hwid);
+ CRASSERT(pBufferObj->hwid);
+ }
+
+ if (pBufferObj->data)
+ {
+ /** @todo http://www.opengl.org/registry/specs/ARB/pixel_buffer_object.txt
+ "While it is entirely legal to create a buffer object by binding
+ it to GL_ARRAY_BUFFER and loading it with data, then using it
+ with the GL_PIXEL_UNPACK_BUFFER_ARB or GL_PIXEL_PACK_BUFFER_ARB
+ binding, such behavior is liable to confuse the driver and may
+ hurt performance."
+ */
+ diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, pBufferObj->hwid);
+ diff_api.BufferDataARB(GL_ARRAY_BUFFER_ARB, pBufferObj->size, pBufferObj->data, pBufferObj->usage);
+
+ if (!pState->retainBufferData)
+ {
+ crFree(pBufferObj->data);
+ pBufferObj->data = NULL;
+ }
+ }
+}
+
+/*
+ * XXX this function might need some testing/fixing.
+ */
+void crStateBufferObjectSwitch(CRBufferObjectBits *bb, CRbitvalue *bitID,
+ CRContext *fromCtx, CRContext *toCtx)
+{
+ /*const CRBufferObjectState *from = &(fromCtx->bufferobject); - unused */
+ CRBufferObjectState *to = &(toCtx->bufferobject);
+ int i;
+
+ if (!HaveBufferObjectExtension())
+ return;
+
+ if (toCtx->shared->bVBOResyncNeeded)
+ {
+ CRClientPointer *cp;
+ GLboolean locked = toCtx->client.array.locked;
+
+ crHashtableWalk(toCtx->shared->buffersTable, crStateBufferObjectSyncCB, to);
+ toCtx->shared->bVBOResyncNeeded = GL_FALSE;
+
+ /*@todo, move to state_client.c*/
+ cp = &toCtx->client.array.v;
+ if (cp->buffer && (cp->buffer->id || locked))
+ {
+ diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, cp->buffer->hwid);
+ diff_api.VertexPointer(cp->size, cp->type, cp->stride, cp->p);
+ }
+
+ cp = &toCtx->client.array.c;
+ if (cp->buffer && (cp->buffer->id || locked))
+ {
+ diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, cp->buffer->hwid);
+ diff_api.ColorPointer(cp->size, cp->type, cp->stride, cp->p);
+ }
+
+ cp = &toCtx->client.array.f;
+ if (cp->buffer && (cp->buffer->id || locked))
+ {
+ diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, cp->buffer->hwid);
+ diff_api.FogCoordPointerEXT(cp->type, cp->stride, cp->p);
+ }
+
+ cp = &toCtx->client.array.s;
+ if (cp->buffer && (cp->buffer->id || locked))
+ {
+ diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, cp->buffer->hwid);
+ diff_api.SecondaryColorPointerEXT(cp->size, cp->type, cp->stride, cp->p);
+ }
+
+ cp = &toCtx->client.array.e;
+ if (cp->buffer && (cp->buffer->id || locked))
+ {
+ diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, cp->buffer->hwid);
+ diff_api.EdgeFlagPointer(cp->stride, cp->p);
+ }
+
+ cp = &toCtx->client.array.i;
+ if (cp->buffer && (cp->buffer->id || locked))
+ {
+ diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, cp->buffer->hwid);
+ diff_api.IndexPointer(cp->type, cp->stride, cp->p);
+ }
+
+ cp = &toCtx->client.array.n;
+ if (cp->buffer && (cp->buffer->id || locked))
+ {
+ diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, cp->buffer->hwid);
+ diff_api.NormalPointer(cp->type, cp->stride, cp->p);
+ }
+
+ for (i = 0; i < CR_MAX_TEXTURE_UNITS; i++)
+ {
+ cp = &toCtx->client.array.t[i];
+ if (cp->buffer && (cp->buffer->id || locked))
+ {
+ if (diff_api.ActiveTextureARB)
+ diff_api.ActiveTextureARB(i+GL_TEXTURE0_ARB);
+ diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, cp->buffer->hwid);
+ diff_api.TexCoordPointer(cp->size, cp->type, cp->stride, cp->p);
+ }
+ }
+
+ if (diff_api.ActiveTextureARB)
+ diff_api.ActiveTextureARB(toCtx->client.curClientTextureUnit+GL_TEXTURE0_ARB);
+
+#ifdef CR_NV_vertex_program
+ for (i = 0; i < CR_MAX_VERTEX_ATTRIBS; i++)
+ {
+ cp = &toCtx->client.array.a[i];
+ if (cp->buffer && (cp->buffer->id || locked))
+ {
+ diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, cp->buffer->hwid);
+ diff_api.VertexAttribPointerARB(i, cp->size, cp->type, cp->normalized, cp->stride, cp->p);
+ }
+ }
+#endif
+ diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, to->arrayBuffer->hwid);
+ diff_api.BindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, to->elementsBuffer->hwid);
+#ifdef CR_ARB_pixel_buffer_object
+ diff_api.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, to->packBuffer->hwid);
+ diff_api.BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, to->unpackBuffer->hwid);
+#endif
+ }
+ else
+ {
+ crStateBufferObjectIntCmp(bb, bitID, fromCtx, toCtx, GL_TRUE);
+ }
+}
+