Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / main / varray.c
1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.6
4  *
5  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
6  * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included
16  * in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25
26
27 #include "glheader.h"
28 #include "imports.h"
29 #include "bufferobj.h"
30 #include "context.h"
31 #include "enable.h"
32 #include "enums.h"
33 #include "hash.h"
34 #include "image.h"
35 #include "macros.h"
36 #include "mfeatures.h"
37 #include "mtypes.h"
38 #include "varray.h"
39 #include "arrayobj.h"
40 #include "main/dispatch.h"
41
42
43 /** Used to do error checking for GL_EXT_vertex_array_bgra */
44 #define BGRA_OR_4  5
45
46
47 /** Used to indicate which GL datatypes are accepted by each of the
48  * glVertex/Color/Attrib/EtcPointer() functions.
49  */
50 #define BOOL_BIT             0x1
51 #define BYTE_BIT             0x2
52 #define UNSIGNED_BYTE_BIT    0x4
53 #define SHORT_BIT            0x8
54 #define UNSIGNED_SHORT_BIT   0x10
55 #define INT_BIT              0x20
56 #define UNSIGNED_INT_BIT     0x40
57 #define HALF_BIT             0x80
58 #define FLOAT_BIT            0x100
59 #define DOUBLE_BIT           0x200
60 #define FIXED_ES_BIT         0x400
61 #define FIXED_GL_BIT         0x800
62
63
64 /** Convert GL datatype enum into a <type>_BIT value seen above */
65 static GLbitfield
66 type_to_bit(const struct gl_context *ctx, GLenum type)
67 {
68    switch (type) {
69    case GL_BOOL:
70       return BOOL_BIT;
71    case GL_BYTE:
72       return BYTE_BIT;
73    case GL_UNSIGNED_BYTE:
74       return UNSIGNED_BYTE_BIT;
75    case GL_SHORT:
76       return SHORT_BIT;
77    case GL_UNSIGNED_SHORT:
78       return UNSIGNED_SHORT_BIT;
79    case GL_INT:
80       return INT_BIT;
81    case GL_UNSIGNED_INT:
82       return UNSIGNED_INT_BIT;
83    case GL_HALF_FLOAT:
84       if (ctx->Extensions.ARB_half_float_vertex)
85          return HALF_BIT;
86       else
87          return 0x0;
88    case GL_FLOAT:
89       return FLOAT_BIT;
90    case GL_DOUBLE:
91       return DOUBLE_BIT;
92    case GL_FIXED:
93       return ctx->API == API_OPENGL ? FIXED_GL_BIT : FIXED_ES_BIT;
94    default:
95       return 0;
96    }
97 }
98
99
100 /**
101  * Do error checking and update state for glVertex/Color/TexCoord/...Pointer
102  * functions.
103  *
104  * \param func  name of calling function used for error reporting
105  * \param array  the array to update
106  * \param dirtyBit  which bit to set in ctx->Array.NewState for this array
107  * \param legalTypes  bitmask of *_BIT above indicating legal datatypes
108  * \param sizeMin  min allowable size value
109  * \param sizeMax  max allowable size value (may also be BGRA_OR_4)
110  * \param size  components per element (1, 2, 3 or 4)
111  * \param type  datatype of each component (GL_FLOAT, GL_INT, etc)
112  * \param stride  stride between elements, in elements
113  * \param normalized  are integer types converted to floats in [-1, 1]?
114  * \param integer  integer-valued values (will not be normalized to [-1,1])
115  * \param ptr  the address (or offset inside VBO) of the array data
116  */
117 static void
118 update_array(struct gl_context *ctx,
119              const char *func,
120              struct gl_client_array *array,
121              GLbitfield dirtyBit, GLbitfield legalTypesMask,
122              GLint sizeMin, GLint sizeMax,
123              GLint size, GLenum type, GLsizei stride,
124              GLboolean normalized, GLboolean integer,
125              const GLvoid *ptr)
126 {
127    GLbitfield typeBit;
128    GLsizei elementSize;
129    GLenum format = GL_RGBA;
130
131    if (ctx->API != API_OPENGLES && ctx->API != API_OPENGLES2) {
132       /* fixed point arrays / data is only allowed with OpenGL ES 1.x/2.0 */
133       legalTypesMask &= ~FIXED_ES_BIT;
134    }
135    if (!ctx->Extensions.ARB_ES2_compatibility) {
136       legalTypesMask &= ~FIXED_GL_BIT;
137    }
138
139    typeBit = type_to_bit(ctx, type);
140    if (typeBit == 0x0 || (typeBit & legalTypesMask) == 0x0) {
141       _mesa_error(ctx, GL_INVALID_ENUM, "%s(type = %s)",
142                   func, _mesa_lookup_enum_by_nr(type));
143       return;
144    }
145
146    /* Do size parameter checking.
147     * If sizeMax = BGRA_OR_4 it means that size = GL_BGRA is legal and
148     * must be handled specially.
149     */
150    if (ctx->Extensions.EXT_vertex_array_bgra &&
151        sizeMax == BGRA_OR_4 &&
152        size == GL_BGRA) {
153       if (type != GL_UNSIGNED_BYTE) {
154          _mesa_error(ctx, GL_INVALID_VALUE, "%s(GL_BGRA/GLubyte)", func);
155          return;
156       }
157       format = GL_BGRA;
158       size = 4;
159    }
160    else if (size < sizeMin || size > sizeMax || size > 4) {
161       _mesa_error(ctx, GL_INVALID_VALUE, "%s(size=%d)", func, size);
162       return;
163    }
164
165    ASSERT(size <= 4);
166
167    if (stride < 0) {
168       _mesa_error( ctx, GL_INVALID_VALUE, "%s(stride=%d)", func, stride );
169       return;
170    }
171
172    if (ctx->Array.ArrayObj->VBOonly &&
173        ctx->Array.ArrayBufferObj->Name == 0) {
174       /* GL_ARB_vertex_array_object requires that all arrays reside in VBOs.
175        * Generate GL_INVALID_OPERATION if that's not true.
176        */
177       _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-VBO array)", func);
178       return;
179    }
180
181    elementSize = _mesa_sizeof_type(type) * size;
182
183    array->Size = size;
184    array->Type = type;
185    array->Format = format;
186    array->Stride = stride;
187    array->StrideB = stride ? stride : elementSize;
188    array->Normalized = normalized;
189    array->Ptr = (const GLubyte *) ptr;
190    array->_ElementSize = elementSize;
191
192    _mesa_reference_buffer_object(ctx, &array->BufferObj,
193                                  ctx->Array.ArrayBufferObj);
194
195    ctx->NewState |= _NEW_ARRAY;
196    ctx->Array.NewState |= dirtyBit;
197 }
198
199
200 void GLAPIENTRY
201 _mesa_VertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
202 {
203    GLbitfield legalTypes = (SHORT_BIT | INT_BIT | FLOAT_BIT |
204                             DOUBLE_BIT | HALF_BIT | FIXED_ES_BIT);
205    GET_CURRENT_CONTEXT(ctx);
206    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
207
208    if (ctx->API == API_OPENGLES)
209       legalTypes |= BYTE_BIT;
210
211    update_array(ctx, "glVertexPointer",
212                 &ctx->Array.ArrayObj->Vertex, _NEW_ARRAY_VERTEX,
213                 legalTypes, 2, 4,
214                 size, type, stride, GL_FALSE, GL_FALSE, ptr);
215 }
216
217
218 void GLAPIENTRY
219 _mesa_NormalPointer(GLenum type, GLsizei stride, const GLvoid *ptr )
220 {
221    const GLbitfield legalTypes = (BYTE_BIT | SHORT_BIT | INT_BIT |
222                                   HALF_BIT | FLOAT_BIT | DOUBLE_BIT |
223                                   FIXED_ES_BIT);
224    GET_CURRENT_CONTEXT(ctx);
225    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
226
227    update_array(ctx, "glNormalPointer",
228                 &ctx->Array.ArrayObj->Normal, _NEW_ARRAY_NORMAL,
229                 legalTypes, 3, 3,
230                 3, type, stride, GL_TRUE, GL_FALSE, ptr);
231 }
232
233
234 void GLAPIENTRY
235 _mesa_ColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr)
236 {
237    const GLbitfield legalTypes = (BYTE_BIT | UNSIGNED_BYTE_BIT |
238                                   SHORT_BIT | UNSIGNED_SHORT_BIT |
239                                   INT_BIT | UNSIGNED_INT_BIT |
240                                   HALF_BIT | FLOAT_BIT | DOUBLE_BIT |
241                                   FIXED_ES_BIT);
242    GET_CURRENT_CONTEXT(ctx);
243    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
244
245    update_array(ctx, "glColorPointer",
246                 &ctx->Array.ArrayObj->Color, _NEW_ARRAY_COLOR0,
247                 legalTypes, 3, BGRA_OR_4,
248                 size, type, stride, GL_TRUE, GL_FALSE, ptr);
249 }
250
251
252 void GLAPIENTRY
253 _mesa_FogCoordPointerEXT(GLenum type, GLsizei stride, const GLvoid *ptr)
254 {
255    const GLbitfield legalTypes = (HALF_BIT | FLOAT_BIT | DOUBLE_BIT);
256    GET_CURRENT_CONTEXT(ctx);
257    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
258
259    update_array(ctx, "glFogCoordPointer",
260                 &ctx->Array.ArrayObj->FogCoord, _NEW_ARRAY_FOGCOORD,
261                 legalTypes, 1, 1,
262                 1, type, stride, GL_FALSE, GL_FALSE, ptr);
263 }
264
265
266 void GLAPIENTRY
267 _mesa_IndexPointer(GLenum type, GLsizei stride, const GLvoid *ptr)
268 {
269    const GLbitfield legalTypes = (UNSIGNED_BYTE_BIT | SHORT_BIT | INT_BIT |
270                                   FLOAT_BIT | DOUBLE_BIT);
271    GET_CURRENT_CONTEXT(ctx);
272    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
273
274    update_array(ctx, "glIndexPointer",
275                 &ctx->Array.ArrayObj->Index, _NEW_ARRAY_INDEX,
276                 legalTypes, 1, 1,
277                 1, type, stride, GL_FALSE, GL_FALSE, ptr);
278 }
279
280
281 void GLAPIENTRY
282 _mesa_SecondaryColorPointerEXT(GLint size, GLenum type,
283                                GLsizei stride, const GLvoid *ptr)
284 {
285    const GLbitfield legalTypes = (BYTE_BIT | UNSIGNED_BYTE_BIT |
286                                   SHORT_BIT | UNSIGNED_SHORT_BIT |
287                                   INT_BIT | UNSIGNED_INT_BIT |
288                                   HALF_BIT | FLOAT_BIT | DOUBLE_BIT);
289    GET_CURRENT_CONTEXT(ctx);
290    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
291
292    update_array(ctx, "glSecondaryColorPointer",
293                 &ctx->Array.ArrayObj->SecondaryColor, _NEW_ARRAY_COLOR1,
294                 legalTypes, 3, BGRA_OR_4,
295                 size, type, stride, GL_TRUE, GL_FALSE, ptr);
296 }
297
298
299 void GLAPIENTRY
300 _mesa_TexCoordPointer(GLint size, GLenum type, GLsizei stride,
301                       const GLvoid *ptr)
302 {
303    GLbitfield legalTypes = (SHORT_BIT | INT_BIT |
304                             HALF_BIT | FLOAT_BIT | DOUBLE_BIT |
305                             FIXED_ES_BIT);
306    GET_CURRENT_CONTEXT(ctx);
307    const GLuint unit = ctx->Array.ActiveTexture;
308    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
309
310    if (ctx->API == API_OPENGLES)
311       legalTypes |= BYTE_BIT;
312
313    ASSERT(unit < Elements(ctx->Array.ArrayObj->TexCoord));
314
315    update_array(ctx, "glTexCoordPointer",
316                 &ctx->Array.ArrayObj->TexCoord[unit],
317                 _NEW_ARRAY_TEXCOORD(unit),
318                 legalTypes, 1, 4,
319                 size, type, stride, GL_FALSE, GL_FALSE,
320                 ptr);
321 }
322
323
324 void GLAPIENTRY
325 _mesa_EdgeFlagPointer(GLsizei stride, const GLvoid *ptr)
326 {
327    const GLbitfield legalTypes = UNSIGNED_BYTE_BIT;
328    /* see table 2.4 edits in GL_EXT_gpu_shader4 spec: */
329    const GLboolean integer = GL_TRUE;
330    GET_CURRENT_CONTEXT(ctx);
331    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
332
333    update_array(ctx, "glEdgeFlagPointer",
334                 &ctx->Array.ArrayObj->EdgeFlag, _NEW_ARRAY_EDGEFLAG,
335                 legalTypes, 1, 1,
336                 1, GL_UNSIGNED_BYTE, stride, GL_FALSE, integer, ptr);
337 }
338
339
340 void GLAPIENTRY
341 _mesa_PointSizePointer(GLenum type, GLsizei stride, const GLvoid *ptr)
342 {
343    const GLbitfield legalTypes = (FLOAT_BIT | FIXED_ES_BIT);
344    GET_CURRENT_CONTEXT(ctx);
345    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
346
347    if (ctx->API != API_OPENGLES) {
348       _mesa_error(ctx, GL_INVALID_OPERATION,
349                   "glPointSizePointer(ES 1.x only)");
350       return;
351    }
352       
353    update_array(ctx, "glPointSizePointer",
354                 &ctx->Array.ArrayObj->PointSize, _NEW_ARRAY_POINT_SIZE,
355                 legalTypes, 1, 1,
356                 1, type, stride, GL_FALSE, GL_FALSE, ptr);
357 }
358
359
360 #if FEATURE_NV_vertex_program
361 /**
362  * Set a vertex attribute array.
363  * Note that these arrays DO alias the conventional GL vertex arrays
364  * (position, normal, color, fog, texcoord, etc).
365  * The generic attribute slots at #16 and above are not touched.
366  */
367 void GLAPIENTRY
368 _mesa_VertexAttribPointerNV(GLuint index, GLint size, GLenum type,
369                             GLsizei stride, const GLvoid *ptr)
370 {
371    const GLbitfield legalTypes = (UNSIGNED_BYTE_BIT | SHORT_BIT |
372                                   FLOAT_BIT | DOUBLE_BIT);
373    GLboolean normalized = GL_FALSE;
374    GET_CURRENT_CONTEXT(ctx);
375    ASSERT_OUTSIDE_BEGIN_END(ctx);
376
377    if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
378       _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerNV(index)");
379       return;
380    }
381
382    if (type == GL_UNSIGNED_BYTE && size != 4) {
383       _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerNV(size!=4)");
384       return;
385    }
386
387    update_array(ctx, "glVertexAttribPointerNV",
388                 &ctx->Array.ArrayObj->VertexAttrib[index],
389                 _NEW_ARRAY_ATTRIB(index),
390                 legalTypes, 1, BGRA_OR_4,
391                 size, type, stride, normalized, GL_FALSE, ptr);
392 }
393 #endif
394
395
396 #if FEATURE_ARB_vertex_program
397 /**
398  * Set a generic vertex attribute array.
399  * Note that these arrays DO NOT alias the conventional GL vertex arrays
400  * (position, normal, color, fog, texcoord, etc).
401  */
402 void GLAPIENTRY
403 _mesa_VertexAttribPointerARB(GLuint index, GLint size, GLenum type,
404                              GLboolean normalized,
405                              GLsizei stride, const GLvoid *ptr)
406 {
407    const GLbitfield legalTypes = (BYTE_BIT | UNSIGNED_BYTE_BIT |
408                                   SHORT_BIT | UNSIGNED_SHORT_BIT |
409                                   INT_BIT | UNSIGNED_INT_BIT |
410                                   HALF_BIT | FLOAT_BIT | DOUBLE_BIT |
411                                   FIXED_ES_BIT | FIXED_GL_BIT);
412    GET_CURRENT_CONTEXT(ctx);
413    ASSERT_OUTSIDE_BEGIN_END(ctx);
414
415    if (index >= ctx->Const.VertexProgram.MaxAttribs) {
416       _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribPointerARB(index)");
417       return;
418    }
419
420    update_array(ctx, "glVertexAttribPointer",
421                 &ctx->Array.ArrayObj->VertexAttrib[index],
422                 _NEW_ARRAY_ATTRIB(index),
423                 legalTypes, 1, BGRA_OR_4,
424                 size, type, stride, normalized, GL_FALSE, ptr);
425 }
426 #endif
427
428
429 /**
430  * GL_EXT_gpu_shader4 / GL 3.0.
431  * Set an integer-valued vertex attribute array.
432  * Note that these arrays DO NOT alias the conventional GL vertex arrays
433  * (position, normal, color, fog, texcoord, etc).
434  */
435 void GLAPIENTRY
436 _mesa_VertexAttribIPointer(GLuint index, GLint size, GLenum type,
437                            GLsizei stride, const GLvoid *ptr)
438 {
439    const GLbitfield legalTypes = (BYTE_BIT | UNSIGNED_BYTE_BIT |
440                                   SHORT_BIT | UNSIGNED_SHORT_BIT |
441                                   INT_BIT | UNSIGNED_INT_BIT);
442    const GLboolean normalized = GL_FALSE;
443    const GLboolean integer = GL_TRUE;
444    GET_CURRENT_CONTEXT(ctx);
445    ASSERT_OUTSIDE_BEGIN_END(ctx);
446
447    if (index >= ctx->Const.VertexProgram.MaxAttribs) {
448       _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribIPointer(index)");
449       return;
450    }
451
452    update_array(ctx, "glVertexAttribIPointer",
453                 &ctx->Array.ArrayObj->VertexAttrib[index],
454                 _NEW_ARRAY_ATTRIB(index),
455                 legalTypes, 1, 4,
456                 size, type, stride, normalized, integer, ptr);
457 }
458
459
460
461 void GLAPIENTRY
462 _mesa_EnableVertexAttribArrayARB(GLuint index)
463 {
464    GET_CURRENT_CONTEXT(ctx);
465    ASSERT_OUTSIDE_BEGIN_END(ctx);
466
467    if (index >= ctx->Const.VertexProgram.MaxAttribs) {
468       _mesa_error(ctx, GL_INVALID_VALUE,
469                   "glEnableVertexAttribArrayARB(index)");
470       return;
471    }
472
473    ASSERT(index < Elements(ctx->Array.ArrayObj->VertexAttrib));
474
475    FLUSH_VERTICES(ctx, _NEW_ARRAY);
476    ctx->Array.ArrayObj->VertexAttrib[index].Enabled = GL_TRUE;
477    ctx->Array.ArrayObj->_Enabled |= _NEW_ARRAY_ATTRIB(index);
478    ctx->Array.NewState |= _NEW_ARRAY_ATTRIB(index);
479 }
480
481
482 void GLAPIENTRY
483 _mesa_DisableVertexAttribArrayARB(GLuint index)
484 {
485    GET_CURRENT_CONTEXT(ctx);
486    ASSERT_OUTSIDE_BEGIN_END(ctx);
487
488    if (index >= ctx->Const.VertexProgram.MaxAttribs) {
489       _mesa_error(ctx, GL_INVALID_VALUE,
490                   "glDisableVertexAttribArrayARB(index)");
491       return;
492    }
493
494    ASSERT(index < Elements(ctx->Array.ArrayObj->VertexAttrib));
495
496    FLUSH_VERTICES(ctx, _NEW_ARRAY);
497    ctx->Array.ArrayObj->VertexAttrib[index].Enabled = GL_FALSE;
498    ctx->Array.ArrayObj->_Enabled &= ~_NEW_ARRAY_ATTRIB(index);
499    ctx->Array.NewState |= _NEW_ARRAY_ATTRIB(index);
500 }
501
502
503 /**
504  * Return info for a vertex attribute array (no alias with legacy
505  * vertex attributes (pos, normal, color, etc)).  This function does
506  * not handle the 4-element GL_CURRENT_VERTEX_ATTRIB_ARB query.
507  */
508 static GLuint
509 get_vertex_array_attrib(struct gl_context *ctx, GLuint index, GLenum pname,
510                   const char *caller)
511 {
512    const struct gl_client_array *array;
513
514    if (index >= ctx->Const.VertexProgram.MaxAttribs) {
515       _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%u)", caller, index);
516       return 0;
517    }
518
519    ASSERT(index < Elements(ctx->Array.ArrayObj->VertexAttrib));
520
521    array = &ctx->Array.ArrayObj->VertexAttrib[index];
522
523    switch (pname) {
524    case GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB:
525       return array->Enabled;
526    case GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB:
527       return array->Size;
528    case GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB:
529       return array->Stride;
530    case GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB:
531       return array->Type;
532    case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB:
533       return array->Normalized;
534    case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB:
535       return array->BufferObj->Name;
536    case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
537       if (ctx->Extensions.EXT_gpu_shader4) {
538          return array->Integer;
539       }
540       goto error;
541    case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB:
542       if (ctx->Extensions.ARB_instanced_arrays) {
543          return array->InstanceDivisor;
544       }
545       goto error;
546    default:
547       ; /* fall-through */
548    }
549
550 error:
551    _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", caller, pname);
552    return 0;
553 }
554
555
556 static const GLfloat *
557 get_current_attrib(struct gl_context *ctx, GLuint index, const char *function)
558 {
559    if (index == 0) {
560       if (ctx->API != API_OPENGLES2) {
561          _mesa_error(ctx, GL_INVALID_OPERATION, "%s(index==0)", function);
562          return NULL;
563       }
564    }
565    else if (index >= ctx->Const.VertexProgram.MaxAttribs) {
566       _mesa_error(ctx, GL_INVALID_VALUE,
567                   "%s(index>=GL_MAX_VERTEX_ATTRIBS)", function);
568       return NULL;
569    }
570
571    FLUSH_CURRENT(ctx, 0);
572    return ctx->Current.Attrib[VERT_ATTRIB_GENERIC0 + index];
573 }
574
575 void GLAPIENTRY
576 _mesa_GetVertexAttribfvARB(GLuint index, GLenum pname, GLfloat *params)
577 {
578    GET_CURRENT_CONTEXT(ctx);
579    ASSERT_OUTSIDE_BEGIN_END(ctx);
580
581    if (pname == GL_CURRENT_VERTEX_ATTRIB_ARB) {
582       const GLfloat *v = get_current_attrib(ctx, index, "glGetVertexAttribfv");
583       if (v != NULL) {
584          COPY_4V(params, v);
585       }
586    }
587    else {
588       params[0] = (GLfloat) get_vertex_array_attrib(ctx, index, pname,
589                                                     "glGetVertexAttribfv");
590    }
591 }
592
593
594 void GLAPIENTRY
595 _mesa_GetVertexAttribdvARB(GLuint index, GLenum pname, GLdouble *params)
596 {
597    GET_CURRENT_CONTEXT(ctx);
598    ASSERT_OUTSIDE_BEGIN_END(ctx);
599
600    if (pname == GL_CURRENT_VERTEX_ATTRIB_ARB) {
601       const GLfloat *v = get_current_attrib(ctx, index, "glGetVertexAttribdv");
602       if (v != NULL) {
603          params[0] = (GLdouble) v[0];
604          params[1] = (GLdouble) v[1];
605          params[2] = (GLdouble) v[2];
606          params[3] = (GLdouble) v[3];
607       }
608    }
609    else {
610       params[0] = (GLdouble) get_vertex_array_attrib(ctx, index, pname,
611                                                      "glGetVertexAttribdv");
612    }
613 }
614
615
616 void GLAPIENTRY
617 _mesa_GetVertexAttribivARB(GLuint index, GLenum pname, GLint *params)
618 {
619    GET_CURRENT_CONTEXT(ctx);
620    ASSERT_OUTSIDE_BEGIN_END(ctx);
621
622    if (pname == GL_CURRENT_VERTEX_ATTRIB_ARB) {
623       const GLfloat *v = get_current_attrib(ctx, index, "glGetVertexAttribiv");
624       if (v != NULL) {
625          /* XXX should floats in[0,1] be scaled to full int range? */
626          params[0] = (GLint) v[0];
627          params[1] = (GLint) v[1];
628          params[2] = (GLint) v[2];
629          params[3] = (GLint) v[3];
630       }
631    }
632    else {
633       params[0] = (GLint) get_vertex_array_attrib(ctx, index, pname,
634                                                   "glGetVertexAttribiv");
635    }
636 }
637
638
639 /** GL 3.0 */
640 void GLAPIENTRY
641 _mesa_GetVertexAttribIiv(GLuint index, GLenum pname, GLint *params)
642 {
643    GET_CURRENT_CONTEXT(ctx);
644    ASSERT_OUTSIDE_BEGIN_END(ctx);
645
646    if (pname == GL_CURRENT_VERTEX_ATTRIB_ARB) {
647       const GLfloat *v =
648          get_current_attrib(ctx, index, "glGetVertexAttribIiv");
649       if (v != NULL) {
650          /* XXX we don't have true integer-valued vertex attribs yet */
651          params[0] = (GLint) v[0];
652          params[1] = (GLint) v[1];
653          params[2] = (GLint) v[2];
654          params[3] = (GLint) v[3];
655       }
656    }
657    else {
658       params[0] = (GLint) get_vertex_array_attrib(ctx, index, pname,
659                                                   "glGetVertexAttribIiv");
660    }
661 }
662
663
664 /** GL 3.0 */
665 void GLAPIENTRY
666 _mesa_GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params)
667 {
668    GET_CURRENT_CONTEXT(ctx);
669    ASSERT_OUTSIDE_BEGIN_END(ctx);
670
671    if (pname == GL_CURRENT_VERTEX_ATTRIB_ARB) {
672       const GLfloat *v =
673          get_current_attrib(ctx, index, "glGetVertexAttribIuiv");
674       if (v != NULL) {
675          /* XXX we don't have true integer-valued vertex attribs yet */
676          params[0] = (GLuint) v[0];
677          params[1] = (GLuint) v[1];
678          params[2] = (GLuint) v[2];
679          params[3] = (GLuint) v[3];
680       }
681    }
682    else {
683       params[0] = get_vertex_array_attrib(ctx, index, pname,
684                                           "glGetVertexAttribIuiv");
685    }
686 }
687
688
689 void GLAPIENTRY
690 _mesa_GetVertexAttribPointervARB(GLuint index, GLenum pname, GLvoid **pointer)
691 {
692    GET_CURRENT_CONTEXT(ctx);
693    ASSERT_OUTSIDE_BEGIN_END(ctx);
694
695    if (index >= ctx->Const.VertexProgram.MaxAttribs) {
696       _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribPointerARB(index)");
697       return;
698    }
699
700    if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB) {
701       _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribPointerARB(pname)");
702       return;
703    }
704
705    ASSERT(index < Elements(ctx->Array.ArrayObj->VertexAttrib));
706
707    *pointer = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[index].Ptr;
708 }
709
710
711 void GLAPIENTRY
712 _mesa_VertexPointerEXT(GLint size, GLenum type, GLsizei stride,
713                        GLsizei count, const GLvoid *ptr)
714 {
715    (void) count;
716    _mesa_VertexPointer(size, type, stride, ptr);
717 }
718
719
720 void GLAPIENTRY
721 _mesa_NormalPointerEXT(GLenum type, GLsizei stride, GLsizei count,
722                        const GLvoid *ptr)
723 {
724    (void) count;
725    _mesa_NormalPointer(type, stride, ptr);
726 }
727
728
729 void GLAPIENTRY
730 _mesa_ColorPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count,
731                       const GLvoid *ptr)
732 {
733    (void) count;
734    _mesa_ColorPointer(size, type, stride, ptr);
735 }
736
737
738 void GLAPIENTRY
739 _mesa_IndexPointerEXT(GLenum type, GLsizei stride, GLsizei count,
740                       const GLvoid *ptr)
741 {
742    (void) count;
743    _mesa_IndexPointer(type, stride, ptr);
744 }
745
746
747 void GLAPIENTRY
748 _mesa_TexCoordPointerEXT(GLint size, GLenum type, GLsizei stride,
749                          GLsizei count, const GLvoid *ptr)
750 {
751    (void) count;
752    _mesa_TexCoordPointer(size, type, stride, ptr);
753 }
754
755
756 void GLAPIENTRY
757 _mesa_EdgeFlagPointerEXT(GLsizei stride, GLsizei count, const GLboolean *ptr)
758 {
759    (void) count;
760    _mesa_EdgeFlagPointer(stride, ptr);
761 }
762
763
764 void GLAPIENTRY
765 _mesa_InterleavedArrays(GLenum format, GLsizei stride, const GLvoid *pointer)
766 {
767    GET_CURRENT_CONTEXT(ctx);
768    GLboolean tflag, cflag, nflag;  /* enable/disable flags */
769    GLint tcomps, ccomps, vcomps;   /* components per texcoord, color, vertex */
770    GLenum ctype = 0;               /* color type */
771    GLint coffset = 0, noffset = 0, voffset;/* color, normal, vertex offsets */
772    const GLint toffset = 0;        /* always zero */
773    GLint defstride;                /* default stride */
774    GLint c, f;
775
776    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
777
778    f = sizeof(GLfloat);
779    c = f * ((4 * sizeof(GLubyte) + (f - 1)) / f);
780
781    if (stride < 0) {
782       _mesa_error( ctx, GL_INVALID_VALUE, "glInterleavedArrays(stride)" );
783       return;
784    }
785
786    switch (format) {
787       case GL_V2F:
788          tflag = GL_FALSE;  cflag = GL_FALSE;  nflag = GL_FALSE;
789          tcomps = 0;  ccomps = 0;  vcomps = 2;
790          voffset = 0;
791          defstride = 2*f;
792          break;
793       case GL_V3F:
794          tflag = GL_FALSE;  cflag = GL_FALSE;  nflag = GL_FALSE;
795          tcomps = 0;  ccomps = 0;  vcomps = 3;
796          voffset = 0;
797          defstride = 3*f;
798          break;
799       case GL_C4UB_V2F:
800          tflag = GL_FALSE;  cflag = GL_TRUE;  nflag = GL_FALSE;
801          tcomps = 0;  ccomps = 4;  vcomps = 2;
802          ctype = GL_UNSIGNED_BYTE;
803          coffset = 0;
804          voffset = c;
805          defstride = c + 2*f;
806          break;
807       case GL_C4UB_V3F:
808          tflag = GL_FALSE;  cflag = GL_TRUE;  nflag = GL_FALSE;
809          tcomps = 0;  ccomps = 4;  vcomps = 3;
810          ctype = GL_UNSIGNED_BYTE;
811          coffset = 0;
812          voffset = c;
813          defstride = c + 3*f;
814          break;
815       case GL_C3F_V3F:
816          tflag = GL_FALSE;  cflag = GL_TRUE;  nflag = GL_FALSE;
817          tcomps = 0;  ccomps = 3;  vcomps = 3;
818          ctype = GL_FLOAT;
819          coffset = 0;
820          voffset = 3*f;
821          defstride = 6*f;
822          break;
823       case GL_N3F_V3F:
824          tflag = GL_FALSE;  cflag = GL_FALSE;  nflag = GL_TRUE;
825          tcomps = 0;  ccomps = 0;  vcomps = 3;
826          noffset = 0;
827          voffset = 3*f;
828          defstride = 6*f;
829          break;
830       case GL_C4F_N3F_V3F:
831          tflag = GL_FALSE;  cflag = GL_TRUE;  nflag = GL_TRUE;
832          tcomps = 0;  ccomps = 4;  vcomps = 3;
833          ctype = GL_FLOAT;
834          coffset = 0;
835          noffset = 4*f;
836          voffset = 7*f;
837          defstride = 10*f;
838          break;
839       case GL_T2F_V3F:
840          tflag = GL_TRUE;  cflag = GL_FALSE;  nflag = GL_FALSE;
841          tcomps = 2;  ccomps = 0;  vcomps = 3;
842          voffset = 2*f;
843          defstride = 5*f;
844          break;
845       case GL_T4F_V4F:
846          tflag = GL_TRUE;  cflag = GL_FALSE;  nflag = GL_FALSE;
847          tcomps = 4;  ccomps = 0;  vcomps = 4;
848          voffset = 4*f;
849          defstride = 8*f;
850          break;
851       case GL_T2F_C4UB_V3F:
852          tflag = GL_TRUE;  cflag = GL_TRUE;  nflag = GL_FALSE;
853          tcomps = 2;  ccomps = 4;  vcomps = 3;
854          ctype = GL_UNSIGNED_BYTE;
855          coffset = 2*f;
856          voffset = c+2*f;
857          defstride = c+5*f;
858          break;
859       case GL_T2F_C3F_V3F:
860          tflag = GL_TRUE;  cflag = GL_TRUE;  nflag = GL_FALSE;
861          tcomps = 2;  ccomps = 3;  vcomps = 3;
862          ctype = GL_FLOAT;
863          coffset = 2*f;
864          voffset = 5*f;
865          defstride = 8*f;
866          break;
867       case GL_T2F_N3F_V3F:
868          tflag = GL_TRUE;  cflag = GL_FALSE;  nflag = GL_TRUE;
869          tcomps = 2;  ccomps = 0;  vcomps = 3;
870          noffset = 2*f;
871          voffset = 5*f;
872          defstride = 8*f;
873          break;
874       case GL_T2F_C4F_N3F_V3F:
875          tflag = GL_TRUE;  cflag = GL_TRUE;  nflag = GL_TRUE;
876          tcomps = 2;  ccomps = 4;  vcomps = 3;
877          ctype = GL_FLOAT;
878          coffset = 2*f;
879          noffset = 6*f;
880          voffset = 9*f;
881          defstride = 12*f;
882          break;
883       case GL_T4F_C4F_N3F_V4F:
884          tflag = GL_TRUE;  cflag = GL_TRUE;  nflag = GL_TRUE;
885          tcomps = 4;  ccomps = 4;  vcomps = 4;
886          ctype = GL_FLOAT;
887          coffset = 4*f;
888          noffset = 8*f;
889          voffset = 11*f;
890          defstride = 15*f;
891          break;
892       default:
893          _mesa_error( ctx, GL_INVALID_ENUM, "glInterleavedArrays(format)" );
894          return;
895    }
896
897    if (stride==0) {
898       stride = defstride;
899    }
900
901    _mesa_DisableClientState( GL_EDGE_FLAG_ARRAY );
902    _mesa_DisableClientState( GL_INDEX_ARRAY );
903    /* XXX also disable secondary color and generic arrays? */
904
905    /* Texcoords */
906    if (tflag) {
907       _mesa_EnableClientState( GL_TEXTURE_COORD_ARRAY );
908       _mesa_TexCoordPointer( tcomps, GL_FLOAT, stride,
909                              (GLubyte *) pointer + toffset );
910    }
911    else {
912       _mesa_DisableClientState( GL_TEXTURE_COORD_ARRAY );
913    }
914
915    /* Color */
916    if (cflag) {
917       _mesa_EnableClientState( GL_COLOR_ARRAY );
918       _mesa_ColorPointer( ccomps, ctype, stride,
919                           (GLubyte *) pointer + coffset );
920    }
921    else {
922       _mesa_DisableClientState( GL_COLOR_ARRAY );
923    }
924
925
926    /* Normals */
927    if (nflag) {
928       _mesa_EnableClientState( GL_NORMAL_ARRAY );
929       _mesa_NormalPointer( GL_FLOAT, stride, (GLubyte *) pointer + noffset );
930    }
931    else {
932       _mesa_DisableClientState( GL_NORMAL_ARRAY );
933    }
934
935    /* Vertices */
936    _mesa_EnableClientState( GL_VERTEX_ARRAY );
937    _mesa_VertexPointer( vcomps, GL_FLOAT, stride,
938                         (GLubyte *) pointer + voffset );
939 }
940
941
942 void GLAPIENTRY
943 _mesa_LockArraysEXT(GLint first, GLsizei count)
944 {
945    GET_CURRENT_CONTEXT(ctx);
946    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
947
948    if (MESA_VERBOSE & VERBOSE_API)
949       _mesa_debug(ctx, "glLockArrays %d %d\n", first, count);
950
951    if (first < 0) {
952       _mesa_error( ctx, GL_INVALID_VALUE, "glLockArraysEXT(first)" );
953       return;
954    }
955    if (count <= 0) {
956       _mesa_error( ctx, GL_INVALID_VALUE, "glLockArraysEXT(count)" );
957       return;
958    }
959    if (ctx->Array.LockCount != 0) {
960       _mesa_error( ctx, GL_INVALID_OPERATION, "glLockArraysEXT(reentry)" );
961       return;
962    }
963
964    ctx->Array.LockFirst = first;
965    ctx->Array.LockCount = count;
966
967    ctx->NewState |= _NEW_ARRAY;
968    ctx->Array.NewState |= _NEW_ARRAY_ALL;
969 }
970
971
972 void GLAPIENTRY
973 _mesa_UnlockArraysEXT( void )
974 {
975    GET_CURRENT_CONTEXT(ctx);
976    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
977
978    if (MESA_VERBOSE & VERBOSE_API)
979       _mesa_debug(ctx, "glUnlockArrays\n");
980
981    if (ctx->Array.LockCount == 0) {
982       _mesa_error( ctx, GL_INVALID_OPERATION, "glUnlockArraysEXT(reexit)" );
983       return;
984    }
985
986    ctx->Array.LockFirst = 0;
987    ctx->Array.LockCount = 0;
988    ctx->NewState |= _NEW_ARRAY;
989    ctx->Array.NewState |= _NEW_ARRAY_ALL;
990 }
991
992
993 /* GL_EXT_multi_draw_arrays */
994 void GLAPIENTRY
995 _mesa_MultiDrawArraysEXT( GLenum mode, const GLint *first,
996                           const GLsizei *count, GLsizei primcount )
997 {
998    GET_CURRENT_CONTEXT(ctx);
999    GLint i;
1000
1001    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
1002
1003    for (i = 0; i < primcount; i++) {
1004       if (count[i] > 0) {
1005          CALL_DrawArrays(ctx->Exec, (mode, first[i], count[i]));
1006       }
1007    }
1008 }
1009
1010
1011 /* GL_IBM_multimode_draw_arrays */
1012 void GLAPIENTRY
1013 _mesa_MultiModeDrawArraysIBM( const GLenum * mode, const GLint * first,
1014                               const GLsizei * count,
1015                               GLsizei primcount, GLint modestride )
1016 {
1017    GET_CURRENT_CONTEXT(ctx);
1018    GLint i;
1019
1020    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
1021
1022    for ( i = 0 ; i < primcount ; i++ ) {
1023       if ( count[i] > 0 ) {
1024          GLenum m = *((GLenum *) ((GLubyte *) mode + i * modestride));
1025          CALL_DrawArrays(ctx->Exec, ( m, first[i], count[i] ));
1026       }
1027    }
1028 }
1029
1030
1031 /* GL_IBM_multimode_draw_arrays */
1032 void GLAPIENTRY
1033 _mesa_MultiModeDrawElementsIBM( const GLenum * mode, const GLsizei * count,
1034                                 GLenum type, const GLvoid * const * indices,
1035                                 GLsizei primcount, GLint modestride )
1036 {
1037    GET_CURRENT_CONTEXT(ctx);
1038    GLint i;
1039
1040    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
1041
1042    /* XXX not sure about ARB_vertex_buffer_object handling here */
1043
1044    for ( i = 0 ; i < primcount ; i++ ) {
1045       if ( count[i] > 0 ) {
1046          GLenum m = *((GLenum *) ((GLubyte *) mode + i * modestride));
1047          CALL_DrawElements(ctx->Exec, ( m, count[i], type, indices[i] ));
1048       }
1049    }
1050 }
1051
1052
1053 /**
1054  * GL_NV_primitive_restart and GL 3.1
1055  */
1056 void GLAPIENTRY
1057 _mesa_PrimitiveRestartIndex(GLuint index)
1058 {
1059    GET_CURRENT_CONTEXT(ctx);
1060
1061    if (!ctx->Extensions.NV_primitive_restart &&
1062        ctx->VersionMajor * 10 + ctx->VersionMinor < 31) {
1063       _mesa_error(ctx, GL_INVALID_OPERATION, "glPrimitiveRestartIndexNV()");
1064       return;
1065    }
1066
1067    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
1068
1069    FLUSH_VERTICES(ctx, _NEW_TRANSFORM);
1070
1071    ctx->Array.RestartIndex = index;
1072 }
1073
1074
1075 /**
1076  * See GL_ARB_instanced_arrays.
1077  * Note that the instance divisor only applies to generic arrays, not
1078  * the legacy vertex arrays.
1079  */
1080 void GLAPIENTRY
1081 _mesa_VertexAttribDivisor(GLuint index, GLuint divisor)
1082 {
1083    GET_CURRENT_CONTEXT(ctx);
1084    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
1085
1086    if (!ctx->Extensions.ARB_instanced_arrays) {
1087       _mesa_error(ctx, GL_INVALID_OPERATION, "glVertexAttribDivisor()");
1088       return;
1089    }
1090
1091    if (index >= ctx->Const.VertexProgram.MaxAttribs) {
1092       _mesa_error(ctx, GL_INVALID_ENUM, "glVertexAttribDivisor(index = %u)",
1093                   index);
1094       return;
1095    }
1096
1097    ctx->Array.ArrayObj->VertexAttrib[index].InstanceDivisor = divisor;
1098 }
1099
1100
1101
1102 /**
1103  * Copy one client vertex array to another.
1104  */
1105 void
1106 _mesa_copy_client_array(struct gl_context *ctx,
1107                         struct gl_client_array *dst,
1108                         struct gl_client_array *src)
1109 {
1110    dst->Size = src->Size;
1111    dst->Type = src->Type;
1112    dst->Format = src->Format;
1113    dst->Stride = src->Stride;
1114    dst->StrideB = src->StrideB;
1115    dst->Ptr = src->Ptr;
1116    dst->Enabled = src->Enabled;
1117    dst->Normalized = src->Normalized;
1118    dst->Integer = src->Integer;
1119    dst->InstanceDivisor = src->InstanceDivisor;
1120    dst->_ElementSize = src->_ElementSize;
1121    _mesa_reference_buffer_object(ctx, &dst->BufferObj, src->BufferObj);
1122    dst->_MaxElement = src->_MaxElement;
1123 }
1124
1125
1126
1127 /**
1128  * Print vertex array's fields.
1129  */
1130 static void
1131 print_array(const char *name, GLint index, const struct gl_client_array *array)
1132 {
1133    if (index >= 0)
1134       printf("  %s[%d]: ", name, index);
1135    else
1136       printf("  %s: ", name);
1137    printf("Ptr=%p, Type=0x%x, Size=%d, ElemSize=%u, Stride=%d, Buffer=%u(Size %lu), MaxElem=%u\n",
1138           array->Ptr, array->Type, array->Size,
1139           array->_ElementSize, array->StrideB,
1140           array->BufferObj->Name, (unsigned long) array->BufferObj->Size,
1141           array->_MaxElement);
1142 }
1143
1144
1145 /**
1146  * Print current vertex object/array info.  For debug.
1147  */
1148 void
1149 _mesa_print_arrays(struct gl_context *ctx)
1150 {
1151    struct gl_array_object *arrayObj = ctx->Array.ArrayObj;
1152    GLuint i;
1153
1154    _mesa_update_array_object_max_element(ctx, arrayObj);
1155
1156    printf("Array Object %u\n", arrayObj->Name);
1157    if (arrayObj->Vertex.Enabled)
1158       print_array("Vertex", -1, &arrayObj->Vertex);
1159    if (arrayObj->Normal.Enabled)
1160       print_array("Normal", -1, &arrayObj->Normal);
1161    if (arrayObj->Color.Enabled)
1162       print_array("Color", -1, &arrayObj->Color);
1163    for (i = 0; i < Elements(arrayObj->TexCoord); i++)
1164       if (arrayObj->TexCoord[i].Enabled)
1165          print_array("TexCoord", i, &arrayObj->TexCoord[i]);
1166    for (i = 0; i < Elements(arrayObj->VertexAttrib); i++)
1167       if (arrayObj->VertexAttrib[i].Enabled)
1168          print_array("Attrib", i, &arrayObj->VertexAttrib[i]);
1169    printf("  _MaxElement = %u\n", arrayObj->_MaxElement);
1170 }
1171
1172
1173 /**
1174  * Initialize vertex array state for given context.
1175  */
1176 void 
1177 _mesa_init_varray(struct gl_context *ctx)
1178 {
1179    ctx->Array.DefaultArrayObj = _mesa_new_array_object(ctx, 0);
1180    _mesa_reference_array_object(ctx, &ctx->Array.ArrayObj,
1181                                 ctx->Array.DefaultArrayObj);
1182    ctx->Array.ActiveTexture = 0;   /* GL_ARB_multitexture */
1183
1184    ctx->Array.Objects = _mesa_NewHashTable();
1185 }
1186
1187
1188 /**
1189  * Callback for deleting an array object.  Called by _mesa_HashDeleteAll().
1190  */
1191 static void
1192 delete_arrayobj_cb(GLuint id, void *data, void *userData)
1193 {
1194    struct gl_array_object *arrayObj = (struct gl_array_object *) data;
1195    struct gl_context *ctx = (struct gl_context *) userData;
1196    _mesa_delete_array_object(ctx, arrayObj);
1197 }
1198
1199
1200 /**
1201  * Free vertex array state for given context.
1202  */
1203 void 
1204 _mesa_free_varray_data(struct gl_context *ctx)
1205 {
1206    _mesa_HashDeleteAll(ctx->Array.Objects, delete_arrayobj_cb, ctx);
1207    _mesa_DeleteHashTable(ctx->Array.Objects);
1208 }