st/mesa: fix vertex elements setup for doubles
authorNicolai Hähnle <nicolai.haehnle@amd.com>
Mon, 10 Oct 2016 18:20:22 +0000 (20:20 +0200)
committerNicolai Hähnle <nicolai.haehnle@amd.com>
Thu, 13 Oct 2016 13:41:36 +0000 (15:41 +0200)
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@lists.freedesktop.org
Reviewed-by: Dave Airlie <airlied@redhat.com>
src/mesa/state_tracker/st_atom_array.c

index 1c2cfa791cdca972a690185a4f6f0317217b5bf3..e5b949fbaecd707174c7fa6c68fbd50205ef5eb7 100644 (file)
@@ -386,6 +386,7 @@ static void init_velement(struct pipe_vertex_element *velement,
 }
 
 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,
@@ -396,23 +397,33 @@ static void init_velement_lowered(struct st_context *st,
    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 {
@@ -435,10 +446,9 @@ setup_interleaved_attribs(struct st_context *st,
                           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;
@@ -481,15 +491,13 @@ setup_interleaved_attribs(struct st_context *st,
    /* 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 ==
@@ -501,13 +509,11 @@ setup_interleaved_attribs(struct st_context *st,
                                          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.
     */
@@ -554,25 +560,25 @@ setup_non_interleaved_attribs(struct st_context *st,
                               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;
@@ -590,9 +596,9 @@ setup_non_interleaved_attribs(struct st_context *st,
             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 */
@@ -609,13 +615,13 @@ setup_non_interleaved_attribs(struct st_context *st,
 
          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,
@@ -623,13 +629,11 @@ setup_non_interleaved_attribs(struct st_context *st,
                                          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;
 }
 
@@ -641,7 +645,7 @@ static void update_array(struct st_context *st)
    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;
 
@@ -659,23 +663,21 @@ static void update_array(struct st_context *st)
     * 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);
@@ -685,7 +687,7 @@ static void update_array(struct st_context *st)
                              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);
 }