+ /* The ARB_vertex_attrib_binding spec says:
+ *
+ * "The command
+ *
+ * void VertexAttribDivisor(uint index, uint divisor);
+ *
+ * is equivalent to (assuming no errors are generated):
+ *
+ * VertexAttribBinding(index, index);
+ * VertexBindingDivisor(index, divisor);"
+ */
+ vertex_attrib_binding(ctx, vao, genericIndex, genericIndex);
+ vertex_binding_divisor(ctx, vao, genericIndex, divisor);
+}
+
+
+unsigned
+_mesa_primitive_restart_index(const struct gl_context *ctx, GLenum ib_type)
+{
+ /* From the OpenGL 4.3 core specification, page 302:
+ * "If both PRIMITIVE_RESTART and PRIMITIVE_RESTART_FIXED_INDEX are
+ * enabled, the index value determined by PRIMITIVE_RESTART_FIXED_INDEX
+ * is used."
+ */
+ if (ctx->Array.PrimitiveRestartFixedIndex) {
+ switch (ib_type) {
+ case GL_UNSIGNED_BYTE:
+ return 0xff;
+ case GL_UNSIGNED_SHORT:
+ return 0xffff;
+ case GL_UNSIGNED_INT:
+ return 0xffffffff;
+ default:
+ assert(!"_mesa_primitive_restart_index: Invalid index buffer type.");
+ }
+ }
+
+ return ctx->Array.RestartIndex;
+}
+
+
+/**
+ * GL_ARB_vertex_attrib_binding
+ */
+static void
+vertex_array_vertex_buffer(struct gl_context *ctx,
+ struct gl_vertex_array_object *vao,
+ GLuint bindingIndex, GLuint buffer, GLintptr offset,
+ GLsizei stride, const char *func)
+{
+ struct gl_buffer_object *vbo;
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ /* The ARB_vertex_attrib_binding spec says:
+ *
+ * "An INVALID_VALUE error is generated if <bindingindex> is greater than
+ * the value of MAX_VERTEX_ATTRIB_BINDINGS."
+ */
+ if (bindingIndex >= ctx->Const.MaxVertexAttribBindings) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(bindingindex=%u > "
+ "GL_MAX_VERTEX_ATTRIB_BINDINGS)",
+ func, bindingIndex);
+ return;
+ }
+
+ /* The ARB_vertex_attrib_binding spec says:
+ *
+ * "The error INVALID_VALUE is generated if <stride> or <offset>
+ * are negative."
+ */
+ if (offset < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(offset=%" PRId64 " < 0)",
+ func, (int64_t) offset);
+ return;
+ }
+
+ if (stride < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(stride=%d < 0)", func, stride);
+ return;
+ }
+
+ if (((ctx->API == API_OPENGL_CORE && ctx->Version >= 44) || _mesa_is_gles31(ctx)) &&
+ stride > ctx->Const.MaxVertexAttribStride) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(stride=%d > "
+ "GL_MAX_VERTEX_ATTRIB_STRIDE)", func, stride);
+ return;
+ }
+
+ if (buffer ==
+ vao->BufferBinding[VERT_ATTRIB_GENERIC(bindingIndex)].BufferObj->Name) {
+ vbo = vao->BufferBinding[VERT_ATTRIB_GENERIC(bindingIndex)].BufferObj;
+ } else if (buffer != 0) {
+ vbo = _mesa_lookup_bufferobj(ctx, buffer);
+
+ if (!vbo && _mesa_is_gles31(ctx)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", func);
+ return;
+ }
+ /* From the GL_ARB_vertex_attrib_array spec:
+ *
+ * "[Core profile only:]
+ * An INVALID_OPERATION error is generated if buffer is not zero or a
+ * name returned from a previous call to GenBuffers, or if such a name
+ * has since been deleted with DeleteBuffers.
+ *
+ * Otherwise, we fall back to the same compat profile behavior as other
+ * object references (automatically gen it).
+ */
+ if (!_mesa_handle_bind_buffer_gen(ctx, buffer, &vbo, func))
+ return;
+ } else {
+ /* The ARB_vertex_attrib_binding spec says:
+ *
+ * "If <buffer> is zero, any buffer object attached to this
+ * bindpoint is detached."
+ */
+ vbo = ctx->Shared->NullBufferObj;
+ }
+
+ _mesa_bind_vertex_buffer(ctx, vao, VERT_ATTRIB_GENERIC(bindingIndex),
+ vbo, offset, stride);
+}
+
+
+void GLAPIENTRY
+_mesa_BindVertexBuffer(GLuint bindingIndex, GLuint buffer, GLintptr offset,
+ GLsizei stride)
+{
+ GET_CURRENT_CONTEXT(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 || _mesa_is_gles31(ctx)) &&
+ ctx->Array.VAO == ctx->Array.DefaultVAO) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindVertexBuffer(No array object bound)");
+ return;
+ }
+
+ vertex_array_vertex_buffer(ctx, ctx->Array.VAO, bindingIndex,
+ buffer, offset, stride, "glBindVertexBuffer");
+}
+
+
+void GLAPIENTRY
+_mesa_VertexArrayVertexBuffer(GLuint vaobj, GLuint bindingIndex, GLuint buffer,
+ GLintptr offset, GLsizei stride)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_vertex_array_object *vao;
+
+ /* The ARB_direct_state_access specification says:
+ *
+ * "An INVALID_OPERATION error is generated by VertexArrayVertexBuffer
+ * if <vaobj> is not [compatibility profile: zero or] the name of an
+ * existing vertex array object."
+ */
+ vao = _mesa_lookup_vao_err(ctx, vaobj, "glVertexArrayVertexBuffer");
+ if (!vao)
+ return;
+
+ vertex_array_vertex_buffer(ctx, vao, bindingIndex,
+ buffer, offset, stride,
+ "glVertexArrayVertexBuffer");
+}
+
+
+static void
+vertex_array_vertex_buffers(struct gl_context *ctx,
+ struct gl_vertex_array_object *vao,
+ GLuint first, GLsizei count, const GLuint *buffers,
+ const GLintptr *offsets, const GLsizei *strides,
+ const char *func)
+{
+ GLuint i;
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ /* 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,
+ "%s(first=%u + count=%d > the value of "
+ "GL_MAX_VERTEX_ATTRIB_BINDINGS=%u)",
+ func, 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++)
+ _mesa_bind_vertex_buffer(ctx, vao, 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++) {
+ struct gl_buffer_object *vbo;
+
+ /* 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,
+ "%s(offsets[%u]=%" PRId64 " < 0)",
+ func, i, (int64_t) offsets[i]);
+ continue;
+ }
+
+ if (strides[i] < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(strides[%u]=%d < 0)",
+ func, i, strides[i]);
+ continue;
+ }
+
+ if (ctx->API == API_OPENGL_CORE && ctx->Version >= 44 &&
+ strides[i] > ctx->Const.MaxVertexAttribStride) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(strides[%u]=%d > "
+ "GL_MAX_VERTEX_ATTRIB_STRIDE)", func, i, strides[i]);
+ continue;
+ }
+
+ if (buffers[i]) {
+ struct gl_vertex_buffer_binding *binding =
+ &vao->BufferBinding[VERT_ATTRIB_GENERIC(first + i)];
+
+ if (buffers[i] == binding->BufferObj->Name)
+ vbo = binding->BufferObj;
+ else
+ vbo = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, func);
+
+ if (!vbo)
+ continue;
+ } else {
+ vbo = ctx->Shared->NullBufferObj;
+ }
+
+ _mesa_bind_vertex_buffer(ctx, vao, VERT_ATTRIB_GENERIC(first + i),
+ vbo, offsets[i], strides[i]);
+ }
+
+ _mesa_end_bufferobj_lookups(ctx);
+}
+
+
+void GLAPIENTRY
+_mesa_BindVertexBuffers(GLuint first, GLsizei count, const GLuint *buffers,
+ const GLintptr *offsets, const GLsizei *strides)
+{
+ GET_CURRENT_CONTEXT(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;
+ }
+
+ vertex_array_vertex_buffers(ctx, ctx->Array.VAO, first, count,
+ buffers, offsets, strides,
+ "glBindVertexBuffers");
+}
+
+
+void GLAPIENTRY
+_mesa_VertexArrayVertexBuffers(GLuint vaobj, GLuint first, GLsizei count,
+ const GLuint *buffers,
+ const GLintptr *offsets, const GLsizei *strides)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_vertex_array_object *vao;
+
+ /* The ARB_direct_state_access specification says:
+ *
+ * "An INVALID_OPERATION error is generated by VertexArrayVertexBuffer
+ * if <vaobj> is not [compatibility profile: zero or] the name of an
+ * existing vertex array object."
+ */
+ vao = _mesa_lookup_vao_err(ctx, vaobj, "glVertexArrayVertexBuffers");
+ if (!vao)
+ return;
+
+ vertex_array_vertex_buffers(ctx, vao, first, count,
+ buffers, offsets, strides,
+ "glVertexArrayVertexBuffers");
+}
+
+
+static void
+vertex_attrib_format(GLuint attribIndex, GLint size, GLenum type,
+ GLboolean normalized, GLboolean integer,
+ GLboolean doubles, GLbitfield legalTypes,
+ GLsizei maxSize, GLuint relativeOffset,
+ const char *func)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ /* The ARB_vertex_attrib_binding spec says:
+ *
+ * "An INVALID_OPERATION error is generated under any of the following
+ * conditions:
+ * - if no vertex array object is currently bound (see section 2.10);
+ * - ..."
+ *
+ * This error condition only applies to VertexAttribFormat and
+ * VertexAttribIFormat in the extension spec, but we assume that this
+ * is an oversight. In the OpenGL 4.3 (Core Profile) spec, it applies
+ * to all three functions.
+ */
+ if ((ctx->API == API_OPENGL_CORE || _mesa_is_gles31(ctx)) &&
+ ctx->Array.VAO == ctx->Array.DefaultVAO) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(No array object bound)", func);
+ return;
+ }
+
+ /* The ARB_vertex_attrib_binding spec says:
+ *
+ * "The error INVALID_VALUE is generated if index is greater than or equal
+ * to the value of MAX_VERTEX_ATTRIBS."
+ */
+ if (attribIndex >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(attribindex=%u > "
+ "GL_MAX_VERTEX_ATTRIBS)",
+ func, attribIndex);
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, 0);
+
+ update_array_format(ctx, func, ctx->Array.VAO,
+ VERT_ATTRIB_GENERIC(attribIndex),
+ legalTypes, 1, maxSize, size, type,
+ normalized, integer, doubles, relativeOffset);
+}
+
+
+void GLAPIENTRY
+_mesa_VertexAttribFormat(GLuint attribIndex, GLint size, GLenum type,
+ GLboolean normalized, GLuint relativeOffset)
+{
+ vertex_attrib_format(attribIndex, size, type, normalized,
+ GL_FALSE, GL_FALSE, ATTRIB_FORMAT_TYPES_MASK,
+ BGRA_OR_4, relativeOffset,
+ "glVertexAttribFormat");
+}
+
+
+void GLAPIENTRY
+_mesa_VertexAttribIFormat(GLuint attribIndex, GLint size, GLenum type,
+ GLuint relativeOffset)
+{
+ vertex_attrib_format(attribIndex, size, type, GL_FALSE,
+ GL_TRUE, GL_FALSE, ATTRIB_IFORMAT_TYPES_MASK, 4,
+ relativeOffset, "glVertexAttribIFormat");
+}
+
+
+void GLAPIENTRY
+_mesa_VertexAttribLFormat(GLuint attribIndex, GLint size, GLenum type,
+ GLuint relativeOffset)
+{
+ vertex_attrib_format(attribIndex, size, type, GL_FALSE, GL_FALSE,
+ GL_TRUE, ATTRIB_LFORMAT_TYPES_MASK, 4,
+ relativeOffset, "glVertexAttribLFormat");
+}
+
+
+static void
+vertex_array_attrib_format(GLuint vaobj, GLuint attribIndex, GLint size,
+ GLenum type, GLboolean normalized,
+ GLboolean integer, GLboolean doubles,
+ GLbitfield legalTypes, GLsizei maxSize,
+ GLuint relativeOffset, const char *func)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_vertex_array_object *vao;
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ /* The ARB_direct_state_access spec says:
+ *
+ * "An INVALID_OPERATION error is generated by VertexArrayAttrib*Format
+ * if <vaobj> is not [compatibility profile: zero or] the name of an
+ * existing vertex array object."
+ */
+ vao = _mesa_lookup_vao_err(ctx, vaobj, func);
+ if (!vao)
+ return;
+
+ /* The ARB_vertex_attrib_binding spec says:
+ *
+ * "The error INVALID_VALUE is generated if index is greater than or equal
+ * to the value of MAX_VERTEX_ATTRIBS."
+ */
+ if (attribIndex >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(attribindex=%u > GL_MAX_VERTEX_ATTRIBS)",
+ func, attribIndex);
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, 0);
+
+ update_array_format(ctx, func, vao,
+ VERT_ATTRIB_GENERIC(attribIndex),
+ legalTypes, 1, maxSize, size, type, normalized,
+ integer, doubles, relativeOffset);
+}
+
+
+void GLAPIENTRY
+_mesa_VertexArrayAttribFormat(GLuint vaobj, GLuint attribIndex, GLint size,
+ GLenum type, GLboolean normalized,
+ GLuint relativeOffset)
+{
+ vertex_array_attrib_format(vaobj, attribIndex, size, type, normalized,
+ GL_FALSE, GL_FALSE, ATTRIB_FORMAT_TYPES_MASK,
+ BGRA_OR_4, relativeOffset,
+ "glVertexArrayAttribFormat");
+}
+
+
+void GLAPIENTRY
+_mesa_VertexArrayAttribIFormat(GLuint vaobj, GLuint attribIndex,
+ GLint size, GLenum type,
+ GLuint relativeOffset)
+{
+ vertex_array_attrib_format(vaobj, attribIndex, size, type, GL_FALSE,
+ GL_TRUE, GL_FALSE, ATTRIB_IFORMAT_TYPES_MASK,
+ 4, relativeOffset,
+ "glVertexArrayAttribIFormat");
+}
+
+
+void GLAPIENTRY
+_mesa_VertexArrayAttribLFormat(GLuint vaobj, GLuint attribIndex,
+ GLint size, GLenum type,
+ GLuint relativeOffset)
+{
+ vertex_array_attrib_format(vaobj, attribIndex, size, type, GL_FALSE,
+ GL_FALSE, GL_TRUE, ATTRIB_LFORMAT_TYPES_MASK,
+ 4, relativeOffset,
+ "glVertexArrayAttribLFormat");
+}
+
+
+static void
+vertex_array_attrib_binding(struct gl_context *ctx,
+ struct gl_vertex_array_object *vao,
+ GLuint attribIndex, GLuint bindingIndex,
+ const char *func)
+{
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ /* The ARB_vertex_attrib_binding spec says:
+ *
+ * "<attribindex> must be less than the value of MAX_VERTEX_ATTRIBS and
+ * <bindingindex> must be less than the value of
+ * MAX_VERTEX_ATTRIB_BINDINGS, otherwise the error INVALID_VALUE
+ * is generated."
+ */
+ if (attribIndex >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(attribindex=%u >= "
+ "GL_MAX_VERTEX_ATTRIBS)",
+ func, attribIndex);
+ return;
+ }
+
+ if (bindingIndex >= ctx->Const.MaxVertexAttribBindings) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(bindingindex=%u >= "
+ "GL_MAX_VERTEX_ATTRIB_BINDINGS)",
+ func, bindingIndex);
+ return;
+ }
+
+ assert(VERT_ATTRIB_GENERIC(attribIndex) < ARRAY_SIZE(vao->VertexAttrib));
+
+ vertex_attrib_binding(ctx, vao,
+ VERT_ATTRIB_GENERIC(attribIndex),
+ VERT_ATTRIB_GENERIC(bindingIndex));
+}
+
+
+void GLAPIENTRY
+_mesa_VertexAttribBinding(GLuint attribIndex, GLuint bindingIndex)
+{
+ GET_CURRENT_CONTEXT(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 || _mesa_is_gles31(ctx)) &&
+ ctx->Array.VAO == ctx->Array.DefaultVAO) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glVertexAttribBinding(No array object bound)");
+ return;
+ }
+
+ vertex_array_attrib_binding(ctx, ctx->Array.VAO,
+ attribIndex, bindingIndex,
+ "glVertexAttribBinding");
+}
+
+
+void GLAPIENTRY
+_mesa_VertexArrayAttribBinding(GLuint vaobj, GLuint attribIndex, GLuint bindingIndex)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_vertex_array_object *vao;
+
+ /* The ARB_direct_state_access specification says:
+ *
+ * "An INVALID_OPERATION error is generated by VertexArrayAttribBinding
+ * if <vaobj> is not [compatibility profile: zero or] the name of an
+ * existing vertex array object."
+ */
+ vao = _mesa_lookup_vao_err(ctx, vaobj, "glVertexArrayAttribBinding");
+ if (!vao)
+ return;
+
+ vertex_array_attrib_binding(ctx, vao, attribIndex, bindingIndex,
+ "glVertexArrayAttribBinding");
+}
+
+
+static void
+vertex_array_binding_divisor(struct gl_context *ctx,
+ struct gl_vertex_array_object *vao,
+ GLuint bindingIndex, GLuint divisor,
+ const char *func)
+{
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ if (!ctx->Extensions.ARB_instanced_arrays) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s()", func);
+ return;
+ }
+
+ /* The ARB_vertex_attrib_binding spec says:
+ *
+ * "An INVALID_VALUE error is generated if <bindingindex> is greater
+ * than or equal to the value of MAX_VERTEX_ATTRIB_BINDINGS."
+ */
+ if (bindingIndex >= ctx->Const.MaxVertexAttribBindings) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(bindingindex=%u > "
+ "GL_MAX_VERTEX_ATTRIB_BINDINGS)",
+ func, bindingIndex);
+ return;
+ }
+
+ vertex_binding_divisor(ctx, vao, VERT_ATTRIB_GENERIC(bindingIndex), divisor);
+}
+
+
+void GLAPIENTRY
+_mesa_VertexBindingDivisor(GLuint bindingIndex, GLuint divisor)
+{
+ GET_CURRENT_CONTEXT(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 || _mesa_is_gles31(ctx)) &&
+ ctx->Array.VAO == ctx->Array.DefaultVAO) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glVertexBindingDivisor(No array object bound)");
+ return;