xref: /aosp_15_r20/external/mesa3d/src/mesa/main/arrayobj.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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 <[email protected]>
39  * \author Brian Paul
40  */
41 
42 
43 #include "util/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 (_mesa_is_desktop_gl_compat(ctx))
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 || _mesa_is_desktop_gl_core(ctx)) {
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,bool display_list)517 _mesa_update_vao_derived_arrays(struct gl_context *ctx,
518                                 struct gl_vertex_array_object *vao,
519                                 bool display_list)
520 {
521    assert(display_list || !ctx->Const.UseVAOFastPath);
522    /* Make sure we do not run into problems with shared objects */
523    assert(!vao->SharedAndImmutable);
524 
525    /* Limit used for common binding scanning below. */
526    const GLsizeiptr MaxRelativeOffset =
527       ctx->Const.MaxVertexAttribRelativeOffset;
528 
529    /* The gl_vertex_array_object::_AttributeMapMode denotes the way
530     * VERT_ATTRIB_{POS,GENERIC0} mapping is done.
531     *
532     * This mapping is used to map between the OpenGL api visible
533     * VERT_ATTRIB_* arrays to mesa driver arrayinputs or shader inputs.
534     * The mapping only depends on the enabled bits of the
535     * VERT_ATTRIB_{POS,GENERIC0} arrays and is tracked in the VAO.
536     *
537     * This map needs to be applied when finally translating to the bitmasks
538     * as consumed by the driver backends. The duplicate scanning is here
539     * can as well be done in the OpenGL API numbering without this map.
540     */
541    const gl_attribute_map_mode mode = vao->_AttributeMapMode;
542    /* Enabled array bits. */
543    const GLbitfield enabled = vao->Enabled;
544    /* VBO array bits. */
545    const GLbitfield vbos = vao->VertexAttribBufferMask;
546 
547    /* Walk those enabled arrays that have a real vbo attached */
548    GLbitfield mask = enabled;
549    while (mask) {
550       /* Do not use u_bit_scan as we can walk multiple attrib arrays at once */
551       const int i = ffs(mask) - 1;
552       /* The binding from the first to be processed attribute. */
553       const GLuint bindex = vao->VertexAttrib[i].BufferBindingIndex;
554       struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[bindex];
555 
556       /* The scan goes different for user space arrays than vbos */
557       if (binding->BufferObj) {
558          /* The bound arrays. */
559          const GLbitfield bound = enabled & binding->_BoundArrays;
560 
561          /* Start this current effective binding with the actual bound arrays */
562          GLbitfield eff_bound_arrays = bound;
563 
564          /*
565           * If there is nothing left to scan just update the effective binding
566           * information. If the VAO is already only using a single binding point
567           * we end up here. So the overhead of this scan for an application
568           * carefully preparing the VAO for draw is low.
569           */
570 
571          GLbitfield scanmask = mask & vbos & ~bound;
572          /* Is there something left to scan? */
573          if (scanmask == 0) {
574             /* Just update the back reference from the attrib to the binding and
575              * the effective offset.
576              */
577             GLbitfield attrmask = eff_bound_arrays;
578             while (attrmask) {
579                const int j = u_bit_scan(&attrmask);
580                struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j];
581 
582                /* Update the index into the common binding point and offset */
583                attrib2->_EffBufferBindingIndex = bindex;
584                attrib2->_EffRelativeOffset = attrib2->RelativeOffset;
585                assert(attrib2->_EffRelativeOffset <= MaxRelativeOffset);
586             }
587             /* Finally this is the set of effectively bound arrays with the
588              * original binding offset.
589              */
590             binding->_EffOffset = binding->Offset;
591             /* The bound arrays past the VERT_ATTRIB_{POS,GENERIC0} mapping. */
592             binding->_EffBoundArrays =
593                _mesa_vao_enable_to_vp_inputs(mode, eff_bound_arrays);
594 
595          } else {
596             /* In the VBO case, scan for attribute/binding
597              * combinations with relative bindings in the range of
598              * [0, ctx->Const.MaxVertexAttribRelativeOffset].
599              * Note that this does also go beyond just interleaved arrays
600              * as long as they use the same VBO, binding parameters and the
601              * offsets stay within bounds that the backend still can handle.
602              */
603 
604             GLsizeiptr min_offset, max_offset;
605             compute_vbo_offset_range(vao, binding, &min_offset, &max_offset);
606             assert(max_offset <= min_offset + MaxRelativeOffset);
607 
608             /* Now scan. */
609             while (scanmask) {
610                /* Do not use u_bit_scan as we can walk multiple
611                 * attrib arrays at once
612                 */
613                const int j = ffs(scanmask) - 1;
614                const struct gl_array_attributes *attrib2 =
615                   &vao->VertexAttrib[j];
616                const struct gl_vertex_buffer_binding *binding2 =
617                   &vao->BufferBinding[attrib2->BufferBindingIndex];
618 
619                /* Remove those attrib bits from the mask that are bound to the
620                 * same effective binding point.
621                 */
622                const GLbitfield bound2 = enabled & binding2->_BoundArrays;
623                scanmask &= ~bound2;
624 
625                /* Check if we have an identical binding */
626                if (binding->Stride != binding2->Stride)
627                   continue;
628                if (binding->InstanceDivisor != binding2->InstanceDivisor)
629                   continue;
630                if (binding->BufferObj != binding2->BufferObj)
631                   continue;
632                /* Check if we can fold both bindings into a common binding */
633                GLsizeiptr min_offset2, max_offset2;
634                compute_vbo_offset_range(vao, binding2,
635                                         &min_offset2, &max_offset2);
636                /* If the relative offset is within the limits ... */
637                if (min_offset + MaxRelativeOffset < max_offset2)
638                   continue;
639                if (min_offset2 + MaxRelativeOffset < max_offset)
640                   continue;
641                /* ... add this array to the effective binding */
642                eff_bound_arrays |= bound2;
643                min_offset = MIN2(min_offset, min_offset2);
644                max_offset = MAX2(max_offset, max_offset2);
645                assert(max_offset <= min_offset + MaxRelativeOffset);
646             }
647 
648             /* Update the back reference from the attrib to the binding */
649             GLbitfield attrmask = eff_bound_arrays;
650             while (attrmask) {
651                const int j = u_bit_scan(&attrmask);
652                struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j];
653                const struct gl_vertex_buffer_binding *binding2 =
654                   &vao->BufferBinding[attrib2->BufferBindingIndex];
655 
656                /* Update the index into the common binding point and offset */
657                attrib2->_EffBufferBindingIndex = bindex;
658                attrib2->_EffRelativeOffset =
659                   binding2->Offset + attrib2->RelativeOffset - min_offset;
660                assert(attrib2->_EffRelativeOffset <= MaxRelativeOffset);
661             }
662             /* Finally this is the set of effectively bound arrays */
663             binding->_EffOffset = min_offset;
664             /* The bound arrays past the VERT_ATTRIB_{POS,GENERIC0} mapping. */
665             binding->_EffBoundArrays =
666                _mesa_vao_enable_to_vp_inputs(mode, eff_bound_arrays);
667          }
668 
669          /* Mark all the effective bound arrays as processed. */
670          mask &= ~eff_bound_arrays;
671 
672       } else {
673          /* Scanning of common bindings for user space arrays.
674           */
675 
676          const struct gl_array_attributes *attrib = &vao->VertexAttrib[i];
677          const GLbitfield bound = VERT_BIT(i);
678 
679          /* Note that user space array pointers can only happen using a one
680           * to one binding point to array mapping.
681           * The OpenGL 4.x/ARB_vertex_attrib_binding api does not support
682           * user space arrays collected at multiple binding points.
683           * The only provider of user space interleaved arrays with a single
684           * binding point is the mesa internal vbo module. But that one
685           * provides a perfect interleaved set of arrays.
686           *
687           * If this would not be true we would potentially get attribute arrays
688           * with user space pointers that may not lie within the
689           * MaxRelativeOffset range but still attached to a single binding.
690           * Then we would need to store the effective attribute and binding
691           * grouping information in a seperate array beside
692           * gl_array_attributes/gl_vertex_buffer_binding.
693           */
694          assert(util_bitcount(binding->_BoundArrays & vao->Enabled) == 1
695                 || (vao->Enabled & ~binding->_BoundArrays) == 0);
696 
697          /* Start this current effective binding with the array */
698          GLbitfield eff_bound_arrays = bound;
699 
700          const GLubyte *ptr = attrib->Ptr;
701          unsigned vertex_end = attrib->Format._ElementSize;
702 
703          /* Walk other user space arrays and see which are interleaved
704           * using the same binding parameters.
705           */
706          GLbitfield scanmask = mask & ~vbos & ~bound;
707          while (scanmask) {
708             const int j = u_bit_scan(&scanmask);
709             const struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j];
710             const struct gl_vertex_buffer_binding *binding2 =
711                &vao->BufferBinding[attrib2->BufferBindingIndex];
712 
713             /* See the comment at the same assert above. */
714             assert(util_bitcount(binding2->_BoundArrays & vao->Enabled) == 1
715                    || (vao->Enabled & ~binding->_BoundArrays) == 0);
716 
717             /* Check if we have an identical binding */
718             if (binding->Stride != binding2->Stride)
719                continue;
720             if (binding->InstanceDivisor != binding2->InstanceDivisor)
721                continue;
722             if (ptr <= attrib2->Ptr) {
723                if (ptr + binding->Stride < attrib2->Ptr +
724                    attrib2->Format._ElementSize)
725                   continue;
726                unsigned end = attrib2->Ptr + attrib2->Format._ElementSize - ptr;
727                vertex_end = MAX2(vertex_end, end);
728             } else {
729                if (attrib2->Ptr + binding->Stride < ptr + vertex_end)
730                   continue;
731                vertex_end += (GLsizei)(ptr - attrib2->Ptr);
732                ptr = attrib2->Ptr;
733             }
734 
735             /* User space buffer object */
736             assert(!binding2->BufferObj);
737 
738             eff_bound_arrays |= VERT_BIT(j);
739          }
740 
741          /* Update the back reference from the attrib to the binding */
742          GLbitfield attrmask = eff_bound_arrays;
743          while (attrmask) {
744             const int j = u_bit_scan(&attrmask);
745             struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j];
746 
747             /* Update the index into the common binding point and the offset */
748             attrib2->_EffBufferBindingIndex = bindex;
749             attrib2->_EffRelativeOffset = attrib2->Ptr - ptr;
750             assert(attrib2->_EffRelativeOffset <= binding->Stride);
751          }
752          /* Finally this is the set of effectively bound arrays */
753          binding->_EffOffset = (GLintptr)ptr;
754          /* The bound arrays past the VERT_ATTRIB_{POS,GENERIC0} mapping. */
755          binding->_EffBoundArrays =
756             _mesa_vao_enable_to_vp_inputs(mode, eff_bound_arrays);
757 
758          /* Mark all the effective bound arrays as processed. */
759          mask &= ~eff_bound_arrays;
760       }
761    }
762 
763 #ifndef NDEBUG
764    /* Make sure the above code works as expected. */
765    for (gl_vert_attrib attr = 0; attr < VERT_ATTRIB_MAX; ++attr) {
766       /* Query the original api defined attrib/binding information ... */
767       const unsigned char *const map =_mesa_vao_attribute_map[mode];
768       if (vao->Enabled & VERT_BIT(map[attr])) {
769          const struct gl_array_attributes *attrib =
770             &vao->VertexAttrib[map[attr]];
771          const struct gl_vertex_buffer_binding *binding =
772             &vao->BufferBinding[attrib->BufferBindingIndex];
773          /* ... and compare that with the computed attrib/binding */
774          const struct gl_vertex_buffer_binding *binding2 =
775             &vao->BufferBinding[attrib->_EffBufferBindingIndex];
776          assert(binding->Stride == binding2->Stride);
777          assert(binding->InstanceDivisor == binding2->InstanceDivisor);
778          assert(binding->BufferObj == binding2->BufferObj);
779          if (binding->BufferObj) {
780             assert(attrib->_EffRelativeOffset <= MaxRelativeOffset);
781             assert(binding->Offset + attrib->RelativeOffset ==
782                    binding2->_EffOffset + attrib->_EffRelativeOffset);
783          } else {
784             assert(attrib->_EffRelativeOffset < binding->Stride);
785             assert((GLintptr)attrib->Ptr ==
786                    binding2->_EffOffset + attrib->_EffRelativeOffset);
787          }
788       }
789    }
790 #endif
791 }
792 
793 
794 /**
795  * Map buffer objects used in attribute arrays.
796  */
797 void
_mesa_vao_map_arrays(struct gl_context * ctx,struct gl_vertex_array_object * vao,GLbitfield access)798 _mesa_vao_map_arrays(struct gl_context *ctx, struct gl_vertex_array_object *vao,
799                      GLbitfield access)
800 {
801    GLbitfield mask = vao->Enabled & vao->VertexAttribBufferMask;
802    while (mask) {
803       /* Do not use u_bit_scan as we can walk multiple attrib arrays at once */
804       const gl_vert_attrib attr = ffs(mask) - 1;
805       const GLubyte bindex = vao->VertexAttrib[attr].BufferBindingIndex;
806       struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[bindex];
807       mask &= ~binding->_BoundArrays;
808 
809       struct gl_buffer_object *bo = binding->BufferObj;
810       assert(bo);
811       if (_mesa_bufferobj_mapped(bo, MAP_INTERNAL))
812          continue;
813 
814       _mesa_bufferobj_map_range(ctx, 0, bo->Size, access, bo, MAP_INTERNAL);
815    }
816 }
817 
818 
819 /**
820  * Map buffer objects used in the vao, attribute arrays and index buffer.
821  */
822 void
_mesa_vao_map(struct gl_context * ctx,struct gl_vertex_array_object * vao,GLbitfield access)823 _mesa_vao_map(struct gl_context *ctx, struct gl_vertex_array_object *vao,
824               GLbitfield access)
825 {
826    struct gl_buffer_object *bo = vao->IndexBufferObj;
827 
828    /* map the index buffer, if there is one, and not already mapped */
829    if (bo && !_mesa_bufferobj_mapped(bo, MAP_INTERNAL))
830       _mesa_bufferobj_map_range(ctx, 0, bo->Size, access, bo, MAP_INTERNAL);
831 
832    _mesa_vao_map_arrays(ctx, vao, access);
833 }
834 
835 
836 /**
837  * Unmap buffer objects used in attribute arrays.
838  */
839 void
_mesa_vao_unmap_arrays(struct gl_context * ctx,struct gl_vertex_array_object * vao)840 _mesa_vao_unmap_arrays(struct gl_context *ctx,
841                        struct gl_vertex_array_object *vao)
842 {
843    GLbitfield mask = vao->Enabled & vao->VertexAttribBufferMask;
844    while (mask) {
845       /* Do not use u_bit_scan as we can walk multiple attrib arrays at once */
846       const gl_vert_attrib attr = ffs(mask) - 1;
847       const GLubyte bindex = vao->VertexAttrib[attr].BufferBindingIndex;
848       struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[bindex];
849       mask &= ~binding->_BoundArrays;
850 
851       struct gl_buffer_object *bo = binding->BufferObj;
852       assert(bo);
853       if (!_mesa_bufferobj_mapped(bo, MAP_INTERNAL))
854          continue;
855 
856       _mesa_bufferobj_unmap(ctx, bo, MAP_INTERNAL);
857    }
858 }
859 
860 
861 /**
862  * Unmap buffer objects used in the vao, attribute arrays and index buffer.
863  */
864 void
_mesa_vao_unmap(struct gl_context * ctx,struct gl_vertex_array_object * vao)865 _mesa_vao_unmap(struct gl_context *ctx, struct gl_vertex_array_object *vao)
866 {
867    struct gl_buffer_object *bo = vao->IndexBufferObj;
868 
869    /* unmap the index buffer, if there is one, and still mapped */
870    if (bo && _mesa_bufferobj_mapped(bo, MAP_INTERNAL))
871       _mesa_bufferobj_unmap(ctx, bo, MAP_INTERNAL);
872 
873    _mesa_vao_unmap_arrays(ctx, vao);
874 }
875 
876 
877 /**********************************************************************/
878 /* API Functions                                                      */
879 /**********************************************************************/
880 
881 
882 /**
883  * ARB version of glBindVertexArray()
884  */
885 static ALWAYS_INLINE void
bind_vertex_array(struct gl_context * ctx,GLuint id,bool no_error)886 bind_vertex_array(struct gl_context *ctx, GLuint id, bool no_error)
887 {
888    struct gl_vertex_array_object *const oldObj = ctx->Array.VAO;
889    struct gl_vertex_array_object *newObj = NULL;
890 
891    assert(oldObj != NULL);
892 
893    if (oldObj->Name == id)
894       return;   /* rebinding the same array object- no change */
895 
896    /*
897     * Get pointer to new array object (newObj)
898     */
899    if (id == 0) {
900       /* The spec says there is no array object named 0, but we use
901        * one internally because it simplifies things.
902        */
903       newObj = ctx->Array.DefaultVAO;
904    }
905    else {
906       /* non-default array object */
907       newObj = _mesa_lookup_vao(ctx, id);
908       if (!no_error && !newObj) {
909          _mesa_error(ctx, GL_INVALID_OPERATION,
910                      "glBindVertexArray(non-gen name)");
911          return;
912       }
913 
914       newObj->EverBound = GL_TRUE;
915    }
916 
917    _mesa_reference_vao(ctx, &ctx->Array.VAO, newObj);
918    _mesa_set_draw_vao(ctx, newObj);
919 
920    /* Update the valid-to-render state if binding on unbinding default VAO
921     * if drawing with the default VAO is invalid.
922     */
923    if (_mesa_is_desktop_gl_core(ctx) &&
924        (oldObj == ctx->Array.DefaultVAO) != (newObj == ctx->Array.DefaultVAO))
925       _mesa_update_valid_to_render_state(ctx);
926 }
927 
928 
929 void GLAPIENTRY
_mesa_BindVertexArray_no_error(GLuint id)930 _mesa_BindVertexArray_no_error(GLuint id)
931 {
932    GET_CURRENT_CONTEXT(ctx);
933    bind_vertex_array(ctx, id, true);
934 }
935 
936 
937 void GLAPIENTRY
_mesa_BindVertexArray(GLuint id)938 _mesa_BindVertexArray(GLuint id)
939 {
940    GET_CURRENT_CONTEXT(ctx);
941    bind_vertex_array(ctx, id, false);
942 }
943 
944 
945 /**
946  * Delete a set of array objects.
947  *
948  * \param n      Number of array objects to delete.
949  * \param ids    Array of \c n array object IDs.
950  */
951 static void
delete_vertex_arrays(struct gl_context * ctx,GLsizei n,const GLuint * ids)952 delete_vertex_arrays(struct gl_context *ctx, GLsizei n, const GLuint *ids)
953 {
954    GLsizei i;
955 
956    for (i = 0; i < n; i++) {
957       /* IDs equal to 0 should be silently ignored. */
958       if (!ids[i])
959          continue;
960 
961       struct gl_vertex_array_object *obj = _mesa_lookup_vao(ctx, ids[i]);
962 
963       if (obj) {
964          assert(obj->Name == ids[i]);
965 
966          /* If the array object is currently bound, the spec says "the binding
967           * for that object reverts to zero and the default vertex array
968           * becomes current."
969           */
970          if (obj == ctx->Array.VAO)
971             _mesa_BindVertexArray_no_error(0);
972 
973          /* The ID is immediately freed for re-use */
974          _mesa_HashRemoveLocked(&ctx->Array.Objects, obj->Name);
975 
976          if (ctx->Array.LastLookedUpVAO == obj)
977             _mesa_reference_vao(ctx, &ctx->Array.LastLookedUpVAO, NULL);
978 
979          /* Unreference the array object.
980           * If refcount hits zero, the object will be deleted.
981           */
982          _mesa_reference_vao(ctx, &obj, NULL);
983       }
984    }
985 }
986 
987 
988 void GLAPIENTRY
_mesa_DeleteVertexArrays_no_error(GLsizei n,const GLuint * ids)989 _mesa_DeleteVertexArrays_no_error(GLsizei n, const GLuint *ids)
990 {
991    GET_CURRENT_CONTEXT(ctx);
992    delete_vertex_arrays(ctx, n, ids);
993 }
994 
995 
996 void GLAPIENTRY
_mesa_DeleteVertexArrays(GLsizei n,const GLuint * ids)997 _mesa_DeleteVertexArrays(GLsizei n, const GLuint *ids)
998 {
999    GET_CURRENT_CONTEXT(ctx);
1000 
1001    if (n < 0) {
1002       _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteVertexArray(n)");
1003       return;
1004    }
1005 
1006    delete_vertex_arrays(ctx, n, ids);
1007 }
1008 
1009 
1010 /**
1011  * Generate a set of unique array object IDs and store them in \c arrays.
1012  * Helper for _mesa_GenVertexArrays() and _mesa_CreateVertexArrays()
1013  * below.
1014  *
1015  * \param n       Number of IDs to generate.
1016  * \param arrays  Array of \c n locations to store the IDs.
1017  * \param create  Indicates that the objects should also be created.
1018  * \param func    The name of the GL entry point.
1019  */
1020 static void
gen_vertex_arrays(struct gl_context * ctx,GLsizei n,GLuint * arrays,bool create,const char * func)1021 gen_vertex_arrays(struct gl_context *ctx, GLsizei n, GLuint *arrays,
1022                   bool create, const char *func)
1023 {
1024    GLint i;
1025 
1026    if (!arrays)
1027       return;
1028 
1029    _mesa_HashFindFreeKeys(&ctx->Array.Objects, arrays, n);
1030 
1031    /* For the sake of simplicity we create the array objects in both
1032     * the Gen* and Create* cases.  The only difference is the value of
1033     * EverBound, which is set to true in the Create* case.
1034     */
1035    for (i = 0; i < n; i++) {
1036       struct gl_vertex_array_object *obj;
1037 
1038       obj = _mesa_new_vao(ctx, arrays[i]);
1039       if (!obj) {
1040          _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
1041          return;
1042       }
1043       obj->EverBound = create;
1044       _mesa_HashInsertLocked(&ctx->Array.Objects, obj->Name, obj);
1045    }
1046 }
1047 
1048 
1049 static void
gen_vertex_arrays_err(struct gl_context * ctx,GLsizei n,GLuint * arrays,bool create,const char * func)1050 gen_vertex_arrays_err(struct gl_context *ctx, GLsizei n, GLuint *arrays,
1051                       bool create, const char *func)
1052 {
1053    if (n < 0) {
1054       _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
1055       return;
1056    }
1057 
1058    gen_vertex_arrays(ctx, n, arrays, create, func);
1059 }
1060 
1061 
1062 /**
1063  * ARB version of glGenVertexArrays()
1064  * All arrays will be required to live in VBOs.
1065  */
1066 void GLAPIENTRY
_mesa_GenVertexArrays_no_error(GLsizei n,GLuint * arrays)1067 _mesa_GenVertexArrays_no_error(GLsizei n, GLuint *arrays)
1068 {
1069    GET_CURRENT_CONTEXT(ctx);
1070    gen_vertex_arrays(ctx, n, arrays, false, "glGenVertexArrays");
1071 }
1072 
1073 
1074 void GLAPIENTRY
_mesa_GenVertexArrays(GLsizei n,GLuint * arrays)1075 _mesa_GenVertexArrays(GLsizei n, GLuint *arrays)
1076 {
1077    GET_CURRENT_CONTEXT(ctx);
1078    gen_vertex_arrays_err(ctx, n, arrays, false, "glGenVertexArrays");
1079 }
1080 
1081 
1082 /**
1083  * ARB_direct_state_access
1084  * Generates ID's and creates the array objects.
1085  */
1086 void GLAPIENTRY
_mesa_CreateVertexArrays_no_error(GLsizei n,GLuint * arrays)1087 _mesa_CreateVertexArrays_no_error(GLsizei n, GLuint *arrays)
1088 {
1089    GET_CURRENT_CONTEXT(ctx);
1090    gen_vertex_arrays(ctx, n, arrays, true, "glCreateVertexArrays");
1091 }
1092 
1093 
1094 void GLAPIENTRY
_mesa_CreateVertexArrays(GLsizei n,GLuint * arrays)1095 _mesa_CreateVertexArrays(GLsizei n, GLuint *arrays)
1096 {
1097    GET_CURRENT_CONTEXT(ctx);
1098    gen_vertex_arrays_err(ctx, n, arrays, true, "glCreateVertexArrays");
1099 }
1100 
1101 
1102 /**
1103  * Determine if ID is the name of an array object.
1104  *
1105  * \param id  ID of the potential array object.
1106  * \return  \c GL_TRUE if \c id is the name of a array object,
1107  *          \c GL_FALSE otherwise.
1108  */
1109 GLboolean GLAPIENTRY
_mesa_IsVertexArray(GLuint id)1110 _mesa_IsVertexArray( GLuint id )
1111 {
1112    struct gl_vertex_array_object * obj;
1113    GET_CURRENT_CONTEXT(ctx);
1114    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1115 
1116    obj = _mesa_lookup_vao(ctx, id);
1117 
1118    return obj != NULL && obj->EverBound;
1119 }
1120 
1121 
1122 /**
1123  * Sets the element array buffer binding of a vertex array object.
1124  *
1125  * This is the ARB_direct_state_access equivalent of
1126  * glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer).
1127  */
1128 static ALWAYS_INLINE void
vertex_array_element_buffer(struct gl_context * ctx,GLuint vaobj,GLuint buffer,bool no_error)1129 vertex_array_element_buffer(struct gl_context *ctx, GLuint vaobj, GLuint buffer,
1130                             bool no_error)
1131 {
1132    struct gl_vertex_array_object *vao;
1133    struct gl_buffer_object *bufObj;
1134 
1135    ASSERT_OUTSIDE_BEGIN_END(ctx);
1136 
1137    if (!no_error) {
1138       /* The GL_ARB_direct_state_access specification says:
1139        *
1140        *    "An INVALID_OPERATION error is generated by
1141        *     VertexArrayElementBuffer if <vaobj> is not [compatibility profile:
1142        *     zero or] the name of an existing vertex array object."
1143        */
1144       vao =_mesa_lookup_vao_err(ctx, vaobj, false, "glVertexArrayElementBuffer");
1145       if (!vao)
1146          return;
1147    } else {
1148       vao = _mesa_lookup_vao(ctx, vaobj);
1149    }
1150 
1151    if (buffer != 0) {
1152       if (!no_error) {
1153          /* The GL_ARB_direct_state_access specification says:
1154           *
1155           *    "An INVALID_OPERATION error is generated if <buffer> is not zero
1156           *     or the name of an existing buffer object."
1157           */
1158          bufObj = _mesa_lookup_bufferobj_err(ctx, buffer,
1159                                              "glVertexArrayElementBuffer");
1160       } else {
1161          bufObj = _mesa_lookup_bufferobj(ctx, buffer);
1162       }
1163 
1164       if (!bufObj)
1165          return;
1166    } else {
1167       bufObj = NULL;
1168    }
1169 
1170    _mesa_reference_buffer_object(ctx, &vao->IndexBufferObj, bufObj);
1171 }
1172 
1173 
1174 void GLAPIENTRY
_mesa_VertexArrayElementBuffer_no_error(GLuint vaobj,GLuint buffer)1175 _mesa_VertexArrayElementBuffer_no_error(GLuint vaobj, GLuint buffer)
1176 {
1177    GET_CURRENT_CONTEXT(ctx);
1178    vertex_array_element_buffer(ctx, vaobj, buffer, true);
1179 }
1180 
1181 
1182 void GLAPIENTRY
_mesa_VertexArrayElementBuffer(GLuint vaobj,GLuint buffer)1183 _mesa_VertexArrayElementBuffer(GLuint vaobj, GLuint buffer)
1184 {
1185    GET_CURRENT_CONTEXT(ctx);
1186    vertex_array_element_buffer(ctx, vaobj, buffer, false);
1187 }
1188 
1189 
1190 void GLAPIENTRY
_mesa_GetVertexArrayiv(GLuint vaobj,GLenum pname,GLint * param)1191 _mesa_GetVertexArrayiv(GLuint vaobj, GLenum pname, GLint *param)
1192 {
1193    GET_CURRENT_CONTEXT(ctx);
1194    struct gl_vertex_array_object *vao;
1195 
1196    ASSERT_OUTSIDE_BEGIN_END(ctx);
1197 
1198    /* The GL_ARB_direct_state_access specification says:
1199     *
1200     *   "An INVALID_OPERATION error is generated if <vaobj> is not
1201     *    [compatibility profile: zero or] the name of an existing
1202     *    vertex array object."
1203     */
1204    vao = _mesa_lookup_vao_err(ctx, vaobj, false, "glGetVertexArrayiv");
1205    if (!vao)
1206       return;
1207 
1208    /* The GL_ARB_direct_state_access specification says:
1209     *
1210     *   "An INVALID_ENUM error is generated if <pname> is not
1211     *    ELEMENT_ARRAY_BUFFER_BINDING."
1212     */
1213    if (pname != GL_ELEMENT_ARRAY_BUFFER_BINDING) {
1214       _mesa_error(ctx, GL_INVALID_ENUM,
1215                   "glGetVertexArrayiv(pname != "
1216                   "GL_ELEMENT_ARRAY_BUFFER_BINDING)");
1217       return;
1218    }
1219 
1220    param[0] = vao->IndexBufferObj ? vao->IndexBufferObj->Name : 0;
1221 }
1222