glx: Fix indirect multi-texture GL_DOUBLE coordinate arrays.
authorColin McDonald <cjmmail10-bz@yahoo.co.uk>
Thu, 23 Jun 2016 02:19:30 +0000 (19:19 -0700)
committerMatt Turner <mattst88@gmail.com>
Fri, 8 Jul 2016 21:03:16 +0000 (14:03 -0700)
There is no draw arrays protocol support for multi-texture coordinate
arrays, so it is implemented by sending batches of immediate mode
commands from emit_element_none in indirect_vertex_array.c.  This sends
the target texture unit (which has been previously setup in the
array_state header field), followed by the texture coordinates.  But for
GL_DOUBLE coordinates the texture unit must be sent *after* the texture
coordinates. This is documented in the glx protocol description, and can
also be seen in the indirect.c immediate mode commands generated from
gl_API.xml. Sending the target texture unit in the wrong place can crash
the remote X server.

To fix this required some more extensive changes to
indirect_vertex_array.c and indirect_vertex_array_priv.h, in order to
remove the texture unit value out of the array_state "header" field, and
send it separately.

Reviewed-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61907

src/glx/indirect_vertex_array.c
src/glx/indirect_vertex_array_priv.h

index 01fab3345a93afed6dfeea47b7b68b693dafea1e..0374093b0eca90f8cc9dce4540b3b8fdb795e304 100644 (file)
@@ -240,8 +240,6 @@ __glXInitVertexArrayState(struct glx_context * gc)
 
       arrays->arrays[4 + i].old_DrawArrays_possible = (i == 0);
       arrays->arrays[4 + i].index = i;
-
-      arrays->arrays[4 + i].header[1] = i + GL_TEXTURE0;
    }
 
    i = 4 + texture_units;
@@ -274,8 +272,6 @@ __glXInitVertexArrayState(struct glx_context * gc)
 
       arrays->arrays[idx + i].old_DrawArrays_possible = 0;
       arrays->arrays[idx + i].index = idx;
-
-      arrays->arrays[idx + i].header[1] = idx;
    }
 
    i += vertex_program_attribs;
@@ -325,7 +321,7 @@ calculate_single_vertex_size_none(const struct array_state_vector *arrays)
 
    for (i = 0; i < arrays->num_arrays; i++) {
       if (arrays->arrays[i].enabled) {
-         single_vertex_size += ((uint16_t *) arrays->arrays[i].header)[0];
+         single_vertex_size += arrays->arrays[i].header[0];
       }
    }
 
@@ -353,17 +349,45 @@ emit_element_none(GLubyte * dst,
           * protocol is for a 4Nus.  Since the sizes are small, the
           * performance impact on modern processors should be negligible.
           */
-         (void) memset(dst, 0, ((uint16_t *) arrays->arrays[i].header)[0]);
-
-         (void) memcpy(dst, arrays->arrays[i].header,
-                       arrays->arrays[i].header_size);
-
-         dst += arrays->arrays[i].header_size;
-
-         (void) memcpy(dst, ((GLubyte *) arrays->arrays[i].data) + offset,
-                       arrays->arrays[i].element_size);
-
-         dst += __GLX_PAD(arrays->arrays[i].element_size);
+         (void) memset(dst, 0, arrays->arrays[i].header[0]);
+
+         (void) memcpy(dst, arrays->arrays[i].header, 4);
+
+         dst += 4;
+
+         if (arrays->arrays[i].key == GL_TEXTURE_COORD_ARRAY &&
+             arrays->arrays[i].index > 0) {
+            /* Multi-texture coordinate arrays require the texture target
+             * to be sent.  For doubles it is after the data, for everything
+             * else it is before.
+             */
+            GLenum texture = arrays->arrays[i].index + GL_TEXTURE0;
+            if (arrays->arrays[i].data_type == GL_DOUBLE) {
+               (void) memcpy(dst, ((GLubyte *) arrays->arrays[i].data) + offset,
+                             arrays->arrays[i].element_size);
+               dst += arrays->arrays[i].element_size;
+               (void) memcpy(dst, &texture, 4);
+               dst += 4;
+            } else {
+               (void) memcpy(dst, &texture, 4);
+               dst += 4;
+               (void) memcpy(dst, ((GLubyte *) arrays->arrays[i].data) + offset,
+                             arrays->arrays[i].element_size);
+               dst += __GLX_PAD(arrays->arrays[i].element_size);
+            }
+         } else if (arrays->arrays[i].key == GL_VERTEX_ATTRIB_ARRAY_POINTER) {
+            /* Vertex attribute data requires the index sent first.
+             */
+            (void) memcpy(dst, &arrays->arrays[i].index, 4);
+            dst += 4;
+            (void) memcpy(dst, ((GLubyte *) arrays->arrays[i].data) + offset,
+                          arrays->arrays[i].element_size);
+            dst += __GLX_PAD(arrays->arrays[i].element_size);
+         } else {
+            (void) memcpy(dst, ((GLubyte *) arrays->arrays[i].data) + offset,
+                          arrays->arrays[i].element_size);
+            dst += __GLX_PAD(arrays->arrays[i].element_size);
+         }
       }
    }
 
@@ -1099,6 +1123,10 @@ __indirect_glMultiDrawElementsEXT(GLenum mode, const GLsizei * count,
 }
 
 
+/* The HDR_SIZE macro argument is the command header size (4 bytes)
+ * plus any additional index word e.g. for texture units or vertex
+ * attributes.
+ */
 #define COMMON_ARRAY_DATA_INIT(a, PTR, TYPE, STRIDE, COUNT, NORMALIZED, HDR_SIZE, OPCODE) \
   do {                                                                  \
     (a)->data = PTR;                                                    \
@@ -1111,9 +1139,8 @@ __indirect_glMultiDrawElementsEXT(GLenum mode, const GLsizei * count,
     (a)->true_stride = (STRIDE == 0)                                    \
       ? (a)->element_size : STRIDE;                                     \
                                                                         \
-    (a)->header_size = HDR_SIZE;                                        \
-    ((uint16_t *) (a)->header)[0] = __GLX_PAD((a)->header_size + (a)->element_size); \
-    ((uint16_t *) (a)->header)[1] = OPCODE;                             \
+    (a)->header[0] = __GLX_PAD(HDR_SIZE + (a)->element_size);           \
+    (a)->header[1] = OPCODE;                                            \
   } while(0)
 
 
@@ -1691,8 +1718,7 @@ __indirect_glVertexAttribPointer(GLuint index, GLint size,
                           opcode);
 
    true_immediate_size = __glXTypeSize(type) * true_immediate_count;
-   ((uint16_t *) (a)->header)[0] = __GLX_PAD(a->header_size
-                                             + true_immediate_size);
+   a->header[0] = __GLX_PAD(8 + true_immediate_size);
 
    if (a->enabled) {
       arrays->array_info_cache_valid = GL_FALSE;
index 56dac37c7834a4b78f907867ffd1c7b97f972e12..488dacb99d117346dace7d3da9db7f9cba4341dc 100644 (file)
@@ -87,16 +87,10 @@ struct array_state
 
     /**
      * Pre-calculated GLX protocol command header.
+     * This contains two 16-bit words: the command length and the command
+     * opcode.
      */
-   uint32_t header[2];
-
-    /**
-     * Size of the header data.  For simple data, like glColorPointerfv,
-     * this is 4.  For complex data that requires either a count (e.g.,
-     * glWeightfvARB), an index (e.g., glVertexAttrib1fvARB), or a
-     * selector enum (e.g., glMultiTexCoord2fv) this is 8.
-     */
-   unsigned header_size;
+   uint16_t header[2];
 
     /**
      * Set to \c GL_TRUE if this array is enabled.  Otherwise, it is set