[Mesa-dev] [PATCH 05/11] mesa: Add ARB_vertex_attrib_binding

Ian Romanick idr at freedesktop.org
Mon Nov 4 13:20:50 PST 2013


On 10/28/2013 03:33 PM, Fredrik Höglund wrote:
> update_array() and update_array_format() are changed to update the new
> attrib and binding states, and the client arrays become derived state.

I don't think we should enable the extension until after the other
patches.  Otherwise people can encounter spurious piglit failures while
bisecting other problems.  I'm sure that there are some of your piglit
tests that would fail at this point in the series... right?

> ---
>  src/mesa/main/api_arrayelt.c |    7 +
>  src/mesa/main/arrayobj.c     |   63 ++++--
>  src/mesa/main/arrayobj.h     |    5 +
>  src/mesa/main/attrib.c       |    5 +-
>  src/mesa/main/bufferobj.c    |    4 +-
>  src/mesa/main/context.c      |    4 +
>  src/mesa/main/extensions.c   |    1 +
>  src/mesa/main/mtypes.h       |   50 ++++-
>  src/mesa/main/state.c        |    3 +
>  src/mesa/main/varray.c       |  490 +++++++++++++++++++++++++++++++++++++++---
>  src/mesa/main/varray.h       |   48 +++++
>  11 files changed, 629 insertions(+), 51 deletions(-)
> 
> diff --git a/src/mesa/main/api_arrayelt.c b/src/mesa/main/api_arrayelt.c
> index 5a316f0..6822465 100644
> --- a/src/mesa/main/api_arrayelt.c
> +++ b/src/mesa/main/api_arrayelt.c
> @@ -35,6 +35,7 @@
>   */
>  
>  #include "glheader.h"
> +#include "arrayobj.h"
>  #include "api_arrayelt.h"
>  #include "bufferobj.h"
>  #include "context.h"
> @@ -1485,6 +1486,12 @@ _ae_update_state(struct gl_context *ctx)
>  
>     actx->nr_vbos = 0;
>  
> +   if (arrayObj->NewArrays) {
> +      /* update the derived client arrays */
> +      _mesa_update_array_object_client_arrays(ctx, arrayObj);
> +      arrayObj->NewArrays = 0;
> +   }
> +
>     /* conventional vertex arrays */
>     if (arrayObj->_VertexAttrib[VERT_ATTRIB_COLOR_INDEX].Enabled) {
>        aa->array = &arrayObj->_VertexAttrib[VERT_ATTRIB_COLOR_INDEX];
> diff --git a/src/mesa/main/arrayobj.c b/src/mesa/main/arrayobj.c
> index 79a54fa..dbf8fdc 100644
> --- a/src/mesa/main/arrayobj.c
> +++ b/src/mesa/main/arrayobj.c
> @@ -72,7 +72,7 @@ _mesa_lookup_arrayobj(struct gl_context *ctx, GLuint id)
>  
>  
>  /**
> - * For all the vertex arrays in the array object, unbind any pointers
> + * For all the vertex binding points in the array object, unbind any pointers
>   * to any buffer objects (VBOs).
>   * This is done just prior to array object destruction.
>   */
> @@ -81,6 +81,9 @@ unbind_array_object_vbos(struct gl_context *ctx, struct gl_array_object *obj)
>  {
>     GLuint i;
>  
> +   for (i = 0; i < Elements(obj->VertexBinding); i++)
> +      _mesa_reference_buffer_object(ctx, &obj->VertexBinding[i].BufferObj, NULL);
> +
>     for (i = 0; i < Elements(obj->_VertexAttrib); i++)
>        _mesa_reference_buffer_object(ctx, &obj->_VertexAttrib[i].BufferObj, NULL);
>  }
> @@ -181,20 +184,30 @@ _mesa_reference_array_object_(struct gl_context *ctx,
>  
>  static void
>  init_array(struct gl_context *ctx,
> -           struct gl_client_array *array, GLint size, GLint type)
> +           struct gl_array_object *obj, GLuint index, GLint size, GLint type)
>  {
> +   struct gl_vertex_attrib_array *array = &obj->VertexAttrib[index];
> +   struct gl_vertex_buffer_binding *binding = &obj->VertexBinding[index];
> +
>     array->Size = size;
>     array->Type = type;
>     array->Format = GL_RGBA; /* only significant for GL_EXT_vertex_array_bgra */
>     array->Stride = 0;
> -   array->StrideB = 0;
>     array->Ptr = NULL;
> +   array->RelativeOffset = 0;
>     array->Enabled = GL_FALSE;
>     array->Normalized = GL_FALSE;
>     array->Integer = GL_FALSE;
>     array->_ElementSize = size * _mesa_sizeof_type(type);
> +   array->VertexBinding = index;
> +
> +   binding->Offset = 0;
> +   binding->Stride = array->_ElementSize;
> +   binding->BufferObj = NULL;
> +   binding->_BoundArrays = BITFIELD64_BIT(index);
> +
>     /* Vertex array buffers */
> -   _mesa_reference_buffer_object(ctx, &array->BufferObj,
> +   _mesa_reference_buffer_object(ctx, &binding->BufferObj,
>                                   ctx->Shared->NullBufferObj);
>  }
>  
> @@ -218,28 +231,28 @@ _mesa_initialize_array_object( struct gl_context *ctx,
>     for (i = 0; i < Elements(obj->_VertexAttrib); i++) {
>        switch (i) {
>        case VERT_ATTRIB_WEIGHT:
> -         init_array(ctx, &obj->_VertexAttrib[VERT_ATTRIB_WEIGHT], 1, GL_FLOAT);
> +         init_array(ctx, obj, VERT_ATTRIB_WEIGHT, 1, GL_FLOAT);
>           break;
>        case VERT_ATTRIB_NORMAL:
> -         init_array(ctx, &obj->_VertexAttrib[VERT_ATTRIB_NORMAL], 3, GL_FLOAT);
> +         init_array(ctx, obj, VERT_ATTRIB_NORMAL, 3, GL_FLOAT);
>           break;
>        case VERT_ATTRIB_COLOR1:
> -         init_array(ctx, &obj->_VertexAttrib[VERT_ATTRIB_COLOR1], 3, GL_FLOAT);
> +         init_array(ctx, obj, VERT_ATTRIB_COLOR1, 3, GL_FLOAT);
>           break;
>        case VERT_ATTRIB_FOG:
> -         init_array(ctx, &obj->_VertexAttrib[VERT_ATTRIB_FOG], 1, GL_FLOAT);
> +         init_array(ctx, obj, VERT_ATTRIB_FOG, 1, GL_FLOAT);
>           break;
>        case VERT_ATTRIB_COLOR_INDEX:
> -         init_array(ctx, &obj->_VertexAttrib[VERT_ATTRIB_COLOR_INDEX], 1, GL_FLOAT);
> +         init_array(ctx, obj, VERT_ATTRIB_COLOR_INDEX, 1, GL_FLOAT);
>           break;
>        case VERT_ATTRIB_EDGEFLAG:
> -         init_array(ctx, &obj->_VertexAttrib[VERT_ATTRIB_EDGEFLAG], 1, GL_BOOL);
> +         init_array(ctx, obj, VERT_ATTRIB_EDGEFLAG, 1, GL_BOOL);
>           break;
>        case VERT_ATTRIB_POINT_SIZE:
> -         init_array(ctx, &obj->_VertexAttrib[VERT_ATTRIB_POINT_SIZE], 1, GL_FLOAT);
> +         init_array(ctx, obj, VERT_ATTRIB_POINT_SIZE, 1, GL_FLOAT);
>           break;
>        default:
> -         init_array(ctx, &obj->_VertexAttrib[i], 4, GL_FLOAT);
> +         init_array(ctx, obj, i, 4, GL_FLOAT);
>           break;
>        }
>     }
> @@ -322,6 +335,32 @@ _mesa_update_array_object_max_element(struct gl_context *ctx,
>  }
>  
>  
> +/**
> + * Updates the derived gl_client_arrays when a gl_vertex_attrib_array
> + * or a gl_vertex_buffer_binding has changed.
> + */
> +void
> +_mesa_update_array_object_client_arrays(struct gl_context *ctx, struct gl_array_object *arrayObj)
> +{
> +   GLbitfield64 arrays = arrayObj->NewArrays;
> +
> +   while (arrays) {
> +      struct gl_client_array *client_array;
> +      struct gl_vertex_attrib_array *attrib_array;
> +      struct gl_vertex_buffer_binding *buffer_binding;
> +
> +      GLint attrib = ffsll(arrays) - 1;
> +      arrays ^= BITFIELD64_BIT(attrib);
> +
> +      attrib_array = &arrayObj->VertexAttrib[attrib];
> +      buffer_binding = &arrayObj->VertexBinding[attrib_array->VertexBinding];
> +      client_array = &arrayObj->_VertexAttrib[attrib];
> +
> +      _mesa_update_client_array(ctx, client_array, attrib_array, buffer_binding);
> +   }
> +}
> +
> +
>  /**********************************************************************/
>  /* API Functions                                                      */
>  /**********************************************************************/
> diff --git a/src/mesa/main/arrayobj.h b/src/mesa/main/arrayobj.h
> index 492ef35..7c37202 100644
> --- a/src/mesa/main/arrayobj.h
> +++ b/src/mesa/main/arrayobj.h
> @@ -78,6 +78,11 @@ extern void
>  _mesa_update_array_object_max_element(struct gl_context *ctx,
>                                        struct gl_array_object *arrayObj);
>  
> +extern void
> +_mesa_update_array_object_client_arrays(struct gl_context *ctx,
> +                                        struct gl_array_object *arrayObj);
> +
> +
>  /** Returns the bitmask of all enabled arrays in fixed function mode.
>   *
>   *  In fixed function mode only the traditional fixed function arrays
> diff --git a/src/mesa/main/attrib.c b/src/mesa/main/attrib.c
> index 87c7f66..c9332bd 100644
> --- a/src/mesa/main/attrib.c
> +++ b/src/mesa/main/attrib.c
> @@ -1369,8 +1369,11 @@ copy_array_object(struct gl_context *ctx,
>     /* In theory must be the same anyway, but on recreate make sure it matches */
>     dest->ARBsemantics = src->ARBsemantics;
>  
> -   for (i = 0; i < Elements(src->_VertexAttrib); i++)
> +   for (i = 0; i < Elements(src->_VertexAttrib); i++) {
>        _mesa_copy_client_array(ctx, &dest->_VertexAttrib[i], &src->_VertexAttrib[i]);
> +      _mesa_copy_vertex_attrib_array(ctx, &dest->VertexAttrib[i], &src->VertexAttrib[i]);
> +      _mesa_copy_vertex_buffer_binding(ctx, &dest->VertexBinding[i], &src->VertexBinding[i]);
> +   }
>  
>     /* _Enabled must be the same than on push */
>     dest->_Enabled = src->_Enabled;
> diff --git a/src/mesa/main/bufferobj.c b/src/mesa/main/bufferobj.c
> index d4c4cdd..cab7937 100644
> --- a/src/mesa/main/bufferobj.c
> +++ b/src/mesa/main/bufferobj.c
> @@ -857,8 +857,8 @@ _mesa_DeleteBuffers(GLsizei n, const GLuint *ids)
>           }
>  
>           /* unbind any vertex pointers bound to this buffer */
> -         for (j = 0; j < Elements(arrayObj->_VertexAttrib); j++) {
> -            unbind(ctx, &arrayObj->_VertexAttrib[j].BufferObj, bufObj);
> +         for (j = 0; j < Elements(arrayObj->VertexBinding); j++) {
> +            unbind(ctx, &arrayObj->VertexBinding[j].BufferObj, bufObj);
>           }
>  
>           if (ctx->Array.ArrayBufferObj == bufObj) {
> diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c
> index 0d1f71c..70b2453 100644
> --- a/src/mesa/main/context.c
> +++ b/src/mesa/main/context.c
> @@ -669,6 +669,10 @@ _mesa_init_constants(struct gl_context *ctx)
>     ctx->Const.MaxColorTextureSamples = 1;
>     ctx->Const.MaxDepthTextureSamples = 1;
>     ctx->Const.MaxIntegerSamples = 1;
> +
> +   /* GL_ARB_vertex_attrib_binding */
> +   ctx->Const.MaxVertexAttribRelativeOffset = 2047;
> +   ctx->Const.MaxVertexAttribBindings = MAX_VERTEX_GENERIC_ATTRIBS;
>  }
>  
>  
> diff --git a/src/mesa/main/extensions.c b/src/mesa/main/extensions.c
> index 00d65cc..2c3fc07 100644
> --- a/src/mesa/main/extensions.c
> +++ b/src/mesa/main/extensions.c
> @@ -163,6 +163,7 @@ static const struct extension extension_table[] = {
>     { "GL_ARB_uniform_buffer_object",               o(ARB_uniform_buffer_object),               GL,             2009 },
>     { "GL_ARB_vertex_array_bgra",                   o(EXT_vertex_array_bgra),                   GL,             2008 },
>     { "GL_ARB_vertex_array_object",                 o(dummy_true),                              GL,             2006 },
> +   { "GL_ARB_vertex_attrib_binding",               o(dummy_true),                              GL,             2012 },
>     { "GL_ARB_vertex_buffer_object",                o(dummy_true),                              GLL,            2003 },
>     { "GL_ARB_vertex_program",                      o(ARB_vertex_program),                      GLL,            2002 },
>     { "GL_ARB_vertex_shader",                       o(ARB_vertex_shader),                       GL,             2002 },
> diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
> index b0d638f..aac81c3 100644
> --- a/src/mesa/main/mtypes.h
> +++ b/src/mesa/main/mtypes.h
> @@ -1466,6 +1466,44 @@ struct gl_client_array
>  
>  
>  /**
> + * Vertex attribute array as seen by the client.
> + *
> + * Contains the size, type, format and normalization flag,
> + * along with the index of a vertex buffer binding point.
> + *
> + * Note that the Stride field corresponds to VERTEX_ATTRIB_ARRAY_STRIDE
> + * and is only present for backwards compatibility reasons.
> + * Rendering always uses VERTEX_BINDING_STRIDE.
> + * The gl*Pointer() functions will set VERTEX_ATTRIB_ARRAY_STRIDE
> + * and VERTEX_BINDING_STRIDE to the same value, while
> + * glBindVertexBuffer() will only set VERTEX_BINDING_STRIDE.
> + */
> +struct gl_vertex_attrib_array
> +{
> +   GLint Size;              /**< Components per element (1,2,3,4) */
> +   GLenum Type;             /**< Datatype: GL_FLOAT, GL_INT, etc */
> +   GLenum Format;           /**< Default: GL_RGBA, but may be GL_BGRA */
> +   GLsizei Stride;          /**< Stride as specified with gl*Pointer() */
> +   const GLubyte *Ptr;      /**< Points to client array data. Not used when a VBO is bound */
> +   GLintptr RelativeOffset; /**< Offset of the first element relative to the binding offset */
> +   GLboolean Enabled;       /**< Whether the array is enabled */
> +   GLboolean Normalized;    /**< Fixed-point values are normalized when converted to floats */
> +   GLboolean Integer;       /**< Fixed-point values are not converted to floats */
> +   GLuint _ElementSize;     /**< Size of each element in bytes */
> +   GLuint VertexBinding;    /**< Vertex buffer binding */
> +};
> +
> +struct gl_vertex_buffer_binding
> +{
> +   GLintptr Offset;                    /**< User-specified offset */
> +   GLsizei Stride;                     /**< User-specified stride */
> +   GLuint InstanceDivisor;             /**< GL_ARB_instanced_arrays */
> +   struct gl_buffer_object *BufferObj; /**< GL_ARB_vertex_buffer_object */
> +   GLbitfield64 _BoundArrays;          /**< Arrays bound to this binding point */
> +};
> +
> +
> +/**
>   * Collection of vertex arrays.  Defined by the GL_APPLE_vertex_array_object
>   * extension, but a nice encapsulation in any case.
>   */
> @@ -1499,9 +1537,15 @@ struct gl_array_object
>      */
>     GLboolean EverBound;
>  
> -   /** Vertex attribute arrays */
> +   /** Derived vertex attribute arrays */
>     struct gl_client_array _VertexAttrib[VERT_ATTRIB_MAX];
>  
> +   /** Vertex attribute arrays */
> +   struct gl_vertex_attrib_array VertexAttrib[VERT_ATTRIB_MAX];
> +
> +   /** Vertex buffer bindings */
> +   struct gl_vertex_buffer_binding VertexBinding[VERT_ATTRIB_MAX];
> +
>     /** Mask of VERT_BIT_* values indicating which arrays are enabled */
>     GLbitfield64 _Enabled;
>  
> @@ -3169,6 +3213,10 @@ struct gl_constants
>     GLint MaxColorTextureSamples;
>     GLint MaxDepthTextureSamples;
>     GLint MaxIntegerSamples;
> +
> +   /** GL_ARB_vertex_attrib_binding */
> +   GLint MaxVertexAttribRelativeOffset;
> +   GLint MaxVertexAttribBindings;
>  };
>  
>  
> diff --git a/src/mesa/main/state.c b/src/mesa/main/state.c
> index bf21631..33070b7 100644
> --- a/src/mesa/main/state.c
> +++ b/src/mesa/main/state.c
> @@ -410,6 +410,9 @@ _mesa_update_state_locked( struct gl_context *ctx )
>        new_prog_state |= update_program( ctx );
>     }
>  
> +   if (new_state & _NEW_ARRAY)
> +      _mesa_update_array_object_client_arrays(ctx, ctx->Array.ArrayObj);
> +
>     if (ctx->Const.CheckArrayBounds &&
>         new_state & (_NEW_ARRAY | _NEW_PROGRAM | _NEW_BUFFER_OBJECT)) {
>        _mesa_update_array_object_max_element(ctx, ctx->Array.ArrayObj);
> diff --git a/src/mesa/main/varray.c b/src/mesa/main/varray.c
> index f046fd6..e15081a 100644
> --- a/src/mesa/main/varray.c
> +++ b/src/mesa/main/varray.c
> @@ -102,20 +102,113 @@ type_to_bit(const struct gl_context *ctx, GLenum type)
>  }
>  
>  
> +static inline struct gl_vertex_attrib_array *
> +gl_vertex_attrib_array(struct gl_context *ctx, GLuint index)
> +{
> +   ASSERT(index < Elements(arrayObj->VertexAttrib));
> +   return &ctx->Array.ArrayObj->VertexAttrib[index];
> +}
> +
> +
> +static inline struct gl_vertex_buffer_binding *
> +gl_vertex_buffer_binding(struct gl_context *ctx, GLuint index)
> +{
> +   ASSERT(index < Elements(arrayObj->VertexBinding));
> +   return &ctx->Array.ArrayObj->VertexBinding[index];
> +}
> +
> +
> +/**
> + * Sets the VertexBinding field in the vertex attribute given by attribIndex.
> + */
> +static void
> +vertex_attrib_binding(struct gl_context *ctx, GLuint attribIndex,
> +                      GLuint bindingIndex)
> +{
> +   struct gl_vertex_attrib_array *array =
> +               gl_vertex_attrib_array(ctx, attribIndex);
> +
> +   if (array->VertexBinding != bindingIndex) {
> +      const GLbitfield64 array_bit = VERT_BIT(attribIndex);
> +      struct gl_vertex_buffer_binding *new_binding =
> +                  gl_vertex_buffer_binding(ctx, bindingIndex);
> +      struct gl_vertex_buffer_binding *old_binding =
> +                  gl_vertex_buffer_binding(ctx, array->VertexBinding);
> +
> +      FLUSH_VERTICES(ctx, _NEW_ARRAY);
> +
> +      array->VertexBinding = bindingIndex;
> +
> +      old_binding->_BoundArrays &= ~array_bit;
> +      new_binding->_BoundArrays |= array_bit;
> +
> +      ctx->Array.ArrayObj->NewArrays |= array_bit;
> +   }
> +}
> +
> +
> +/**
> + * Binds a buffer object to the vertex buffer binding point given by index,
> + * and sets the Offset and Stride fields.
> + */
> +static void
> +bind_vertex_buffer(struct gl_context *ctx, GLuint index,
> +                   struct gl_buffer_object *vbo,
> +                   GLintptr offset, GLsizei stride)
> +{
> +   struct gl_vertex_buffer_binding *binding =
> +               gl_vertex_buffer_binding(ctx, index);
> +
> +   if (binding->BufferObj != vbo ||
> +       binding->Offset != offset ||
> +       binding->Stride != stride) {
> +
> +      FLUSH_VERTICES(ctx, _NEW_ARRAY);
> +
> +      _mesa_reference_buffer_object(ctx, &binding->BufferObj, vbo);
> +
> +      binding->Offset = offset;
> +      binding->Stride = stride;
> +
> +      ctx->Array.ArrayObj->NewArrays |= binding->_BoundArrays;
> +   }
> +}
> +
> +
> +/**
> + * Sets the InstanceDivisor field in the vertex buffer binding point
> + * given by bindingIndex.
> + */
> +static void
> +vertex_binding_divisor(struct gl_context *ctx, GLuint bindingIndex,
> +                       GLuint divisor)
> +{
> +   struct gl_vertex_buffer_binding *binding =
> +               gl_vertex_buffer_binding(ctx, bindingIndex);
> +
> +   if (binding->InstanceDivisor != divisor) {
> +      FLUSH_VERTICES(ctx, _NEW_ARRAY);
> +      binding->InstanceDivisor = divisor;
> +      ctx->Array.ArrayObj->NewArrays |= binding->_BoundArrays;
> +   }
> +}
> +
> +
>  /**
>   * Does error checking and updates the format in an attrib array.
>   *
> - * Called by update_array().
> + * Called by update_array() and VertexAttrib*Format().
>   *
> - * \param func        Name of calling function used for error reporting
> - * \param attrib      The index of the attribute array
> - * \param legalTypes  Bitmask of *_BIT above indicating legal datatypes
> - * \param sizeMin     Min allowable size value
> - * \param sizeMax     Max allowable size value (may also be BGRA_OR_4)
> - * \param size        Components per element (1, 2, 3 or 4)
> - * \param type        Datatype of each component (GL_FLOAT, GL_INT, etc)
> - * \param normalized  Whether integer types are converted to floats in [-1, 1]
> - * \param integer     Integer-valued values (will not be normalized to [-1, 1])
> + * \param func         Name of calling function used for error reporting
> + * \param attrib       The index of the attribute array
> + * \param legalTypes   Bitmask of *_BIT above indicating legal datatypes
> + * \param sizeMin      Min allowable size value
> + * \param sizeMax      Max allowable size value (may also be BGRA_OR_4)
> + * \param size         Components per element (1, 2, 3 or 4)
> + * \param type         Datatype of each component (GL_FLOAT, GL_INT, etc)
> + * \param normalized   Whether integer types are converted to floats in [-1, 1]
> + * \param integer      Integer-valued values (will not be normalized to [-1, 1])
> + * \param relativeOffset Offset of the first element relative to the binding offset.
>   */
>  static GLboolean
>  update_array_format(struct gl_context *ctx,
> @@ -123,9 +216,10 @@ update_array_format(struct gl_context *ctx,
>                      GLuint attrib, GLbitfield legalTypesMask,
>                      GLint sizeMin, GLint sizeMax,
>                      GLint size, GLenum type,
> -                    GLboolean normalized, GLboolean integer)
> +                    GLboolean normalized, GLboolean integer,
> +                    GLuint relativeOffset)
>  {
> -   struct gl_client_array *array;
> +   struct gl_vertex_attrib_array *array;
>     GLbitfield typeBit;
>     GLuint elementSize;
>     GLenum format = GL_RGBA;
> @@ -224,19 +318,36 @@ update_array_format(struct gl_context *ctx,
>        return GL_FALSE;
>     }
>  
> +   /* The ARB_vertex_attrib_binding_spec says:
> +    *
> +    *   An INVALID_VALUE error is generated if <relativeoffset> is larger than
> +    *   the value of MAX_VERTEX_ATTRIB_RELATIVE_OFFSET.
> +    */
> +   if (relativeOffset > ctx->Const.MaxVertexAttribRelativeOffset) {
> +      _mesa_error(ctx, GL_INVALID_VALUE,
> +                  "%s(relativeOffset=%d > "
> +                  "GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET)",
> +                  func, relativeOffset);
> +      return GL_FALSE;
> +   }
> +
>     ASSERT(size <= 4);
>  
>     elementSize = _mesa_bytes_per_vertex_attrib(size, type);
>     assert(elementSize != -1);
>  
> -   array = &ctx->Array.ArrayObj->_VertexAttrib[attrib];
> +   array = gl_vertex_attrib_array(ctx, attrib);
>     array->Size = size;
>     array->Type = type;
>     array->Format = format;
>     array->Normalized = normalized;
>     array->Integer = integer;
> +   array->RelativeOffset = relativeOffset;
>     array->_ElementSize = elementSize;
>  
> +   ctx->Array.ArrayObj->NewArrays |= VERT_BIT(attrib);
> +   ctx->NewState |= _NEW_ARRAY;
> +
>     return GL_TRUE;
>  }
>  
> @@ -266,7 +377,8 @@ update_array(struct gl_context *ctx,
>               GLboolean normalized, GLboolean integer,
>               const GLvoid *ptr)
>  {
> -   struct gl_client_array *array;
> +   struct gl_vertex_attrib_array *array;
> +   GLsizei effectiveStride;
>  
>     /* Page 407 (page 423 of the PDF) of the OpenGL 3.0 spec says:
>      *
> @@ -286,7 +398,7 @@ update_array(struct gl_context *ctx,
>     }
>  
>     if (!update_array_format(ctx, func, attrib, legalTypesMask, sizeMin, sizeMax,
> -                            size, type, normalized, integer)) {
> +                            size, type, normalized, integer, 0)) {
>        return;
>     }
>  
> @@ -313,16 +425,18 @@ update_array(struct gl_context *ctx,
>        return;
>     }
>  
> -   array = &ctx->Array.ArrayObj->_VertexAttrib[attrib];
> -   array->Stride = stride;
> -   array->StrideB = stride ? stride : array->_ElementSize;
> -   array->Ptr = (const GLubyte *) ptr;
> +   /* Reset the vertex attrib binding */
> +   vertex_attrib_binding(ctx, attrib, attrib);
>  
> -   _mesa_reference_buffer_object(ctx, &array->BufferObj,
> -                                 ctx->Array.ArrayBufferObj);
> +   /* The Stride and Ptr fields are not set by update_array_format() */
> +   array = gl_vertex_attrib_array(ctx, attrib);
> +   array->Stride = stride;
> +   array->Ptr = (const GLvoid *) ptr;
>  
> -   ctx->NewState |= _NEW_ARRAY;
> -   ctx->Array.ArrayObj->NewArrays |= VERT_BIT(attrib);
> +   /* Update the vertex buffer binding */
> +   effectiveStride = stride != 0 ? stride : array->_ElementSize;
> +   bind_vertex_buffer(ctx, attrib, ctx->Array.ArrayBufferObj,
> +                      (GLintptr) ptr, effectiveStride);
>  }
>  
>  
> @@ -569,10 +683,10 @@ _mesa_EnableVertexAttribArray(GLuint index)
>  
>     ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(arrayObj->_VertexAttrib));
>  
> -   if (!arrayObj->_VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled) {
> +   if (!arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled) {
>        /* was disabled, now being enabled */
>        FLUSH_VERTICES(ctx, _NEW_ARRAY);
> -      arrayObj->_VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled = GL_TRUE;
> +      arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled = GL_TRUE;
>        arrayObj->_Enabled |= VERT_BIT_GENERIC(index);
>        arrayObj->NewArrays |= VERT_BIT_GENERIC(index);
>     }
> @@ -595,10 +709,10 @@ _mesa_DisableVertexAttribArray(GLuint index)
>  
>     ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(arrayObj->_VertexAttrib));
>  
> -   if (arrayObj->_VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled) {
> +   if (arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled) {
>        /* was enabled, now being disabled */
>        FLUSH_VERTICES(ctx, _NEW_ARRAY);
> -      arrayObj->_VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled = GL_FALSE;
> +      arrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Enabled = GL_FALSE;
>        arrayObj->_Enabled &= ~VERT_BIT_GENERIC(index);
>        arrayObj->NewArrays |= VERT_BIT_GENERIC(index);
>     }
> @@ -1180,9 +1294,10 @@ _mesa_PrimitiveRestartIndex(GLuint index)
>  void GLAPIENTRY
>  _mesa_VertexAttribDivisor(GLuint index, GLuint divisor)
>  {
> -   struct gl_client_array *array;
>     GET_CURRENT_CONTEXT(ctx);
>  
> +   const GLuint genericIndex = VERT_ATTRIB_GENERIC(index);
> +
>     if (!ctx->Extensions.ARB_instanced_arrays) {
>        _mesa_error(ctx, GL_INVALID_OPERATION, "glVertexAttribDivisor()");
>        return;
> @@ -1194,14 +1309,21 @@ _mesa_VertexAttribDivisor(GLuint index, GLuint divisor)
>        return;
>     }
>  
> -   ASSERT(VERT_ATTRIB_GENERIC(index) < Elements(ctx->Array.ArrayObj->_VertexAttrib));
> +   ASSERT(genericIndex < Elements(ctx->Array.ArrayObj->VertexAttrib));
>  
> -   array = &ctx->Array.ArrayObj->_VertexAttrib[VERT_ATTRIB_GENERIC(index)];
> -   if (array->InstanceDivisor != divisor) {
> -      FLUSH_VERTICES(ctx, _NEW_ARRAY);
> -      array->InstanceDivisor = divisor;
> -      ctx->Array.ArrayObj->NewArrays |= VERT_BIT(VERT_ATTRIB_GENERIC(index));
> -   }
> +   /* 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, genericIndex, genericIndex);
> +   vertex_binding_divisor(ctx, genericIndex, divisor);
>  }
>  
>  
> @@ -1237,6 +1359,78 @@ void GLAPIENTRY
>  _mesa_BindVertexBuffer(GLuint bindingIndex, GLuint buffer, GLintptr offset,
>                         GLsizei stride)
>  {
> +   struct gl_buffer_object *vbo;
> +
> +   GET_CURRENT_CONTEXT(ctx);
> +   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.ArrayObj == ctx->Array.DefaultArrayObj) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION,
> +                  "glBindVertexBuffer(No array object bound)");
> +      return;
> +   }
> +
> +   /* 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,
> +                  "glBindVertexBuffer(bindingindex=%u > "
> +                  "GL_MAX_VERTEX_ATTRIB_BINDINGS)",
> +                  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,
> +                  "glBindVertexBuffer(offset=%d < 0)", offset);
> +      return;
> +   }
> +
> +   if (stride < 0) {
> +      _mesa_error(ctx, GL_INVALID_VALUE,
> +                  "glBindVertexBuffer(stride=%d < 0)", stride);
> +      return;
> +   }
> +
> +   if (buffer != 0) {
> +      vbo = _mesa_lookup_bufferobj(ctx, buffer);
> +
> +      /* The ARB_vertex_attrib_binding spec doesn't specify that an error
> +       * should be generated when <buffer> doesn't refer to a valid buffer
> +       * object, but we assume that this is an oversight.
> +       */
> +      if (!vbo) {
> +         _mesa_error(ctx, GL_INVALID_OPERATION,
> +                     "glBindVertexBuffer(buffer=%u is not a valid "
> +                     "buffer object)",
> +                     buffer);
> +         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;
> +   }
> +
> +   bind_vertex_buffer(ctx, VERT_ATTRIB_GENERIC(bindingIndex),
> +                      vbo, offset, stride);
>  }
>  
>  
> @@ -1244,6 +1438,50 @@ void GLAPIENTRY
>  _mesa_VertexAttribFormat(GLuint attribIndex, GLint size, GLenum type,
>                           GLboolean normalized, GLuint relativeOffset)
>  {
> +    const GLbitfield legalTypes = (BYTE_BIT | UNSIGNED_BYTE_BIT |
> +                                   SHORT_BIT | UNSIGNED_SHORT_BIT |
> +                                   INT_BIT | UNSIGNED_INT_BIT |
> +                                   HALF_BIT | FLOAT_BIT | DOUBLE_BIT |
> +                                   FIXED_GL_BIT |
> +                                   UNSIGNED_INT_2_10_10_10_REV_BIT |
> +                                   INT_2_10_10_10_REV_BIT);
> +
> +   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);
> +    *     - ..."
> +    */
> +   if (ctx->API == API_OPENGL_CORE &&
> +       ctx->Array.ArrayObj == ctx->Array.DefaultArrayObj) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION,
> +                  "glVertexAttribFormat(No array object bound)");
> +      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.VertexProgram.MaxAttribs) {
> +      _mesa_error(ctx, GL_INVALID_VALUE,
> +                  "glVertexAttribFormat(attribindex=%u > "
> +                  "GL_MAX_VERTEX_ATTRIBS)",
> +                  attribIndex);
> +      return;
> +   }
> +
> +   FLUSH_VERTICES(ctx, 0);
> +
> +   update_array_format(ctx, "glVertexAttribFormat",
> +                       VERT_ATTRIB_GENERIC(attribIndex),
> +                       legalTypes, 1, BGRA_OR_4, size, type, normalized,
> +                       GL_FALSE, relativeOffset);
>  }
>  
>  
> @@ -1251,6 +1489,46 @@ void GLAPIENTRY
>  _mesa_VertexAttribIFormat(GLuint attribIndex, GLint size, GLenum type,
>                            GLuint relativeOffset)
>  {
> +   const GLbitfield legalTypes = (BYTE_BIT | UNSIGNED_BYTE_BIT |
> +                                  SHORT_BIT | UNSIGNED_SHORT_BIT |
> +                                  INT_BIT | UNSIGNED_INT_BIT);
> +
> +   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);
> +    *     - ..."
> +    */
> +   if (ctx->API == API_OPENGL_CORE &&
> +          ctx->Array.ArrayObj == ctx->Array.DefaultArrayObj) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION,
> +                  "glVertexAttribIFormat(No array object bound)");
> +      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.VertexProgram.MaxAttribs) {
> +      _mesa_error(ctx, GL_INVALID_VALUE,
> +                  "glVertexAttribIFormat(attribindex=%u > "
> +                  "GL_MAX_VERTEX_ATTRIBS)",
> +                  attribIndex);
> +      return;
> +   }
> +
> +   FLUSH_VERTICES(ctx, 0);
> +
> +   update_array_format(ctx, "glVertexAttribIFormat",
> +                       VERT_ATTRIB_GENERIC(attribIndex),
> +                       legalTypes, 1, 4, size, type, GL_FALSE, GL_TRUE,
> +                       relativeOffset);
>  }
>  
>  
> @@ -1258,18 +1536,131 @@ void GLAPIENTRY
>  _mesa_VertexAttribLFormat(GLuint attribIndex, GLint size, GLenum type,
>                            GLuint relativeOffset)
>  {
> +   const GLbitfield legalTypes = DOUBLE_BIT;
> +
> +   GET_CURRENT_CONTEXT(ctx);
> +   ASSERT_OUTSIDE_BEGIN_END(ctx);
> +
> +   /* Page 298 of the PDF of the OpenGL 4.3 (Core Profile) spec says:
> +    *
> +    *    "An INVALID_OPERATION error is generated under any of the following
> +    *     conditions:
> +    *     • if no vertex array object is currently bound (see section 10.4);
> +    *     • ..."
> +    *
> +    * This language is missing from the extension spec, but we assume
> +    * that this is an oversight.
> +    */
> +   if (ctx->API == API_OPENGL_CORE &&
> +          ctx->Array.ArrayObj == ctx->Array.DefaultArrayObj) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION,
> +                  "glVertexAttribLFormat(No array object bound)");
> +      return;
> +   }
> +
> +   /* The ARB_vertex_attrib_binding spec says:
> +    *
> +    *   "The error INVALID_VALUE is generated if <attribindex> is greater than
> +    *    or equal to the value of MAX_VERTEX_ATTRIBS."
> +    */
> +   if (attribIndex >= ctx->Const.VertexProgram.MaxAttribs) {
> +      _mesa_error(ctx, GL_INVALID_VALUE,
> +                  "glVertexAttribLFormat(attribindex=%u > "
> +                  "GL_MAX_VERTEX_ATTRIBS)",
> +                  attribIndex);
> +      return;
> +   }
> +
> +   FLUSH_VERTICES(ctx, 0);
> +
> +   update_array_format(ctx, "glVertexAttribLFormat",
> +                       VERT_ATTRIB_GENERIC(attribIndex),
> +                       legalTypes, 1, 4, size, type, GL_FALSE, GL_FALSE,
> +                       relativeOffset);
>  }
>  
>  
>  void GLAPIENTRY
>  _mesa_VertexAttribBinding(GLuint attribIndex, GLuint bindingIndex)
>  {
> +   GET_CURRENT_CONTEXT(ctx);
> +   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.ArrayObj == ctx->Array.DefaultArrayObj) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION,
> +                  "glVertexAttribBinding(No array object bound)");
> +      return;
> +   }
> +
> +   /* 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.VertexProgram.MaxAttribs) {
> +      _mesa_error(ctx, GL_INVALID_VALUE,
> +                  "glVertexAttribBinding(attribindex=%u >= "
> +                  "GL_MAX_VERTEX_ATTRIBS)",
> +                  attribIndex);
> +      return;
> +   }
> +
> +   if (bindingIndex >= ctx->Const.MaxVertexAttribBindings) {
> +      _mesa_error(ctx, GL_INVALID_VALUE,
> +                  "glVertexAttribBinding(bindingindex=%u >= "
> +                  "GL_MAX_VERTEX_ATTRIB_BINDINGS)",
> +                  bindingIndex);
> +      return;
> +   }
> +
> +   ASSERT(VERT_ATTRIB_GENERIC(attribIndex) <
> +          Elements(ctx->Array.ArrayObj->VertexAttrib));
> +
> +   vertex_attrib_binding(ctx, VERT_ATTRIB_GENERIC(attribIndex),
> +                         VERT_ATTRIB_GENERIC(bindingIndex));
>  }
>  
>  
>  void GLAPIENTRY
>  _mesa_VertexBindingDivisor(GLuint bindingIndex, GLuint divisor)
>  {
> +   GET_CURRENT_CONTEXT(ctx);
> +   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.ArrayObj == ctx->Array.DefaultArrayObj) {
> +      _mesa_error(ctx, GL_INVALID_OPERATION,
> +                  "glVertexBindingDivisor(No array object bound)");
> +      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,
> +                  "glVertexBindingDivisor(bindingindex=%u > "
> +                  "GL_MAX_VERTEX_ATTRIB_BINDINGS)",
> +                  bindingIndex);
> +      return;
> +   }
> +
> +   vertex_binding_divisor(ctx, VERT_ATTRIB_GENERIC(bindingIndex), divisor);
>  }
>  
>  
> @@ -1296,7 +1687,36 @@ _mesa_copy_client_array(struct gl_context *ctx,
>     dst->_MaxElement = src->_MaxElement;
>  }
>  
> +void
> +_mesa_copy_vertex_attrib_array(struct gl_context *ctx,
> +                               struct gl_vertex_attrib_array *dst,
> +                               const struct gl_vertex_attrib_array *src)
> +{
> +   dst->Size           = src->Size;
> +   dst->Type           = src->Type;
> +   dst->Format         = src->Format;
> +   dst->VertexBinding  = src->VertexBinding;
> +   dst->RelativeOffset = src->RelativeOffset;
> +   dst->Format         = src->Format;
> +   dst->Integer        = src->Integer;
> +   dst->Normalized     = src->Normalized;
> +   dst->Ptr            = src->Ptr;
> +   dst->Enabled        = src->Enabled;
> +   dst->_ElementSize   = src->_ElementSize;
> +}
> +
> +void
> +_mesa_copy_vertex_buffer_binding(struct gl_context *ctx,
> +                                 struct gl_vertex_buffer_binding *dst,
> +                                 const struct gl_vertex_buffer_binding *src)
> +{
> +   dst->Offset          = src->Offset;
> +   dst->Stride          = src->Stride;
> +   dst->InstanceDivisor = src->InstanceDivisor;
> +   dst->_BoundArrays    = src->_BoundArrays;
>  
> +   _mesa_reference_buffer_object(ctx, &dst->BufferObj, src->BufferObj);
> +}
>  
>  /**
>   * Print vertex array's fields.
> diff --git a/src/mesa/main/varray.h b/src/mesa/main/varray.h
> index 2b54fde..a75cb7d 100644
> --- a/src/mesa/main/varray.h
> +++ b/src/mesa/main/varray.h
> @@ -29,6 +29,7 @@
>  
>  
>  #include "glheader.h"
> +#include "bufferobj.h"
>  
>  struct gl_client_array;
>  struct gl_context;
> @@ -64,6 +65,44 @@ _mesa_update_array_max_element(struct gl_client_array *array)
>  }
>  
>  
> +/**
> + * Returns a pointer to the vertex attribute data in a client array,
> + * or the offset into the vertex buffer for an array that resides in
> + * a vertex buffer.
> + */
> +static inline const GLubyte *
> +_mesa_vertex_attrib_address(struct gl_vertex_attrib_array *array,
> +                            struct gl_vertex_buffer_binding *binding)
> +{
> +   return (binding->BufferObj->Name == 0 ?
> +           array->Ptr :
> +           (const GLubyte *)(binding->Offset + array->RelativeOffset));
> +}
> +
> +/**
> + * Sets the fields in a gl_client_array to values derived from a
> + * gl_vertex_attrib_array and a gl_vertex_buffer_binding.
> + */
> +static inline void
> +_mesa_update_client_array(struct gl_context *ctx,
> +                          struct gl_client_array *dst,
> +                          struct gl_vertex_attrib_array *src,
> +                          struct gl_vertex_buffer_binding *binding)
> +{
> +   dst->Size = src->Size;
> +   dst->Type = src->Type;
> +   dst->Format = src->Format;
> +   dst->Stride = src->Stride;
> +   dst->StrideB = binding->Stride;
> +   dst->Ptr = _mesa_vertex_attrib_address(src, binding);
> +   dst->Enabled = src->Enabled;
> +   dst->Normalized = src->Normalized;
> +   dst->Integer = src->Integer;
> +   dst->InstanceDivisor = binding->InstanceDivisor;
> +   dst->_ElementSize = src->_ElementSize;
> +   _mesa_reference_buffer_object(ctx, &dst->BufferObj, binding->BufferObj);
> +}
> +
>  extern void GLAPIENTRY
>  _mesa_VertexPointer(GLint size, GLenum type, GLsizei stride,
>                      const GLvoid *ptr);
> @@ -278,6 +317,15 @@ _mesa_copy_client_array(struct gl_context *ctx,
>                          struct gl_client_array *dst,
>                          struct gl_client_array *src);
>  
> +extern void
> +_mesa_copy_vertex_attrib_array(struct gl_context *ctx,
> +                               struct gl_vertex_attrib_array *dst,
> +                               const struct gl_vertex_attrib_array *src);
> +
> +extern void
> +_mesa_copy_vertex_buffer_binding(struct gl_context *ctx,
> +                                 struct gl_vertex_buffer_binding *dst,
> +                                 const struct gl_vertex_buffer_binding *src);
>  
>  extern void
>  _mesa_print_arrays(struct gl_context *ctx);
> 



More information about the mesa-dev mailing list