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