• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5  * (C) Copyright IBM Corporation 2006
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  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24  * OTHER DEALINGS IN THE SOFTWARE.
25  */
26 
27 
28 /**
29  * \file arrayobj.c
30  *
31  * Implementation of Vertex Array Objects (VAOs), from OpenGL 3.1+ /
32  * the GL_ARB_vertex_array_object extension.
33  *
34  * \todo
35  * The code in this file borrows a lot from bufferobj.c.  There's a certain
36  * amount of cruft left over from that origin that may be unnecessary.
37  *
38  * \author Ian Romanick <idr@us.ibm.com>
39  * \author Brian Paul
40  */
41 
42 
43 #include "glheader.h"
44 #include "hash.h"
45 #include "image.h"
46 
47 #include "context.h"
48 #include "bufferobj.h"
49 #include "arrayobj.h"
50 #include "draw_validate.h"
51 #include "macros.h"
52 #include "mtypes.h"
53 #include "state.h"
54 #include "varray.h"
55 #include "util/bitscan.h"
56 #include "util/u_atomic.h"
57 #include "util/u_math.h"
58 #include "util/u_memory.h"
59 #include "api_exec_decl.h"
60 
61 const GLubyte
62 _mesa_vao_attribute_map[ATTRIBUTE_MAP_MODE_MAX][VERT_ATTRIB_MAX] =
63 {
64    /* ATTRIBUTE_MAP_MODE_IDENTITY
65     *
66     * Grab vertex processing attribute VERT_ATTRIB_POS from
67     * the VAO attribute VERT_ATTRIB_POS, and grab vertex processing
68     * attribute VERT_ATTRIB_GENERIC0 from the VAO attribute
69     * VERT_ATTRIB_GENERIC0.
70     */
71    {
72       VERT_ATTRIB_POS,                 /* VERT_ATTRIB_POS */
73       VERT_ATTRIB_NORMAL,              /* VERT_ATTRIB_NORMAL */
74       VERT_ATTRIB_COLOR0,              /* VERT_ATTRIB_COLOR0 */
75       VERT_ATTRIB_COLOR1,              /* VERT_ATTRIB_COLOR1 */
76       VERT_ATTRIB_FOG,                 /* VERT_ATTRIB_FOG */
77       VERT_ATTRIB_COLOR_INDEX,         /* VERT_ATTRIB_COLOR_INDEX */
78       VERT_ATTRIB_TEX0,                /* VERT_ATTRIB_TEX0 */
79       VERT_ATTRIB_TEX1,                /* VERT_ATTRIB_TEX1 */
80       VERT_ATTRIB_TEX2,                /* VERT_ATTRIB_TEX2 */
81       VERT_ATTRIB_TEX3,                /* VERT_ATTRIB_TEX3 */
82       VERT_ATTRIB_TEX4,                /* VERT_ATTRIB_TEX4 */
83       VERT_ATTRIB_TEX5,                /* VERT_ATTRIB_TEX5 */
84       VERT_ATTRIB_TEX6,                /* VERT_ATTRIB_TEX6 */
85       VERT_ATTRIB_TEX7,                /* VERT_ATTRIB_TEX7 */
86       VERT_ATTRIB_POINT_SIZE,          /* VERT_ATTRIB_POINT_SIZE */
87       VERT_ATTRIB_GENERIC0,            /* VERT_ATTRIB_GENERIC0 */
88       VERT_ATTRIB_GENERIC1,            /* VERT_ATTRIB_GENERIC1 */
89       VERT_ATTRIB_GENERIC2,            /* VERT_ATTRIB_GENERIC2 */
90       VERT_ATTRIB_GENERIC3,            /* VERT_ATTRIB_GENERIC3 */
91       VERT_ATTRIB_GENERIC4,            /* VERT_ATTRIB_GENERIC4 */
92       VERT_ATTRIB_GENERIC5,            /* VERT_ATTRIB_GENERIC5 */
93       VERT_ATTRIB_GENERIC6,            /* VERT_ATTRIB_GENERIC6 */
94       VERT_ATTRIB_GENERIC7,            /* VERT_ATTRIB_GENERIC7 */
95       VERT_ATTRIB_GENERIC8,            /* VERT_ATTRIB_GENERIC8 */
96       VERT_ATTRIB_GENERIC9,            /* VERT_ATTRIB_GENERIC9 */
97       VERT_ATTRIB_GENERIC10,           /* VERT_ATTRIB_GENERIC10 */
98       VERT_ATTRIB_GENERIC11,           /* VERT_ATTRIB_GENERIC11 */
99       VERT_ATTRIB_GENERIC12,           /* VERT_ATTRIB_GENERIC12 */
100       VERT_ATTRIB_GENERIC13,           /* VERT_ATTRIB_GENERIC13 */
101       VERT_ATTRIB_GENERIC14,           /* VERT_ATTRIB_GENERIC14 */
102       VERT_ATTRIB_GENERIC15,           /* VERT_ATTRIB_GENERIC15 */
103       VERT_ATTRIB_EDGEFLAG,            /* VERT_ATTRIB_EDGEFLAG */
104    },
105 
106    /* ATTRIBUTE_MAP_MODE_POSITION
107     *
108     * Grab vertex processing attribute VERT_ATTRIB_POS as well as
109     * vertex processing attribute VERT_ATTRIB_GENERIC0 from the
110     * VAO attribute VERT_ATTRIB_POS.
111     */
112    {
113       VERT_ATTRIB_POS,                 /* VERT_ATTRIB_POS */
114       VERT_ATTRIB_NORMAL,              /* VERT_ATTRIB_NORMAL */
115       VERT_ATTRIB_COLOR0,              /* VERT_ATTRIB_COLOR0 */
116       VERT_ATTRIB_COLOR1,              /* VERT_ATTRIB_COLOR1 */
117       VERT_ATTRIB_FOG,                 /* VERT_ATTRIB_FOG */
118       VERT_ATTRIB_COLOR_INDEX,         /* VERT_ATTRIB_COLOR_INDEX */
119       VERT_ATTRIB_TEX0,                /* VERT_ATTRIB_TEX0 */
120       VERT_ATTRIB_TEX1,                /* VERT_ATTRIB_TEX1 */
121       VERT_ATTRIB_TEX2,                /* VERT_ATTRIB_TEX2 */
122       VERT_ATTRIB_TEX3,                /* VERT_ATTRIB_TEX3 */
123       VERT_ATTRIB_TEX4,                /* VERT_ATTRIB_TEX4 */
124       VERT_ATTRIB_TEX5,                /* VERT_ATTRIB_TEX5 */
125       VERT_ATTRIB_TEX6,                /* VERT_ATTRIB_TEX6 */
126       VERT_ATTRIB_TEX7,                /* VERT_ATTRIB_TEX7 */
127       VERT_ATTRIB_POINT_SIZE,          /* VERT_ATTRIB_POINT_SIZE */
128       VERT_ATTRIB_POS,                 /* VERT_ATTRIB_GENERIC0 */
129       VERT_ATTRIB_GENERIC1,            /* VERT_ATTRIB_GENERIC1 */
130       VERT_ATTRIB_GENERIC2,            /* VERT_ATTRIB_GENERIC2 */
131       VERT_ATTRIB_GENERIC3,            /* VERT_ATTRIB_GENERIC3 */
132       VERT_ATTRIB_GENERIC4,            /* VERT_ATTRIB_GENERIC4 */
133       VERT_ATTRIB_GENERIC5,            /* VERT_ATTRIB_GENERIC5 */
134       VERT_ATTRIB_GENERIC6,            /* VERT_ATTRIB_GENERIC6 */
135       VERT_ATTRIB_GENERIC7,            /* VERT_ATTRIB_GENERIC7 */
136       VERT_ATTRIB_GENERIC8,            /* VERT_ATTRIB_GENERIC8 */
137       VERT_ATTRIB_GENERIC9,            /* VERT_ATTRIB_GENERIC9 */
138       VERT_ATTRIB_GENERIC10,           /* VERT_ATTRIB_GENERIC10 */
139       VERT_ATTRIB_GENERIC11,           /* VERT_ATTRIB_GENERIC11 */
140       VERT_ATTRIB_GENERIC12,           /* VERT_ATTRIB_GENERIC12 */
141       VERT_ATTRIB_GENERIC13,           /* VERT_ATTRIB_GENERIC13 */
142       VERT_ATTRIB_GENERIC14,           /* VERT_ATTRIB_GENERIC14 */
143       VERT_ATTRIB_GENERIC15,           /* VERT_ATTRIB_GENERIC15 */
144       VERT_ATTRIB_EDGEFLAG,            /* VERT_ATTRIB_EDGEFLAG */
145    },
146 
147    /* ATTRIBUTE_MAP_MODE_GENERIC0
148     *
149     * Grab vertex processing attribute VERT_ATTRIB_POS as well as
150     * vertex processing attribute VERT_ATTRIB_GENERIC0 from the
151     * VAO attribute VERT_ATTRIB_GENERIC0.
152     */
153    {
154       VERT_ATTRIB_GENERIC0,            /* VERT_ATTRIB_POS */
155       VERT_ATTRIB_NORMAL,              /* VERT_ATTRIB_NORMAL */
156       VERT_ATTRIB_COLOR0,              /* VERT_ATTRIB_COLOR0 */
157       VERT_ATTRIB_COLOR1,              /* VERT_ATTRIB_COLOR1 */
158       VERT_ATTRIB_FOG,                 /* VERT_ATTRIB_FOG */
159       VERT_ATTRIB_COLOR_INDEX,         /* VERT_ATTRIB_COLOR_INDEX */
160       VERT_ATTRIB_TEX0,                /* VERT_ATTRIB_TEX0 */
161       VERT_ATTRIB_TEX1,                /* VERT_ATTRIB_TEX1 */
162       VERT_ATTRIB_TEX2,                /* VERT_ATTRIB_TEX2 */
163       VERT_ATTRIB_TEX3,                /* VERT_ATTRIB_TEX3 */
164       VERT_ATTRIB_TEX4,                /* VERT_ATTRIB_TEX4 */
165       VERT_ATTRIB_TEX5,                /* VERT_ATTRIB_TEX5 */
166       VERT_ATTRIB_TEX6,                /* VERT_ATTRIB_TEX6 */
167       VERT_ATTRIB_TEX7,                /* VERT_ATTRIB_TEX7 */
168       VERT_ATTRIB_POINT_SIZE,          /* VERT_ATTRIB_POINT_SIZE */
169       VERT_ATTRIB_GENERIC0,            /* VERT_ATTRIB_GENERIC0 */
170       VERT_ATTRIB_GENERIC1,            /* VERT_ATTRIB_GENERIC1 */
171       VERT_ATTRIB_GENERIC2,            /* VERT_ATTRIB_GENERIC2 */
172       VERT_ATTRIB_GENERIC3,            /* VERT_ATTRIB_GENERIC3 */
173       VERT_ATTRIB_GENERIC4,            /* VERT_ATTRIB_GENERIC4 */
174       VERT_ATTRIB_GENERIC5,            /* VERT_ATTRIB_GENERIC5 */
175       VERT_ATTRIB_GENERIC6,            /* VERT_ATTRIB_GENERIC6 */
176       VERT_ATTRIB_GENERIC7,            /* VERT_ATTRIB_GENERIC7 */
177       VERT_ATTRIB_GENERIC8,            /* VERT_ATTRIB_GENERIC8 */
178       VERT_ATTRIB_GENERIC9,            /* VERT_ATTRIB_GENERIC9 */
179       VERT_ATTRIB_GENERIC10,           /* VERT_ATTRIB_GENERIC10 */
180       VERT_ATTRIB_GENERIC11,           /* VERT_ATTRIB_GENERIC11 */
181       VERT_ATTRIB_GENERIC12,           /* VERT_ATTRIB_GENERIC12 */
182       VERT_ATTRIB_GENERIC13,           /* VERT_ATTRIB_GENERIC13 */
183       VERT_ATTRIB_GENERIC14,           /* VERT_ATTRIB_GENERIC14 */
184       VERT_ATTRIB_GENERIC15,           /* VERT_ATTRIB_GENERIC15 */
185       VERT_ATTRIB_EDGEFLAG,            /* VERT_ATTRIB_EDGEFLAG */
186    }
187 };
188 
189 
190 /**
191  * Look up the array object for the given ID.
192  *
193  * \returns
194  * Either a pointer to the array object with the specified ID or \c NULL for
195  * a non-existent ID.  The spec defines ID 0 as being technically
196  * non-existent.
197  */
198 
199 struct gl_vertex_array_object *
_mesa_lookup_vao(struct gl_context * ctx,GLuint id)200 _mesa_lookup_vao(struct gl_context *ctx, GLuint id)
201 {
202    /* The ARB_direct_state_access specification says:
203     *
204     *    "<vaobj> is [compatibility profile:
205     *     zero, indicating the default vertex array object, or]
206     *     the name of the vertex array object."
207     */
208    if (id == 0) {
209       if (ctx->API == API_OPENGL_COMPAT)
210          return ctx->Array.DefaultVAO;
211 
212       return NULL;
213    } else {
214       struct gl_vertex_array_object *vao;
215 
216       if (ctx->Array.LastLookedUpVAO &&
217           ctx->Array.LastLookedUpVAO->Name == id) {
218          vao = ctx->Array.LastLookedUpVAO;
219       } else {
220          vao = (struct gl_vertex_array_object *)
221             _mesa_HashLookupLocked(ctx->Array.Objects, id);
222 
223          _mesa_reference_vao(ctx, &ctx->Array.LastLookedUpVAO, vao);
224       }
225 
226       return vao;
227    }
228 }
229 
230 
231 /**
232  * Looks up the array object for the given ID.
233  *
234  * While _mesa_lookup_vao doesn't generate an error if the object does not
235  * exist, this function comes in two variants.
236  * If is_ext_dsa is false, this function generates a GL_INVALID_OPERATION
237  * error if the array object does not exist. It also returns the default
238  * array object when ctx is a compatibility profile context and id is zero.
239  * If is_ext_dsa is true, 0 is not a valid name. If the name exists but
240  * the object has never been bound, it is initialized.
241  */
242 struct gl_vertex_array_object *
_mesa_lookup_vao_err(struct gl_context * ctx,GLuint id,bool is_ext_dsa,const char * caller)243 _mesa_lookup_vao_err(struct gl_context *ctx, GLuint id,
244                      bool is_ext_dsa, const char *caller)
245 {
246    /* The ARB_direct_state_access specification says:
247     *
248     *    "<vaobj> is [compatibility profile:
249     *     zero, indicating the default vertex array object, or]
250     *     the name of the vertex array object."
251     */
252    if (id == 0) {
253       if (is_ext_dsa || ctx->API == API_OPENGL_CORE) {
254          _mesa_error(ctx, GL_INVALID_OPERATION,
255                      "%s(zero is not valid vaobj name%s)",
256                      caller,
257                      is_ext_dsa ? "" : " in a core profile context");
258          return NULL;
259       }
260 
261       return ctx->Array.DefaultVAO;
262    } else {
263       struct gl_vertex_array_object *vao;
264 
265       if (ctx->Array.LastLookedUpVAO &&
266           ctx->Array.LastLookedUpVAO->Name == id) {
267          vao = ctx->Array.LastLookedUpVAO;
268       } else {
269          vao = (struct gl_vertex_array_object *)
270             _mesa_HashLookupLocked(ctx->Array.Objects, id);
271 
272          /* The ARB_direct_state_access specification says:
273           *
274           *    "An INVALID_OPERATION error is generated if <vaobj> is not
275           *     [compatibility profile: zero or] the name of an existing
276           *     vertex array object."
277           */
278          if (!vao || (!is_ext_dsa && !vao->EverBound)) {
279             _mesa_error(ctx, GL_INVALID_OPERATION,
280                         "%s(non-existent vaobj=%u)", caller, id);
281             return NULL;
282          }
283 
284          /* The EXT_direct_state_access specification says:
285          *
286          *    "If the vertex array object named by the vaobj parameter has not
287          *     been previously bound but has been generated (without subsequent
288          *     deletion) by GenVertexArrays, the GL first creates a new state
289          *     vector in the same manner as when BindVertexArray creates a new
290          *     vertex array object."
291          */
292          if (vao && is_ext_dsa && !vao->EverBound)
293             vao->EverBound = true;
294 
295          _mesa_reference_vao(ctx, &ctx->Array.LastLookedUpVAO, vao);
296       }
297 
298       return vao;
299    }
300 }
301 
302 
303 /**
304  * For all the vertex binding points in the array object, unbind any pointers
305  * to any buffer objects (VBOs).
306  * This is done just prior to array object destruction.
307  */
308 void
_mesa_unbind_array_object_vbos(struct gl_context * ctx,struct gl_vertex_array_object * obj)309 _mesa_unbind_array_object_vbos(struct gl_context *ctx,
310                                struct gl_vertex_array_object *obj)
311 {
312    GLuint i;
313 
314    for (i = 0; i < ARRAY_SIZE(obj->BufferBinding); i++)
315       _mesa_reference_buffer_object(ctx, &obj->BufferBinding[i].BufferObj, NULL);
316 }
317 
318 
319 /**
320  * Allocate and initialize a new vertex array object.
321  */
322 struct gl_vertex_array_object *
_mesa_new_vao(struct gl_context * ctx,GLuint name)323 _mesa_new_vao(struct gl_context *ctx, GLuint name)
324 {
325    struct gl_vertex_array_object *obj = MALLOC_STRUCT(gl_vertex_array_object);
326    if (obj)
327       _mesa_initialize_vao(ctx, obj, name);
328    return obj;
329 }
330 
331 
332 /**
333  * Delete an array object.
334  */
335 void
_mesa_delete_vao(struct gl_context * ctx,struct gl_vertex_array_object * obj)336 _mesa_delete_vao(struct gl_context *ctx, struct gl_vertex_array_object *obj)
337 {
338    _mesa_unbind_array_object_vbos(ctx, obj);
339    _mesa_reference_buffer_object(ctx, &obj->IndexBufferObj, NULL);
340    free(obj->Label);
341    free(obj);
342 }
343 
344 
345 /**
346  * Set ptr to vao w/ reference counting.
347  * Note: this should only be called from the _mesa_reference_vao()
348  * inline function.
349  */
350 void
_mesa_reference_vao_(struct gl_context * ctx,struct gl_vertex_array_object ** ptr,struct gl_vertex_array_object * vao)351 _mesa_reference_vao_(struct gl_context *ctx,
352                      struct gl_vertex_array_object **ptr,
353                      struct gl_vertex_array_object *vao)
354 {
355    assert(*ptr != vao);
356 
357    if (*ptr) {
358       /* Unreference the old array object */
359       struct gl_vertex_array_object *oldObj = *ptr;
360 
361       bool deleteFlag;
362       if (oldObj->SharedAndImmutable) {
363          deleteFlag = p_atomic_dec_zero(&oldObj->RefCount);
364       } else {
365          assert(oldObj->RefCount > 0);
366          oldObj->RefCount--;
367          deleteFlag = (oldObj->RefCount == 0);
368       }
369 
370       if (deleteFlag)
371          _mesa_delete_vao(ctx, oldObj);
372 
373       *ptr = NULL;
374    }
375    assert(!*ptr);
376 
377    if (vao) {
378       /* reference new array object */
379       if (vao->SharedAndImmutable) {
380          p_atomic_inc(&vao->RefCount);
381       } else {
382          assert(vao->RefCount > 0);
383          vao->RefCount++;
384       }
385 
386       *ptr = vao;
387    }
388 }
389 
390 
391 /**
392  * Initialize a gl_vertex_array_object's arrays.
393  */
394 void
_mesa_initialize_vao(struct gl_context * ctx,struct gl_vertex_array_object * vao,GLuint name)395 _mesa_initialize_vao(struct gl_context *ctx,
396                      struct gl_vertex_array_object *vao,
397                      GLuint name)
398 {
399    memcpy(vao, &ctx->Array.DefaultVAOState, sizeof(*vao));
400    vao->Name = name;
401 }
402 
403 
404 /**
405  * Compute the offset range for the provided binding.
406  *
407  * This is a helper function for the below.
408  */
409 static void
compute_vbo_offset_range(const struct gl_vertex_array_object * vao,const struct gl_vertex_buffer_binding * binding,GLsizeiptr * min,GLsizeiptr * max)410 compute_vbo_offset_range(const struct gl_vertex_array_object *vao,
411                          const struct gl_vertex_buffer_binding *binding,
412                          GLsizeiptr* min, GLsizeiptr* max)
413 {
414    /* The function is meant to work on VBO bindings */
415    assert(binding->BufferObj);
416 
417    /* Start with an inverted range of relative offsets. */
418    GLuint min_offset = ~(GLuint)0;
419    GLuint max_offset = 0;
420 
421    /* We work on the unmapped originaly VAO array entries. */
422    GLbitfield mask = vao->Enabled & binding->_BoundArrays;
423    /* The binding should be active somehow, not to return inverted ranges */
424    assert(mask);
425    while (mask) {
426       const int i = u_bit_scan(&mask);
427       const GLuint off = vao->VertexAttrib[i].RelativeOffset;
428       min_offset = MIN2(off, min_offset);
429       max_offset = MAX2(off, max_offset);
430    }
431 
432    *min = binding->Offset + (GLsizeiptr)min_offset;
433    *max = binding->Offset + (GLsizeiptr)max_offset;
434 }
435 
436 
437 /**
438  * Update the unique binding and pos/generic0 map tracking in the vao.
439  *
440  * The idea is to build up information in the vao so that a consuming
441  * backend can execute the following to set up buffer and vertex element
442  * information:
443  *
444  * const GLbitfield inputs_read = VERT_BIT_ALL; // backend vp inputs
445  *
446  * // Attribute data is in a VBO.
447  * GLbitfield vbomask = inputs_read & _mesa_draw_vbo_array_bits(ctx);
448  * while (vbomask) {
449  *    // The attribute index to start pulling a binding
450  *    const gl_vert_attrib i = ffs(vbomask) - 1;
451  *    const struct gl_vertex_buffer_binding *const binding
452  *       = _mesa_draw_buffer_binding(vao, i);
453  *
454  *    <insert code to handle the vertex buffer object at binding>
455  *
456  *    const GLbitfield boundmask = _mesa_draw_bound_attrib_bits(binding);
457  *    GLbitfield attrmask = vbomask & boundmask;
458  *    assert(attrmask);
459  *    // Walk attributes belonging to the binding
460  *    while (attrmask) {
461  *       const gl_vert_attrib attr = u_bit_scan(&attrmask);
462  *       const struct gl_array_attributes *const attrib
463  *          = _mesa_draw_array_attrib(vao, attr);
464  *
465  *       <insert code to handle the vertex element refering to the binding>
466  *    }
467  *    vbomask &= ~boundmask;
468  * }
469  *
470  * // Process user space buffers
471  * GLbitfield usermask = inputs_read & _mesa_draw_user_array_bits(ctx);
472  * while (usermask) {
473  *    // The attribute index to start pulling a binding
474  *    const gl_vert_attrib i = ffs(usermask) - 1;
475  *    const struct gl_vertex_buffer_binding *const binding
476  *       = _mesa_draw_buffer_binding(vao, i);
477  *
478  *    <insert code to handle a set of interleaved user space arrays at binding>
479  *
480  *    const GLbitfield boundmask = _mesa_draw_bound_attrib_bits(binding);
481  *    GLbitfield attrmask = usermask & boundmask;
482  *    assert(attrmask);
483  *    // Walk interleaved attributes with a common stride and instance divisor
484  *    while (attrmask) {
485  *       const gl_vert_attrib attr = u_bit_scan(&attrmask);
486  *       const struct gl_array_attributes *const attrib
487  *          = _mesa_draw_array_attrib(vao, attr);
488  *
489  *       <insert code to handle non vbo vertex arrays>
490  *    }
491  *    usermask &= ~boundmask;
492  * }
493  *
494  * // Process values that should have better been uniforms in the application
495  * GLbitfield curmask = inputs_read & _mesa_draw_current_bits(ctx);
496  * while (curmask) {
497  *    const gl_vert_attrib attr = u_bit_scan(&curmask);
498  *    const struct gl_array_attributes *const attrib
499  *       = _mesa_draw_current_attrib(ctx, attr);
500  *
501  *    <insert code to handle current values>
502  * }
503  *
504  *
505  * Note that the scan below must not incoporate any context state.
506  * The rationale is that once a VAO is finalized it should not
507  * be touched anymore. That means, do not incorporate the
508  * gl_context::Array._DrawVAOEnabledAttribs bitmask into this scan.
509  * A backend driver may further reduce the handled vertex processing
510  * inputs based on their vertex shader inputs. But scanning for
511  * collapsable binding points to reduce relocs is done based on the
512  * enabled arrays.
513  * Also VAOs may be shared between contexts due to their use in dlists
514  * thus no context state should bleed into the VAO.
515  */
516 void
_mesa_update_vao_derived_arrays(struct gl_context * ctx,struct gl_vertex_array_object * vao)517 _mesa_update_vao_derived_arrays(struct gl_context *ctx,
518                                 struct gl_vertex_array_object *vao)
519 {
520    /* Make sure we do not run into problems with shared objects */
521    assert(!vao->SharedAndImmutable || (!vao->NewVertexBuffers && !vao->NewVertexElements));
522 
523    /* Limit used for common binding scanning below. */
524    const GLsizeiptr MaxRelativeOffset =
525       ctx->Const.MaxVertexAttribRelativeOffset;
526 
527    /* The gl_vertex_array_object::_AttributeMapMode denotes the way
528     * VERT_ATTRIB_{POS,GENERIC0} mapping is done.
529     *
530     * This mapping is used to map between the OpenGL api visible
531     * VERT_ATTRIB_* arrays to mesa driver arrayinputs or shader inputs.
532     * The mapping only depends on the enabled bits of the
533     * VERT_ATTRIB_{POS,GENERIC0} arrays and is tracked in the VAO.
534     *
535     * This map needs to be applied when finally translating to the bitmasks
536     * as consumed by the driver backends. The duplicate scanning is here
537     * can as well be done in the OpenGL API numbering without this map.
538     */
539    const gl_attribute_map_mode mode = vao->_AttributeMapMode;
540    /* Enabled array bits. */
541    const GLbitfield enabled = vao->Enabled;
542    /* VBO array bits. */
543    const GLbitfield vbos = vao->VertexAttribBufferMask;
544    const GLbitfield divisor_is_nonzero = vao->NonZeroDivisorMask;
545 
546    /* Compute and store effectively enabled and mapped vbo arrays */
547    vao->_EffEnabledVBO = _mesa_vao_enable_to_vp_inputs(mode, enabled & vbos);
548    vao->_EffEnabledNonZeroDivisor =
549       _mesa_vao_enable_to_vp_inputs(mode, enabled & divisor_is_nonzero);
550 
551    /* Fast path when the VAO is updated too often. */
552    if (vao->IsDynamic)
553       return;
554 
555    /* More than 4 updates turn the VAO to dynamic. */
556    if (ctx->Const.AllowDynamicVAOFastPath && ++vao->NumUpdates > 4) {
557       vao->IsDynamic = true;
558       /* IsDynamic changes how vertex elements map to vertex buffers. */
559       vao->NewVertexElements = true;
560       return;
561    }
562 
563    /* Walk those enabled arrays that have a real vbo attached */
564    GLbitfield mask = enabled;
565    while (mask) {
566       /* Do not use u_bit_scan as we can walk multiple attrib arrays at once */
567       const int i = ffs(mask) - 1;
568       /* The binding from the first to be processed attribute. */
569       const GLuint bindex = vao->VertexAttrib[i].BufferBindingIndex;
570       struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[bindex];
571 
572       /* The scan goes different for user space arrays than vbos */
573       if (binding->BufferObj) {
574          /* The bound arrays. */
575          const GLbitfield bound = enabled & binding->_BoundArrays;
576 
577          /* Start this current effective binding with the actual bound arrays */
578          GLbitfield eff_bound_arrays = bound;
579 
580          /*
581           * If there is nothing left to scan just update the effective binding
582           * information. If the VAO is already only using a single binding point
583           * we end up here. So the overhead of this scan for an application
584           * carefully preparing the VAO for draw is low.
585           */
586 
587          GLbitfield scanmask = mask & vbos & ~bound;
588          /* Is there something left to scan? */
589          if (scanmask == 0) {
590             /* Just update the back reference from the attrib to the binding and
591              * the effective offset.
592              */
593             GLbitfield attrmask = eff_bound_arrays;
594             while (attrmask) {
595                const int j = u_bit_scan(&attrmask);
596                struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j];
597 
598                /* Update the index into the common binding point and offset */
599                attrib2->_EffBufferBindingIndex = bindex;
600                attrib2->_EffRelativeOffset = attrib2->RelativeOffset;
601                assert(attrib2->_EffRelativeOffset <= MaxRelativeOffset);
602             }
603             /* Finally this is the set of effectively bound arrays with the
604              * original binding offset.
605              */
606             binding->_EffOffset = binding->Offset;
607             /* The bound arrays past the VERT_ATTRIB_{POS,GENERIC0} mapping. */
608             binding->_EffBoundArrays =
609                _mesa_vao_enable_to_vp_inputs(mode, eff_bound_arrays);
610 
611          } else {
612             /* In the VBO case, scan for attribute/binding
613              * combinations with relative bindings in the range of
614              * [0, ctx->Const.MaxVertexAttribRelativeOffset].
615              * Note that this does also go beyond just interleaved arrays
616              * as long as they use the same VBO, binding parameters and the
617              * offsets stay within bounds that the backend still can handle.
618              */
619 
620             GLsizeiptr min_offset, max_offset;
621             compute_vbo_offset_range(vao, binding, &min_offset, &max_offset);
622             assert(max_offset <= min_offset + MaxRelativeOffset);
623 
624             /* Now scan. */
625             while (scanmask) {
626                /* Do not use u_bit_scan as we can walk multiple
627                 * attrib arrays at once
628                 */
629                const int j = ffs(scanmask) - 1;
630                const struct gl_array_attributes *attrib2 =
631                   &vao->VertexAttrib[j];
632                const struct gl_vertex_buffer_binding *binding2 =
633                   &vao->BufferBinding[attrib2->BufferBindingIndex];
634 
635                /* Remove those attrib bits from the mask that are bound to the
636                 * same effective binding point.
637                 */
638                const GLbitfield bound2 = enabled & binding2->_BoundArrays;
639                scanmask &= ~bound2;
640 
641                /* Check if we have an identical binding */
642                if (binding->Stride != binding2->Stride)
643                   continue;
644                if (binding->InstanceDivisor != binding2->InstanceDivisor)
645                   continue;
646                if (binding->BufferObj != binding2->BufferObj)
647                   continue;
648                /* Check if we can fold both bindings into a common binding */
649                GLsizeiptr min_offset2, max_offset2;
650                compute_vbo_offset_range(vao, binding2,
651                                         &min_offset2, &max_offset2);
652                /* If the relative offset is within the limits ... */
653                if (min_offset + MaxRelativeOffset < max_offset2)
654                   continue;
655                if (min_offset2 + MaxRelativeOffset < max_offset)
656                   continue;
657                /* ... add this array to the effective binding */
658                eff_bound_arrays |= bound2;
659                min_offset = MIN2(min_offset, min_offset2);
660                max_offset = MAX2(max_offset, max_offset2);
661                assert(max_offset <= min_offset + MaxRelativeOffset);
662             }
663 
664             /* Update the back reference from the attrib to the binding */
665             GLbitfield attrmask = eff_bound_arrays;
666             while (attrmask) {
667                const int j = u_bit_scan(&attrmask);
668                struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j];
669                const struct gl_vertex_buffer_binding *binding2 =
670                   &vao->BufferBinding[attrib2->BufferBindingIndex];
671 
672                /* Update the index into the common binding point and offset */
673                attrib2->_EffBufferBindingIndex = bindex;
674                attrib2->_EffRelativeOffset =
675                   binding2->Offset + attrib2->RelativeOffset - min_offset;
676                assert(attrib2->_EffRelativeOffset <= MaxRelativeOffset);
677             }
678             /* Finally this is the set of effectively bound arrays */
679             binding->_EffOffset = min_offset;
680             /* The bound arrays past the VERT_ATTRIB_{POS,GENERIC0} mapping. */
681             binding->_EffBoundArrays =
682                _mesa_vao_enable_to_vp_inputs(mode, eff_bound_arrays);
683          }
684 
685          /* Mark all the effective bound arrays as processed. */
686          mask &= ~eff_bound_arrays;
687 
688       } else {
689          /* Scanning of common bindings for user space arrays.
690           */
691 
692          const struct gl_array_attributes *attrib = &vao->VertexAttrib[i];
693          const GLbitfield bound = VERT_BIT(i);
694 
695          /* Note that user space array pointers can only happen using a one
696           * to one binding point to array mapping.
697           * The OpenGL 4.x/ARB_vertex_attrib_binding api does not support
698           * user space arrays collected at multiple binding points.
699           * The only provider of user space interleaved arrays with a single
700           * binding point is the mesa internal vbo module. But that one
701           * provides a perfect interleaved set of arrays.
702           *
703           * If this would not be true we would potentially get attribute arrays
704           * with user space pointers that may not lie within the
705           * MaxRelativeOffset range but still attached to a single binding.
706           * Then we would need to store the effective attribute and binding
707           * grouping information in a seperate array beside
708           * gl_array_attributes/gl_vertex_buffer_binding.
709           */
710          assert(util_bitcount(binding->_BoundArrays & vao->Enabled) == 1
711                 || (vao->Enabled & ~binding->_BoundArrays) == 0);
712 
713          /* Start this current effective binding with the array */
714          GLbitfield eff_bound_arrays = bound;
715 
716          const GLubyte *ptr = attrib->Ptr;
717          unsigned vertex_end = attrib->Format._ElementSize;
718 
719          /* Walk other user space arrays and see which are interleaved
720           * using the same binding parameters.
721           */
722          GLbitfield scanmask = mask & ~vbos & ~bound;
723          while (scanmask) {
724             const int j = u_bit_scan(&scanmask);
725             const struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j];
726             const struct gl_vertex_buffer_binding *binding2 =
727                &vao->BufferBinding[attrib2->BufferBindingIndex];
728 
729             /* See the comment at the same assert above. */
730             assert(util_bitcount(binding2->_BoundArrays & vao->Enabled) == 1
731                    || (vao->Enabled & ~binding->_BoundArrays) == 0);
732 
733             /* Check if we have an identical binding */
734             if (binding->Stride != binding2->Stride)
735                continue;
736             if (binding->InstanceDivisor != binding2->InstanceDivisor)
737                continue;
738             if (ptr <= attrib2->Ptr) {
739                if (ptr + binding->Stride < attrib2->Ptr +
740                    attrib2->Format._ElementSize)
741                   continue;
742                unsigned end = attrib2->Ptr + attrib2->Format._ElementSize - ptr;
743                vertex_end = MAX2(vertex_end, end);
744             } else {
745                if (attrib2->Ptr + binding->Stride < ptr + vertex_end)
746                   continue;
747                vertex_end += (GLsizei)(ptr - attrib2->Ptr);
748                ptr = attrib2->Ptr;
749             }
750 
751             /* User space buffer object */
752             assert(!binding2->BufferObj);
753 
754             eff_bound_arrays |= VERT_BIT(j);
755          }
756 
757          /* Update the back reference from the attrib to the binding */
758          GLbitfield attrmask = eff_bound_arrays;
759          while (attrmask) {
760             const int j = u_bit_scan(&attrmask);
761             struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j];
762 
763             /* Update the index into the common binding point and the offset */
764             attrib2->_EffBufferBindingIndex = bindex;
765             attrib2->_EffRelativeOffset = attrib2->Ptr - ptr;
766             assert(attrib2->_EffRelativeOffset <= binding->Stride);
767          }
768          /* Finally this is the set of effectively bound arrays */
769          binding->_EffOffset = (GLintptr)ptr;
770          /* The bound arrays past the VERT_ATTRIB_{POS,GENERIC0} mapping. */
771          binding->_EffBoundArrays =
772             _mesa_vao_enable_to_vp_inputs(mode, eff_bound_arrays);
773 
774          /* Mark all the effective bound arrays as processed. */
775          mask &= ~eff_bound_arrays;
776       }
777    }
778 
779 #ifndef NDEBUG
780    /* Make sure the above code works as expected. */
781    for (gl_vert_attrib attr = 0; attr < VERT_ATTRIB_MAX; ++attr) {
782       /* Query the original api defined attrib/binding information ... */
783       const unsigned char *const map =_mesa_vao_attribute_map[mode];
784       if (vao->Enabled & VERT_BIT(map[attr])) {
785          const struct gl_array_attributes *attrib =
786             &vao->VertexAttrib[map[attr]];
787          const struct gl_vertex_buffer_binding *binding =
788             &vao->BufferBinding[attrib->BufferBindingIndex];
789          /* ... and compare that with the computed attrib/binding */
790          const struct gl_vertex_buffer_binding *binding2 =
791             &vao->BufferBinding[attrib->_EffBufferBindingIndex];
792          assert(binding->Stride == binding2->Stride);
793          assert(binding->InstanceDivisor == binding2->InstanceDivisor);
794          assert(binding->BufferObj == binding2->BufferObj);
795          if (binding->BufferObj) {
796             assert(attrib->_EffRelativeOffset <= MaxRelativeOffset);
797             assert(binding->Offset + attrib->RelativeOffset ==
798                    binding2->_EffOffset + attrib->_EffRelativeOffset);
799          } else {
800             assert(attrib->_EffRelativeOffset < binding->Stride);
801             assert((GLintptr)attrib->Ptr ==
802                    binding2->_EffOffset + attrib->_EffRelativeOffset);
803          }
804       }
805    }
806 #endif
807 }
808 
809 
810 void
_mesa_set_vao_immutable(struct gl_context * ctx,struct gl_vertex_array_object * vao)811 _mesa_set_vao_immutable(struct gl_context *ctx,
812                         struct gl_vertex_array_object *vao)
813 {
814    _mesa_update_vao_derived_arrays(ctx, vao);
815    vao->NewVertexBuffers = false;
816    vao->NewVertexElements = false;
817    vao->SharedAndImmutable = true;
818 }
819 
820 
821 /**
822  * Map buffer objects used in attribute arrays.
823  */
824 void
_mesa_vao_map_arrays(struct gl_context * ctx,struct gl_vertex_array_object * vao,GLbitfield access)825 _mesa_vao_map_arrays(struct gl_context *ctx, struct gl_vertex_array_object *vao,
826                      GLbitfield access)
827 {
828    GLbitfield mask = vao->Enabled & vao->VertexAttribBufferMask;
829    while (mask) {
830       /* Do not use u_bit_scan as we can walk multiple attrib arrays at once */
831       const gl_vert_attrib attr = ffs(mask) - 1;
832       const GLubyte bindex = vao->VertexAttrib[attr].BufferBindingIndex;
833       struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[bindex];
834       mask &= ~binding->_BoundArrays;
835 
836       struct gl_buffer_object *bo = binding->BufferObj;
837       assert(bo);
838       if (_mesa_bufferobj_mapped(bo, MAP_INTERNAL))
839          continue;
840 
841       _mesa_bufferobj_map_range(ctx, 0, bo->Size, access, bo, MAP_INTERNAL);
842    }
843 }
844 
845 
846 /**
847  * Map buffer objects used in the vao, attribute arrays and index buffer.
848  */
849 void
_mesa_vao_map(struct gl_context * ctx,struct gl_vertex_array_object * vao,GLbitfield access)850 _mesa_vao_map(struct gl_context *ctx, struct gl_vertex_array_object *vao,
851               GLbitfield access)
852 {
853    struct gl_buffer_object *bo = vao->IndexBufferObj;
854 
855    /* map the index buffer, if there is one, and not already mapped */
856    if (bo && !_mesa_bufferobj_mapped(bo, MAP_INTERNAL))
857       _mesa_bufferobj_map_range(ctx, 0, bo->Size, access, bo, MAP_INTERNAL);
858 
859    _mesa_vao_map_arrays(ctx, vao, access);
860 }
861 
862 
863 /**
864  * Unmap buffer objects used in attribute arrays.
865  */
866 void
_mesa_vao_unmap_arrays(struct gl_context * ctx,struct gl_vertex_array_object * vao)867 _mesa_vao_unmap_arrays(struct gl_context *ctx,
868                        struct gl_vertex_array_object *vao)
869 {
870    GLbitfield mask = vao->Enabled & vao->VertexAttribBufferMask;
871    while (mask) {
872       /* Do not use u_bit_scan as we can walk multiple attrib arrays at once */
873       const gl_vert_attrib attr = ffs(mask) - 1;
874       const GLubyte bindex = vao->VertexAttrib[attr].BufferBindingIndex;
875       struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[bindex];
876       mask &= ~binding->_BoundArrays;
877 
878       struct gl_buffer_object *bo = binding->BufferObj;
879       assert(bo);
880       if (!_mesa_bufferobj_mapped(bo, MAP_INTERNAL))
881          continue;
882 
883       _mesa_bufferobj_unmap(ctx, bo, MAP_INTERNAL);
884    }
885 }
886 
887 
888 /**
889  * Unmap buffer objects used in the vao, attribute arrays and index buffer.
890  */
891 void
_mesa_vao_unmap(struct gl_context * ctx,struct gl_vertex_array_object * vao)892 _mesa_vao_unmap(struct gl_context *ctx, struct gl_vertex_array_object *vao)
893 {
894    struct gl_buffer_object *bo = vao->IndexBufferObj;
895 
896    /* unmap the index buffer, if there is one, and still mapped */
897    if (bo && _mesa_bufferobj_mapped(bo, MAP_INTERNAL))
898       _mesa_bufferobj_unmap(ctx, bo, MAP_INTERNAL);
899 
900    _mesa_vao_unmap_arrays(ctx, vao);
901 }
902 
903 
904 /**********************************************************************/
905 /* API Functions                                                      */
906 /**********************************************************************/
907 
908 
909 /**
910  * ARB version of glBindVertexArray()
911  */
912 static ALWAYS_INLINE void
bind_vertex_array(struct gl_context * ctx,GLuint id,bool no_error)913 bind_vertex_array(struct gl_context *ctx, GLuint id, bool no_error)
914 {
915    struct gl_vertex_array_object *const oldObj = ctx->Array.VAO;
916    struct gl_vertex_array_object *newObj = NULL;
917 
918    assert(oldObj != NULL);
919 
920    if (oldObj->Name == id)
921       return;   /* rebinding the same array object- no change */
922 
923    /*
924     * Get pointer to new array object (newObj)
925     */
926    if (id == 0) {
927       /* The spec says there is no array object named 0, but we use
928        * one internally because it simplifies things.
929        */
930       newObj = ctx->Array.DefaultVAO;
931    }
932    else {
933       /* non-default array object */
934       newObj = _mesa_lookup_vao(ctx, id);
935       if (!no_error && !newObj) {
936          _mesa_error(ctx, GL_INVALID_OPERATION,
937                      "glBindVertexArray(non-gen name)");
938          return;
939       }
940 
941       newObj->EverBound = GL_TRUE;
942    }
943 
944    /* The _DrawArrays pointer is pointing at the VAO being unbound and
945     * that VAO may be in the process of being deleted. If it's not going
946     * to be deleted, this will have no effect, because the pointer needs
947     * to be updated by the VBO module anyway.
948     *
949     * Before the VBO module can update the pointer, we have to set it
950     * to NULL for drivers not to set up arrays which are not bound,
951     * or to prevent a crash if the VAO being unbound is going to be
952     * deleted.
953     */
954    _mesa_set_draw_vao(ctx, ctx->Array._EmptyVAO, 0);
955 
956    _mesa_reference_vao(ctx, &ctx->Array.VAO, newObj);
957 
958    /* Update the valid-to-render state if binding on unbinding default VAO
959     * if drawing with the default VAO is invalid.
960     */
961    if (ctx->API == API_OPENGL_CORE &&
962        (oldObj == ctx->Array.DefaultVAO) != (newObj == ctx->Array.DefaultVAO))
963       _mesa_update_valid_to_render_state(ctx);
964 }
965 
966 
967 void GLAPIENTRY
_mesa_BindVertexArray_no_error(GLuint id)968 _mesa_BindVertexArray_no_error(GLuint id)
969 {
970    GET_CURRENT_CONTEXT(ctx);
971    bind_vertex_array(ctx, id, true);
972 }
973 
974 
975 void GLAPIENTRY
_mesa_BindVertexArray(GLuint id)976 _mesa_BindVertexArray(GLuint id)
977 {
978    GET_CURRENT_CONTEXT(ctx);
979    bind_vertex_array(ctx, id, false);
980 }
981 
982 
983 /**
984  * Delete a set of array objects.
985  *
986  * \param n      Number of array objects to delete.
987  * \param ids    Array of \c n array object IDs.
988  */
989 static void
delete_vertex_arrays(struct gl_context * ctx,GLsizei n,const GLuint * ids)990 delete_vertex_arrays(struct gl_context *ctx, GLsizei n, const GLuint *ids)
991 {
992    GLsizei i;
993 
994    for (i = 0; i < n; i++) {
995       /* IDs equal to 0 should be silently ignored. */
996       if (!ids[i])
997          continue;
998 
999       struct gl_vertex_array_object *obj = _mesa_lookup_vao(ctx, ids[i]);
1000 
1001       if (obj) {
1002          assert(obj->Name == ids[i]);
1003 
1004          /* If the array object is currently bound, the spec says "the binding
1005           * for that object reverts to zero and the default vertex array
1006           * becomes current."
1007           */
1008          if (obj == ctx->Array.VAO)
1009             _mesa_BindVertexArray_no_error(0);
1010 
1011          /* The ID is immediately freed for re-use */
1012          _mesa_HashRemoveLocked(ctx->Array.Objects, obj->Name);
1013 
1014          if (ctx->Array.LastLookedUpVAO == obj)
1015             _mesa_reference_vao(ctx, &ctx->Array.LastLookedUpVAO, NULL);
1016          if (ctx->Array._DrawVAO == obj)
1017             _mesa_set_draw_vao(ctx, ctx->Array._EmptyVAO, 0);
1018 
1019          /* Unreference the array object.
1020           * If refcount hits zero, the object will be deleted.
1021           */
1022          _mesa_reference_vao(ctx, &obj, NULL);
1023       }
1024    }
1025 }
1026 
1027 
1028 void GLAPIENTRY
_mesa_DeleteVertexArrays_no_error(GLsizei n,const GLuint * ids)1029 _mesa_DeleteVertexArrays_no_error(GLsizei n, const GLuint *ids)
1030 {
1031    GET_CURRENT_CONTEXT(ctx);
1032    delete_vertex_arrays(ctx, n, ids);
1033 }
1034 
1035 
1036 void GLAPIENTRY
_mesa_DeleteVertexArrays(GLsizei n,const GLuint * ids)1037 _mesa_DeleteVertexArrays(GLsizei n, const GLuint *ids)
1038 {
1039    GET_CURRENT_CONTEXT(ctx);
1040 
1041    if (n < 0) {
1042       _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteVertexArray(n)");
1043       return;
1044    }
1045 
1046    delete_vertex_arrays(ctx, n, ids);
1047 }
1048 
1049 
1050 /**
1051  * Generate a set of unique array object IDs and store them in \c arrays.
1052  * Helper for _mesa_GenVertexArrays() and _mesa_CreateVertexArrays()
1053  * below.
1054  *
1055  * \param n       Number of IDs to generate.
1056  * \param arrays  Array of \c n locations to store the IDs.
1057  * \param create  Indicates that the objects should also be created.
1058  * \param func    The name of the GL entry point.
1059  */
1060 static void
gen_vertex_arrays(struct gl_context * ctx,GLsizei n,GLuint * arrays,bool create,const char * func)1061 gen_vertex_arrays(struct gl_context *ctx, GLsizei n, GLuint *arrays,
1062                   bool create, const char *func)
1063 {
1064    GLint i;
1065 
1066    if (!arrays)
1067       return;
1068 
1069    _mesa_HashFindFreeKeys(ctx->Array.Objects, arrays, n);
1070 
1071    /* For the sake of simplicity we create the array objects in both
1072     * the Gen* and Create* cases.  The only difference is the value of
1073     * EverBound, which is set to true in the Create* case.
1074     */
1075    for (i = 0; i < n; i++) {
1076       struct gl_vertex_array_object *obj;
1077 
1078       obj = _mesa_new_vao(ctx, arrays[i]);
1079       if (!obj) {
1080          _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
1081          return;
1082       }
1083       obj->EverBound = create;
1084       _mesa_HashInsertLocked(ctx->Array.Objects, obj->Name, obj, true);
1085    }
1086 }
1087 
1088 
1089 static void
gen_vertex_arrays_err(struct gl_context * ctx,GLsizei n,GLuint * arrays,bool create,const char * func)1090 gen_vertex_arrays_err(struct gl_context *ctx, GLsizei n, GLuint *arrays,
1091                       bool create, const char *func)
1092 {
1093    if (n < 0) {
1094       _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
1095       return;
1096    }
1097 
1098    gen_vertex_arrays(ctx, n, arrays, create, func);
1099 }
1100 
1101 
1102 /**
1103  * ARB version of glGenVertexArrays()
1104  * All arrays will be required to live in VBOs.
1105  */
1106 void GLAPIENTRY
_mesa_GenVertexArrays_no_error(GLsizei n,GLuint * arrays)1107 _mesa_GenVertexArrays_no_error(GLsizei n, GLuint *arrays)
1108 {
1109    GET_CURRENT_CONTEXT(ctx);
1110    gen_vertex_arrays(ctx, n, arrays, false, "glGenVertexArrays");
1111 }
1112 
1113 
1114 void GLAPIENTRY
_mesa_GenVertexArrays(GLsizei n,GLuint * arrays)1115 _mesa_GenVertexArrays(GLsizei n, GLuint *arrays)
1116 {
1117    GET_CURRENT_CONTEXT(ctx);
1118    gen_vertex_arrays_err(ctx, n, arrays, false, "glGenVertexArrays");
1119 }
1120 
1121 
1122 /**
1123  * ARB_direct_state_access
1124  * Generates ID's and creates the array objects.
1125  */
1126 void GLAPIENTRY
_mesa_CreateVertexArrays_no_error(GLsizei n,GLuint * arrays)1127 _mesa_CreateVertexArrays_no_error(GLsizei n, GLuint *arrays)
1128 {
1129    GET_CURRENT_CONTEXT(ctx);
1130    gen_vertex_arrays(ctx, n, arrays, true, "glCreateVertexArrays");
1131 }
1132 
1133 
1134 void GLAPIENTRY
_mesa_CreateVertexArrays(GLsizei n,GLuint * arrays)1135 _mesa_CreateVertexArrays(GLsizei n, GLuint *arrays)
1136 {
1137    GET_CURRENT_CONTEXT(ctx);
1138    gen_vertex_arrays_err(ctx, n, arrays, true, "glCreateVertexArrays");
1139 }
1140 
1141 
1142 /**
1143  * Determine if ID is the name of an array object.
1144  *
1145  * \param id  ID of the potential array object.
1146  * \return  \c GL_TRUE if \c id is the name of a array object,
1147  *          \c GL_FALSE otherwise.
1148  */
1149 GLboolean GLAPIENTRY
_mesa_IsVertexArray(GLuint id)1150 _mesa_IsVertexArray( GLuint id )
1151 {
1152    struct gl_vertex_array_object * obj;
1153    GET_CURRENT_CONTEXT(ctx);
1154    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1155 
1156    obj = _mesa_lookup_vao(ctx, id);
1157 
1158    return obj != NULL && obj->EverBound;
1159 }
1160 
1161 
1162 /**
1163  * Sets the element array buffer binding of a vertex array object.
1164  *
1165  * This is the ARB_direct_state_access equivalent of
1166  * glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer).
1167  */
1168 static ALWAYS_INLINE void
vertex_array_element_buffer(struct gl_context * ctx,GLuint vaobj,GLuint buffer,bool no_error)1169 vertex_array_element_buffer(struct gl_context *ctx, GLuint vaobj, GLuint buffer,
1170                             bool no_error)
1171 {
1172    struct gl_vertex_array_object *vao;
1173    struct gl_buffer_object *bufObj;
1174 
1175    ASSERT_OUTSIDE_BEGIN_END(ctx);
1176 
1177    if (!no_error) {
1178       /* The GL_ARB_direct_state_access specification says:
1179        *
1180        *    "An INVALID_OPERATION error is generated by
1181        *     VertexArrayElementBuffer if <vaobj> is not [compatibility profile:
1182        *     zero or] the name of an existing vertex array object."
1183        */
1184       vao =_mesa_lookup_vao_err(ctx, vaobj, false, "glVertexArrayElementBuffer");
1185       if (!vao)
1186          return;
1187    } else {
1188       vao = _mesa_lookup_vao(ctx, vaobj);
1189    }
1190 
1191    if (buffer != 0) {
1192       if (!no_error) {
1193          /* The GL_ARB_direct_state_access specification says:
1194           *
1195           *    "An INVALID_OPERATION error is generated if <buffer> is not zero
1196           *     or the name of an existing buffer object."
1197           */
1198          bufObj = _mesa_lookup_bufferobj_err(ctx, buffer,
1199                                              "glVertexArrayElementBuffer");
1200       } else {
1201          bufObj = _mesa_lookup_bufferobj(ctx, buffer);
1202       }
1203 
1204       if (!bufObj)
1205          return;
1206    } else {
1207       bufObj = NULL;
1208    }
1209 
1210    _mesa_reference_buffer_object(ctx, &vao->IndexBufferObj, bufObj);
1211 }
1212 
1213 
1214 void GLAPIENTRY
_mesa_VertexArrayElementBuffer_no_error(GLuint vaobj,GLuint buffer)1215 _mesa_VertexArrayElementBuffer_no_error(GLuint vaobj, GLuint buffer)
1216 {
1217    GET_CURRENT_CONTEXT(ctx);
1218    vertex_array_element_buffer(ctx, vaobj, buffer, true);
1219 }
1220 
1221 
1222 void GLAPIENTRY
_mesa_VertexArrayElementBuffer(GLuint vaobj,GLuint buffer)1223 _mesa_VertexArrayElementBuffer(GLuint vaobj, GLuint buffer)
1224 {
1225    GET_CURRENT_CONTEXT(ctx);
1226    vertex_array_element_buffer(ctx, vaobj, buffer, false);
1227 }
1228 
1229 
1230 void GLAPIENTRY
_mesa_GetVertexArrayiv(GLuint vaobj,GLenum pname,GLint * param)1231 _mesa_GetVertexArrayiv(GLuint vaobj, GLenum pname, GLint *param)
1232 {
1233    GET_CURRENT_CONTEXT(ctx);
1234    struct gl_vertex_array_object *vao;
1235 
1236    ASSERT_OUTSIDE_BEGIN_END(ctx);
1237 
1238    /* The GL_ARB_direct_state_access specification says:
1239     *
1240     *   "An INVALID_OPERATION error is generated if <vaobj> is not
1241     *    [compatibility profile: zero or] the name of an existing
1242     *    vertex array object."
1243     */
1244    vao = _mesa_lookup_vao_err(ctx, vaobj, false, "glGetVertexArrayiv");
1245    if (!vao)
1246       return;
1247 
1248    /* The GL_ARB_direct_state_access specification says:
1249     *
1250     *   "An INVALID_ENUM error is generated if <pname> is not
1251     *    ELEMENT_ARRAY_BUFFER_BINDING."
1252     */
1253    if (pname != GL_ELEMENT_ARRAY_BUFFER_BINDING) {
1254       _mesa_error(ctx, GL_INVALID_ENUM,
1255                   "glGetVertexArrayiv(pname != "
1256                   "GL_ELEMENT_ARRAY_BUFFER_BINDING)");
1257       return;
1258    }
1259 
1260    param[0] = vao->IndexBufferObj ? vao->IndexBufferObj->Name : 0;
1261 }
1262