From: Colin McDonald Date: Thu, 23 Jun 2016 02:19:30 +0000 (-0700) Subject: glx: Fix indirect multi-texture GL_DOUBLE coordinate arrays. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b36644bae611d608cee8ef0d5dd1200313234b73;p=mesa.git glx: Fix indirect multi-texture GL_DOUBLE coordinate arrays. 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 Reviewed-by: Ian Romanick Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61907 --- diff --git a/src/glx/indirect_vertex_array.c b/src/glx/indirect_vertex_array.c index 01fab3345a9..0374093b0ec 100644 --- a/src/glx/indirect_vertex_array.c +++ b/src/glx/indirect_vertex_array.c @@ -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; diff --git a/src/glx/indirect_vertex_array_priv.h b/src/glx/indirect_vertex_array_priv.h index 56dac37c783..488dacb99d1 100644 --- a/src/glx/indirect_vertex_array_priv.h +++ b/src/glx/indirect_vertex_array_priv.h @@ -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