[Mesa-dev,16/19] mesa: Implement glBindVertexBuffers

Submitted by Fredrik Höglund on April 21, 2014, 9:57 p.m.

Details

Message ID 1398117477-10313-17-git-send-email-fredrik@kde.org
State New
Headers show

Not browsing as part of any series.

Commit Message

Fredrik Höglund April 21, 2014, 9:57 p.m.
---
 src/mesa/main/varray.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 114 insertions(+)

Patch hide | download patch | download mbox

diff --git a/src/mesa/main/varray.c b/src/mesa/main/varray.c
index 2f2b23f..939a80b 100644
--- a/src/mesa/main/varray.c
+++ b/src/mesa/main/varray.c
@@ -1449,6 +1449,120 @@  void GLAPIENTRY
 _mesa_BindVertexBuffers(GLuint first, GLsizei count, const GLuint *buffers,
                         const GLintptr *offsets, const GLsizei *strides)
 {
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_vertex_array_object * const vao = ctx->Array.VAO;
+   GLuint i;
+
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   /* The ARB_vertex_attrib_binding spec says:
+    *
+    *    "An INVALID_OPERATION error is generated if no
+    *     vertex array object is bound."
+    */
+   if (ctx->API == API_OPENGL_CORE &&
+       ctx->Array.VAO == ctx->Array.DefaultVAO) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glBindVertexBuffers(No array object bound)");
+      return;
+   }
+
+   /* The ARB_multi_bind spec says:
+    *
+    *    "An INVALID_OPERATION error is generated if <first> + <count>
+    *     is greater than the value of MAX_VERTEX_ATTRIB_BINDINGS."
+    */
+   if (first + count > ctx->Const.MaxVertexAttribBindings) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+                  "glBindVertexBuffers(first=%u + count=%u > the value of "
+                  "GL_MAX_VERTEX_ATTRIB_BINDINGS=%u)",
+                  first, count, ctx->Const.MaxVertexAttribBindings);
+      return;
+   }
+
+   if (!buffers) {
+      /**
+       * The ARB_multi_bind spec says:
+       *
+       *    "If <buffers> is NULL, each affected vertex buffer binding point
+       *     from <first> through <first>+<count>-1 will be reset to have no
+       *     bound buffer object.  In this case, the offsets and strides
+       *     associated with the binding points are set to default values,
+       *     ignoring <offsets> and <strides>."
+       */
+      struct gl_buffer_object *vbo = ctx->Shared->NullBufferObj;
+
+      for (i = 0; i < count; i++)
+         bind_vertex_buffer(ctx, VERT_ATTRIB_GENERIC(first + i), vbo, 0, 16);
+
+      return;
+   }
+
+   /* Note that the error semantics for multi-bind commands differ from
+    * those of other GL commands.
+    *
+    * The Issues section in the ARB_multi_bind spec says:
+    *
+    *    "(11) Typically, OpenGL specifies that if an error is generated by
+    *          a command, that command has no effect.  This is somewhat
+    *          unfortunate for multi-bind commands, because it would require
+    *          a first pass to scan the entire list of bound objects for
+    *          errors and then a second pass to actually perform the
+    *          bindings.  Should we have different error semantics?
+    *
+    *       RESOLVED:  Yes.  In this specification, when the parameters for
+    *       one of the <count> binding points are invalid, that binding
+    *       point is not updated and an error will be generated.  However,
+    *       other binding points in the same command will be updated if
+    *       their parameters are valid and no other error occurs."
+    */
+
+   _mesa_begin_bufferobj_lookups(ctx);
+
+   for (i = 0; i < count; i++) {
+      /* The ARB_multi_bind spec says:
+       *
+       *    "An INVALID_VALUE error is generated if any value in
+       *     <offsets> or <strides> is negative (per binding)."
+       */
+      if (offsets[i] < 0) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glBindVertexBuffer(offsets[%u]=%lldd < 0)",
+                     i, (long long int) offsets[i]);
+         continue;
+      }
+
+      if (strides[i] < 0) {
+         _mesa_error(ctx, GL_INVALID_VALUE,
+                     "glBindVertexBuffer(strides[%u]=%lld < 0)",
+                     i, (long long int) strides[i]);
+         continue;
+      }
+
+      if (buffers[i]) {
+         struct gl_vertex_buffer_binding *binding =
+            &vao->VertexBinding[VERT_ATTRIB_GENERIC(first + i)];
+         struct gl_buffer_object *vbo;
+
+         if (buffers[i] == binding->BufferObj->Name)
+            vbo = binding->BufferObj;
+         else
+            vbo = _mesa_multi_bind_lookup_bufferobj(ctx, GL_ARRAY_BUFFER,
+                                                    buffers, i,
+                                                    "glBindVertexBuffers");
+
+         if (!vbo)
+            continue;
+
+         bind_vertex_buffer(ctx, VERT_ATTRIB_GENERIC(first + i), vbo,
+                            offsets[i], strides[i]);
+      } else {
+         bind_vertex_buffer(ctx, VERT_ATTRIB_GENERIC(first + i),
+                            ctx->Shared->NullBufferObj, 0, 16);
+      }
+   }
+
+   _mesa_end_bufferobj_lookups(ctx);
 }