[Mesa-dev] [PATCH 4/4] st/mesa: fix vertex elements setup for doubles

Nicolai Hähnle nhaehnle at gmail.com
Wed Oct 12 17:50:30 UTC 2016


From: Nicolai Hähnle <nicolai.haehnle at amd.com>

Whether one or two slots are taken up by one API array depends on the
vertex shader, not on how the array is configured. When an array is
set up with fewer components than the shader expects, the high components
are undefined.

Fixes GL45-CTS.vertex_attrib_binding.basic-inputL-case1.

Cc: mesa-stable at lists.freedesktop.org
---
 src/mesa/state_tracker/st_atom_array.c | 98 +++++++++++++++++-----------------
 1 file changed, 50 insertions(+), 48 deletions(-)

diff --git a/src/mesa/state_tracker/st_atom_array.c b/src/mesa/state_tracker/st_atom_array.c
index 1c2cfa7..e5b949f 100644
--- a/src/mesa/state_tracker/st_atom_array.c
+++ b/src/mesa/state_tracker/st_atom_array.c
@@ -379,47 +379,58 @@ static void init_velement(struct pipe_vertex_element *velement,
                           int instance_divisor, int vbo_index)
 {
    velement->src_offset = src_offset;
    velement->src_format = format;
    velement->instance_divisor = instance_divisor;
    velement->vertex_buffer_index = vbo_index;
    assert(velement->src_format);
 }
 
 static void init_velement_lowered(struct st_context *st,
+                                  const struct st_vertex_program *vp,
                                   struct pipe_vertex_element *velements,
                                   int src_offset, int format,
                                   int instance_divisor, int vbo_index,
                                   int nr_components, GLboolean doubles,
                                   GLuint *attr_idx)
 {
    int idx = *attr_idx;
    if (doubles) {
       int lower_format;
 
-      if (nr_components == 1)
+      if (nr_components < 2)
          lower_format = PIPE_FORMAT_R32G32_UINT;
-      else if (nr_components >= 2)
+      else
          lower_format = PIPE_FORMAT_R32G32B32A32_UINT;
 
       init_velement(&velements[idx], src_offset,
                     lower_format, instance_divisor, vbo_index);
       idx++;
 
-      if (nr_components > 2) {
-         if (nr_components == 3)
-            lower_format = PIPE_FORMAT_R32G32_UINT;
-         else if (nr_components >= 4)
-            lower_format = PIPE_FORMAT_R32G32B32A32_UINT;
+      if (idx < vp->num_inputs &&
+          vp->index_to_input[idx] == ST_DOUBLE_ATTRIB_PLACEHOLDER) {
+         if (nr_components >= 3) {
+            if (nr_components == 3)
+               lower_format = PIPE_FORMAT_R32G32_UINT;
+            else
+               lower_format = PIPE_FORMAT_R32G32B32A32_UINT;
+
+            init_velement(&velements[idx], src_offset + 4 * sizeof(float),
+                        lower_format, instance_divisor, vbo_index);
+         } else {
+            /* The values here are undefined. Fill in some conservative
+             * dummy values.
+             */
+            init_velement(&velements[idx], src_offset, PIPE_FORMAT_R32G32_UINT,
+                          instance_divisor, vbo_index);
+         }
 
-         init_velement(&velements[idx], src_offset + 4 * sizeof(float),
-                       lower_format, instance_divisor, vbo_index);
          idx++;
       }
    } else {
       init_velement(&velements[idx], src_offset,
                     format, instance_divisor, vbo_index);
       idx++;
    }
    *attr_idx = idx;
 }
 
@@ -428,24 +439,23 @@ static void init_velement_lowered(struct st_context *st,
  * or all live in user space.
  * \param vbuffer  returns vertex buffer info
  * \param velements  returns vertex element info
  */
 static boolean
 setup_interleaved_attribs(struct st_context *st,
                           const struct st_vertex_program *vp,
                           const struct st_vp_variant *vpv,
                           const struct gl_client_array **arrays,
                           struct pipe_vertex_buffer *vbuffer,
-                          struct pipe_vertex_element velements[],
-                          unsigned *num_velements)
+                          struct pipe_vertex_element velements[])
 {
-   GLuint attr, attr_idx;
+   GLuint attr;
    const GLubyte *low_addr = NULL;
    GLboolean usingVBO;      /* all arrays in a VBO? */
    struct gl_buffer_object *bufobj;
    GLsizei stride;
 
    /* Find the lowest address of the arrays we're drawing,
     * Init bufobj and stride.
     */
    if (vpv->num_inputs) {
       const struct gl_client_array *array;
@@ -474,47 +484,43 @@ setup_interleaved_attribs(struct st_context *st,
    else {
       /* not sure we'll ever have zero inputs, but play it safe */
       bufobj = NULL;
       stride = 0;
       low_addr = 0;
    }
 
    /* are the arrays in user space? */
    usingVBO = _mesa_is_bufferobj(bufobj);
 
-   attr_idx = 0;
-   for (attr = 0; attr < vpv->num_inputs; attr++) {
+   for (attr = 0; attr < vpv->num_inputs;) {
       const struct gl_client_array *array;
       unsigned src_offset;
       unsigned src_format;
 
       array = get_client_array(vp, arrays, attr);
-      if (!array)
-         continue;
+      assert(array);
 
       src_offset = (unsigned) (array->Ptr - low_addr);
       assert(array->_ElementSize ==
              _mesa_bytes_per_vertex_attrib(array->Size, array->Type));
 
       src_format = st_pipe_vertex_format(array->Type,
                                          array->Size,
                                          array->Format,
                                          array->Normalized,
                                          array->Integer);
 
-      init_velement_lowered(st, velements, src_offset, src_format,
+      init_velement_lowered(st, vp, velements, src_offset, src_format,
                             array->InstanceDivisor, 0,
-                            array->Size, array->Doubles, &attr_idx);
+                            array->Size, array->Doubles, &attr);
    }
 
-   *num_velements = attr_idx;
-
    /*
     * Return the vbuffer info and setup user-space attrib info, if needed.
     */
    if (vpv->num_inputs == 0) {
       /* just defensive coding here */
       vbuffer->buffer = NULL;
       vbuffer->user_buffer = NULL;
       vbuffer->buffer_offset = 0;
       vbuffer->stride = 0;
    }
@@ -547,148 +553,144 @@ setup_interleaved_attribs(struct st_context *st,
  * \param vbuffer  returns vertex buffer info
  * \param velements  returns vertex element info
  */
 static boolean
 setup_non_interleaved_attribs(struct st_context *st,
                               const struct st_vertex_program *vp,
                               const struct st_vp_variant *vpv,
                               const struct gl_client_array **arrays,
                               struct pipe_vertex_buffer vbuffer[],
                               struct pipe_vertex_element velements[],
-                              unsigned *num_velements)
+                              unsigned *num_vbuffers)
 {
    struct gl_context *ctx = st->ctx;
-   GLuint attr, attr_idx = 0;
+   GLuint attr;
 
-   for (attr = 0; attr < vpv->num_inputs; attr++) {
+   *num_vbuffers = 0;
+
+   for (attr = 0; attr < vpv->num_inputs;) {
       const GLuint mesaAttr = vp->index_to_input[attr];
       const struct gl_client_array *array;
       struct gl_buffer_object *bufobj;
       GLsizei stride;
       unsigned src_format;
+      unsigned bufidx;
 
       array = get_client_array(vp, arrays, attr);
-      if (!array) {
-         vbuffer[attr].buffer = NULL;
-         vbuffer[attr].user_buffer = NULL;
-         vbuffer[attr].buffer_offset = 0;
-         continue;
-      }
+      assert(array);
+
+      bufidx = (*num_vbuffers)++;
 
       stride = array->StrideB;
       bufobj = array->BufferObj;
       assert(array->_ElementSize ==
              _mesa_bytes_per_vertex_attrib(array->Size, array->Type));
 
       if (_mesa_is_bufferobj(bufobj)) {
          /* Attribute data is in a VBO.
           * Recall that for VBOs, the gl_client_array->Ptr field is
           * really an offset from the start of the VBO, not a pointer.
           */
          struct st_buffer_object *stobj = st_buffer_object(bufobj);
 
          if (!stobj || !stobj->buffer) {
             return FALSE; /* out-of-memory error probably */
          }
 
-         vbuffer[attr].buffer = stobj->buffer;
-         vbuffer[attr].user_buffer = NULL;
-         vbuffer[attr].buffer_offset = pointer_to_offset(array->Ptr);
+         vbuffer[bufidx].buffer = stobj->buffer;
+         vbuffer[bufidx].user_buffer = NULL;
+         vbuffer[bufidx].buffer_offset = pointer_to_offset(array->Ptr);
       }
       else {
          /* wrap user data */
          void *ptr;
 
          if (array->Ptr) {
             ptr = (void *) array->Ptr;
          }
          else {
             /* no array, use ctx->Current.Attrib[] value */
             ptr = (void *) ctx->Current.Attrib[mesaAttr];
             stride = 0;
          }
 
          assert(ptr);
 
-         vbuffer[attr].buffer = NULL;
-         vbuffer[attr].user_buffer = ptr;
-         vbuffer[attr].buffer_offset = 0;
+         vbuffer[bufidx].buffer = NULL;
+         vbuffer[bufidx].user_buffer = ptr;
+         vbuffer[bufidx].buffer_offset = 0;
       }
 
       /* common-case setup */
-      vbuffer[attr].stride = stride; /* in bytes */
+      vbuffer[bufidx].stride = stride; /* in bytes */
 
       src_format = st_pipe_vertex_format(array->Type,
                                          array->Size,
                                          array->Format,
                                          array->Normalized,
                                          array->Integer);
 
-      init_velement_lowered(st, velements, 0, src_format,
-                            array->InstanceDivisor, attr,
-                            array->Size, array->Doubles, &attr_idx);
-
+      init_velement_lowered(st, vp, velements, 0, src_format,
+                            array->InstanceDivisor, bufidx,
+                            array->Size, array->Doubles, &attr);
    }
 
-   *num_velements = attr_idx;
    return TRUE;
 }
 
 static void update_array(struct st_context *st)
 {
    struct gl_context *ctx = st->ctx;
    const struct gl_client_array **arrays = ctx->Array._DrawArrays;
    const struct st_vertex_program *vp;
    const struct st_vp_variant *vpv;
    struct pipe_vertex_buffer vbuffer[PIPE_MAX_SHADER_INPUTS];
    struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS];
-   unsigned num_vbuffers, num_velements;
+   unsigned num_vbuffers;
 
    st->vertex_array_out_of_memory = FALSE;
 
    /* No drawing has been done yet, so do nothing. */
    if (!arrays)
       return;
 
    /* vertex program validation must be done before this */
    vp = st->vp;
    vpv = st->vp_variant;
 
    memset(velements, 0, sizeof(struct pipe_vertex_element) * vpv->num_inputs);
 
    /*
     * Setup the vbuffer[] and velements[] arrays.
     */
    if (is_interleaved_arrays(vp, vpv, arrays)) {
-      if (!setup_interleaved_attribs(st, vp, vpv, arrays, vbuffer, velements, &num_velements)) {
+      if (!setup_interleaved_attribs(st, vp, vpv, arrays, vbuffer, velements)) {
          st->vertex_array_out_of_memory = TRUE;
          return;
       }
 
       num_vbuffers = 1;
-      if (num_velements == 0)
+      if (vpv->num_inputs == 0)
          num_vbuffers = 0;
    }
    else {
       if (!setup_non_interleaved_attribs(st, vp, vpv, arrays, vbuffer,
-                                         velements, &num_velements)) {
+                                         velements, &num_vbuffers)) {
          st->vertex_array_out_of_memory = TRUE;
          return;
       }
-
-      num_vbuffers = vpv->num_inputs;
    }
 
    cso_set_vertex_buffers(st->cso_context, 0, num_vbuffers, vbuffer);
    if (st->last_num_vbuffers > num_vbuffers) {
       /* Unbind remaining buffers, if any. */
       cso_set_vertex_buffers(st->cso_context, num_vbuffers,
                              st->last_num_vbuffers - num_vbuffers, NULL);
    }
    st->last_num_vbuffers = num_vbuffers;
-   cso_set_vertex_elements(st->cso_context, num_velements, velements);
+   cso_set_vertex_elements(st->cso_context, vpv->num_inputs, velements);
 }
 
 
 const struct st_tracked_state st_update_array = {
    update_array						/* update */
 };
-- 
2.7.4



More information about the mesa-dev mailing list