1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5848b8605Smrg * (C) Copyright IBM Corporation 2006
6848b8605Smrg * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
7848b8605Smrg *
8848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
9848b8605Smrg * copy of this software and associated documentation files (the "Software"),
10848b8605Smrg * to deal in the Software without restriction, including without limitation
11848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
13848b8605Smrg * Software is furnished to do so, subject to the following conditions:
14848b8605Smrg *
15848b8605Smrg * The above copyright notice and this permission notice shall be included
16848b8605Smrg * in all copies or substantial portions of the Software.
17848b8605Smrg *
18848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
25848b8605Smrg */
26848b8605Smrg
27848b8605Smrg
28848b8605Smrg/**
29848b8605Smrg * \file arrayobj.c
30848b8605Smrg *
31b8e80941Smrg * Implementation of Vertex Array Objects (VAOs), from OpenGL 3.1+ /
32b8e80941Smrg * the GL_ARB_vertex_array_object extension.
33848b8605Smrg *
34848b8605Smrg * \todo
35848b8605Smrg * The code in this file borrows a lot from bufferobj.c.  There's a certain
36848b8605Smrg * amount of cruft left over from that origin that may be unnecessary.
37848b8605Smrg *
38848b8605Smrg * \author Ian Romanick <idr@us.ibm.com>
39848b8605Smrg * \author Brian Paul
40848b8605Smrg */
41848b8605Smrg
42848b8605Smrg
43848b8605Smrg#include "glheader.h"
44848b8605Smrg#include "hash.h"
45848b8605Smrg#include "image.h"
46848b8605Smrg#include "imports.h"
47848b8605Smrg#include "context.h"
48848b8605Smrg#include "bufferobj.h"
49848b8605Smrg#include "arrayobj.h"
50848b8605Smrg#include "macros.h"
51848b8605Smrg#include "mtypes.h"
52b8e80941Smrg#include "state.h"
53848b8605Smrg#include "varray.h"
54b8e80941Smrg#include "util/bitscan.h"
55b8e80941Smrg#include "util/u_atomic.h"
56b8e80941Smrg#include "util/u_math.h"
57b8e80941Smrg
58b8e80941Smrg
59b8e80941Smrgconst GLubyte
60b8e80941Smrg_mesa_vao_attribute_map[ATTRIBUTE_MAP_MODE_MAX][VERT_ATTRIB_MAX] =
61b8e80941Smrg{
62b8e80941Smrg   /* ATTRIBUTE_MAP_MODE_IDENTITY
63b8e80941Smrg    *
64b8e80941Smrg    * Grab vertex processing attribute VERT_ATTRIB_POS from
65b8e80941Smrg    * the VAO attribute VERT_ATTRIB_POS, and grab vertex processing
66b8e80941Smrg    * attribute VERT_ATTRIB_GENERIC0 from the VAO attribute
67b8e80941Smrg    * VERT_ATTRIB_GENERIC0.
68b8e80941Smrg    */
69b8e80941Smrg   {
70b8e80941Smrg      VERT_ATTRIB_POS,                 /* VERT_ATTRIB_POS */
71b8e80941Smrg      VERT_ATTRIB_NORMAL,              /* VERT_ATTRIB_NORMAL */
72b8e80941Smrg      VERT_ATTRIB_COLOR0,              /* VERT_ATTRIB_COLOR0 */
73b8e80941Smrg      VERT_ATTRIB_COLOR1,              /* VERT_ATTRIB_COLOR1 */
74b8e80941Smrg      VERT_ATTRIB_FOG,                 /* VERT_ATTRIB_FOG */
75b8e80941Smrg      VERT_ATTRIB_COLOR_INDEX,         /* VERT_ATTRIB_COLOR_INDEX */
76b8e80941Smrg      VERT_ATTRIB_EDGEFLAG,            /* VERT_ATTRIB_EDGEFLAG */
77b8e80941Smrg      VERT_ATTRIB_TEX0,                /* VERT_ATTRIB_TEX0 */
78b8e80941Smrg      VERT_ATTRIB_TEX1,                /* VERT_ATTRIB_TEX1 */
79b8e80941Smrg      VERT_ATTRIB_TEX2,                /* VERT_ATTRIB_TEX2 */
80b8e80941Smrg      VERT_ATTRIB_TEX3,                /* VERT_ATTRIB_TEX3 */
81b8e80941Smrg      VERT_ATTRIB_TEX4,                /* VERT_ATTRIB_TEX4 */
82b8e80941Smrg      VERT_ATTRIB_TEX5,                /* VERT_ATTRIB_TEX5 */
83b8e80941Smrg      VERT_ATTRIB_TEX6,                /* VERT_ATTRIB_TEX6 */
84b8e80941Smrg      VERT_ATTRIB_TEX7,                /* VERT_ATTRIB_TEX7 */
85b8e80941Smrg      VERT_ATTRIB_POINT_SIZE,          /* VERT_ATTRIB_POINT_SIZE */
86b8e80941Smrg      VERT_ATTRIB_GENERIC0,            /* VERT_ATTRIB_GENERIC0 */
87b8e80941Smrg      VERT_ATTRIB_GENERIC1,            /* VERT_ATTRIB_GENERIC1 */
88b8e80941Smrg      VERT_ATTRIB_GENERIC2,            /* VERT_ATTRIB_GENERIC2 */
89b8e80941Smrg      VERT_ATTRIB_GENERIC3,            /* VERT_ATTRIB_GENERIC3 */
90b8e80941Smrg      VERT_ATTRIB_GENERIC4,            /* VERT_ATTRIB_GENERIC4 */
91b8e80941Smrg      VERT_ATTRIB_GENERIC5,            /* VERT_ATTRIB_GENERIC5 */
92b8e80941Smrg      VERT_ATTRIB_GENERIC6,            /* VERT_ATTRIB_GENERIC6 */
93b8e80941Smrg      VERT_ATTRIB_GENERIC7,            /* VERT_ATTRIB_GENERIC7 */
94b8e80941Smrg      VERT_ATTRIB_GENERIC8,            /* VERT_ATTRIB_GENERIC8 */
95b8e80941Smrg      VERT_ATTRIB_GENERIC9,            /* VERT_ATTRIB_GENERIC9 */
96b8e80941Smrg      VERT_ATTRIB_GENERIC10,           /* VERT_ATTRIB_GENERIC10 */
97b8e80941Smrg      VERT_ATTRIB_GENERIC11,           /* VERT_ATTRIB_GENERIC11 */
98b8e80941Smrg      VERT_ATTRIB_GENERIC12,           /* VERT_ATTRIB_GENERIC12 */
99b8e80941Smrg      VERT_ATTRIB_GENERIC13,           /* VERT_ATTRIB_GENERIC13 */
100b8e80941Smrg      VERT_ATTRIB_GENERIC14,           /* VERT_ATTRIB_GENERIC14 */
101b8e80941Smrg      VERT_ATTRIB_GENERIC15            /* VERT_ATTRIB_GENERIC15 */
102b8e80941Smrg   },
103b8e80941Smrg
104b8e80941Smrg   /* ATTRIBUTE_MAP_MODE_POSITION
105b8e80941Smrg    *
106b8e80941Smrg    * Grab vertex processing attribute VERT_ATTRIB_POS as well as
107b8e80941Smrg    * vertex processing attribute VERT_ATTRIB_GENERIC0 from the
108b8e80941Smrg    * VAO attribute VERT_ATTRIB_POS.
109b8e80941Smrg    */
110b8e80941Smrg   {
111b8e80941Smrg      VERT_ATTRIB_POS,                 /* VERT_ATTRIB_POS */
112b8e80941Smrg      VERT_ATTRIB_NORMAL,              /* VERT_ATTRIB_NORMAL */
113b8e80941Smrg      VERT_ATTRIB_COLOR0,              /* VERT_ATTRIB_COLOR0 */
114b8e80941Smrg      VERT_ATTRIB_COLOR1,              /* VERT_ATTRIB_COLOR1 */
115b8e80941Smrg      VERT_ATTRIB_FOG,                 /* VERT_ATTRIB_FOG */
116b8e80941Smrg      VERT_ATTRIB_COLOR_INDEX,         /* VERT_ATTRIB_COLOR_INDEX */
117b8e80941Smrg      VERT_ATTRIB_EDGEFLAG,            /* VERT_ATTRIB_EDGEFLAG */
118b8e80941Smrg      VERT_ATTRIB_TEX0,                /* VERT_ATTRIB_TEX0 */
119b8e80941Smrg      VERT_ATTRIB_TEX1,                /* VERT_ATTRIB_TEX1 */
120b8e80941Smrg      VERT_ATTRIB_TEX2,                /* VERT_ATTRIB_TEX2 */
121b8e80941Smrg      VERT_ATTRIB_TEX3,                /* VERT_ATTRIB_TEX3 */
122b8e80941Smrg      VERT_ATTRIB_TEX4,                /* VERT_ATTRIB_TEX4 */
123b8e80941Smrg      VERT_ATTRIB_TEX5,                /* VERT_ATTRIB_TEX5 */
124b8e80941Smrg      VERT_ATTRIB_TEX6,                /* VERT_ATTRIB_TEX6 */
125b8e80941Smrg      VERT_ATTRIB_TEX7,                /* VERT_ATTRIB_TEX7 */
126b8e80941Smrg      VERT_ATTRIB_POINT_SIZE,          /* VERT_ATTRIB_POINT_SIZE */
127b8e80941Smrg      VERT_ATTRIB_POS,                 /* VERT_ATTRIB_GENERIC0 */
128b8e80941Smrg      VERT_ATTRIB_GENERIC1,            /* VERT_ATTRIB_GENERIC1 */
129b8e80941Smrg      VERT_ATTRIB_GENERIC2,            /* VERT_ATTRIB_GENERIC2 */
130b8e80941Smrg      VERT_ATTRIB_GENERIC3,            /* VERT_ATTRIB_GENERIC3 */
131b8e80941Smrg      VERT_ATTRIB_GENERIC4,            /* VERT_ATTRIB_GENERIC4 */
132b8e80941Smrg      VERT_ATTRIB_GENERIC5,            /* VERT_ATTRIB_GENERIC5 */
133b8e80941Smrg      VERT_ATTRIB_GENERIC6,            /* VERT_ATTRIB_GENERIC6 */
134b8e80941Smrg      VERT_ATTRIB_GENERIC7,            /* VERT_ATTRIB_GENERIC7 */
135b8e80941Smrg      VERT_ATTRIB_GENERIC8,            /* VERT_ATTRIB_GENERIC8 */
136b8e80941Smrg      VERT_ATTRIB_GENERIC9,            /* VERT_ATTRIB_GENERIC9 */
137b8e80941Smrg      VERT_ATTRIB_GENERIC10,           /* VERT_ATTRIB_GENERIC10 */
138b8e80941Smrg      VERT_ATTRIB_GENERIC11,           /* VERT_ATTRIB_GENERIC11 */
139b8e80941Smrg      VERT_ATTRIB_GENERIC12,           /* VERT_ATTRIB_GENERIC12 */
140b8e80941Smrg      VERT_ATTRIB_GENERIC13,           /* VERT_ATTRIB_GENERIC13 */
141b8e80941Smrg      VERT_ATTRIB_GENERIC14,           /* VERT_ATTRIB_GENERIC14 */
142b8e80941Smrg      VERT_ATTRIB_GENERIC15            /* VERT_ATTRIB_GENERIC15 */
143b8e80941Smrg   },
144b8e80941Smrg
145b8e80941Smrg   /* ATTRIBUTE_MAP_MODE_GENERIC0
146b8e80941Smrg    *
147b8e80941Smrg    * Grab vertex processing attribute VERT_ATTRIB_POS as well as
148b8e80941Smrg    * vertex processing attribute VERT_ATTRIB_GENERIC0 from the
149b8e80941Smrg    * VAO attribute VERT_ATTRIB_GENERIC0.
150b8e80941Smrg    */
151b8e80941Smrg   {
152b8e80941Smrg      VERT_ATTRIB_GENERIC0,            /* VERT_ATTRIB_POS */
153b8e80941Smrg      VERT_ATTRIB_NORMAL,              /* VERT_ATTRIB_NORMAL */
154b8e80941Smrg      VERT_ATTRIB_COLOR0,              /* VERT_ATTRIB_COLOR0 */
155b8e80941Smrg      VERT_ATTRIB_COLOR1,              /* VERT_ATTRIB_COLOR1 */
156b8e80941Smrg      VERT_ATTRIB_FOG,                 /* VERT_ATTRIB_FOG */
157b8e80941Smrg      VERT_ATTRIB_COLOR_INDEX,         /* VERT_ATTRIB_COLOR_INDEX */
158b8e80941Smrg      VERT_ATTRIB_EDGEFLAG,            /* VERT_ATTRIB_EDGEFLAG */
159b8e80941Smrg      VERT_ATTRIB_TEX0,                /* VERT_ATTRIB_TEX0 */
160b8e80941Smrg      VERT_ATTRIB_TEX1,                /* VERT_ATTRIB_TEX1 */
161b8e80941Smrg      VERT_ATTRIB_TEX2,                /* VERT_ATTRIB_TEX2 */
162b8e80941Smrg      VERT_ATTRIB_TEX3,                /* VERT_ATTRIB_TEX3 */
163b8e80941Smrg      VERT_ATTRIB_TEX4,                /* VERT_ATTRIB_TEX4 */
164b8e80941Smrg      VERT_ATTRIB_TEX5,                /* VERT_ATTRIB_TEX5 */
165b8e80941Smrg      VERT_ATTRIB_TEX6,                /* VERT_ATTRIB_TEX6 */
166b8e80941Smrg      VERT_ATTRIB_TEX7,                /* VERT_ATTRIB_TEX7 */
167b8e80941Smrg      VERT_ATTRIB_POINT_SIZE,          /* VERT_ATTRIB_POINT_SIZE */
168b8e80941Smrg      VERT_ATTRIB_GENERIC0,            /* VERT_ATTRIB_GENERIC0 */
169b8e80941Smrg      VERT_ATTRIB_GENERIC1,            /* VERT_ATTRIB_GENERIC1 */
170b8e80941Smrg      VERT_ATTRIB_GENERIC2,            /* VERT_ATTRIB_GENERIC2 */
171b8e80941Smrg      VERT_ATTRIB_GENERIC3,            /* VERT_ATTRIB_GENERIC3 */
172b8e80941Smrg      VERT_ATTRIB_GENERIC4,            /* VERT_ATTRIB_GENERIC4 */
173b8e80941Smrg      VERT_ATTRIB_GENERIC5,            /* VERT_ATTRIB_GENERIC5 */
174b8e80941Smrg      VERT_ATTRIB_GENERIC6,            /* VERT_ATTRIB_GENERIC6 */
175b8e80941Smrg      VERT_ATTRIB_GENERIC7,            /* VERT_ATTRIB_GENERIC7 */
176b8e80941Smrg      VERT_ATTRIB_GENERIC8,            /* VERT_ATTRIB_GENERIC8 */
177b8e80941Smrg      VERT_ATTRIB_GENERIC9,            /* VERT_ATTRIB_GENERIC9 */
178b8e80941Smrg      VERT_ATTRIB_GENERIC10,           /* VERT_ATTRIB_GENERIC10 */
179b8e80941Smrg      VERT_ATTRIB_GENERIC11,           /* VERT_ATTRIB_GENERIC11 */
180b8e80941Smrg      VERT_ATTRIB_GENERIC12,           /* VERT_ATTRIB_GENERIC12 */
181b8e80941Smrg      VERT_ATTRIB_GENERIC13,           /* VERT_ATTRIB_GENERIC13 */
182b8e80941Smrg      VERT_ATTRIB_GENERIC14,           /* VERT_ATTRIB_GENERIC14 */
183b8e80941Smrg      VERT_ATTRIB_GENERIC15            /* VERT_ATTRIB_GENERIC15 */
184b8e80941Smrg   }
185b8e80941Smrg};
186848b8605Smrg
187848b8605Smrg
188848b8605Smrg/**
189848b8605Smrg * Look up the array object for the given ID.
190848b8605Smrg *
191848b8605Smrg * \returns
192848b8605Smrg * Either a pointer to the array object with the specified ID or \c NULL for
193848b8605Smrg * a non-existent ID.  The spec defines ID 0 as being technically
194848b8605Smrg * non-existent.
195848b8605Smrg */
196848b8605Smrg
197848b8605Smrgstruct gl_vertex_array_object *
198848b8605Smrg_mesa_lookup_vao(struct gl_context *ctx, GLuint id)
199848b8605Smrg{
200b8e80941Smrg   /* The ARB_direct_state_access specification says:
201b8e80941Smrg    *
202b8e80941Smrg    *    "<vaobj> is [compatibility profile:
203b8e80941Smrg    *     zero, indicating the default vertex array object, or]
204b8e80941Smrg    *     the name of the vertex array object."
205b8e80941Smrg    */
206b8e80941Smrg   if (id == 0) {
207b8e80941Smrg      if (ctx->API == API_OPENGL_COMPAT)
208b8e80941Smrg         return ctx->Array.DefaultVAO;
209b8e80941Smrg
210848b8605Smrg      return NULL;
211b8e80941Smrg   } else {
212b8e80941Smrg      struct gl_vertex_array_object *vao;
213b8e80941Smrg
214b8e80941Smrg      if (ctx->Array.LastLookedUpVAO &&
215b8e80941Smrg          ctx->Array.LastLookedUpVAO->Name == id) {
216b8e80941Smrg         vao = ctx->Array.LastLookedUpVAO;
217b8e80941Smrg      } else {
218b8e80941Smrg         vao = (struct gl_vertex_array_object *)
219b8e80941Smrg            _mesa_HashLookupLocked(ctx->Array.Objects, id);
220b8e80941Smrg
221b8e80941Smrg         _mesa_reference_vao(ctx, &ctx->Array.LastLookedUpVAO, vao);
222b8e80941Smrg      }
223b8e80941Smrg
224b8e80941Smrg      return vao;
225b8e80941Smrg   }
226b8e80941Smrg}
227b8e80941Smrg
228b8e80941Smrg
229b8e80941Smrg/**
230b8e80941Smrg * Looks up the array object for the given ID.
231b8e80941Smrg *
232b8e80941Smrg * Unlike _mesa_lookup_vao, this function generates a GL_INVALID_OPERATION
233b8e80941Smrg * error if the array object does not exist. It also returns the default
234b8e80941Smrg * array object when ctx is a compatibility profile context and id is zero.
235b8e80941Smrg */
236b8e80941Smrgstruct gl_vertex_array_object *
237b8e80941Smrg_mesa_lookup_vao_err(struct gl_context *ctx, GLuint id, const char *caller)
238b8e80941Smrg{
239b8e80941Smrg   /* The ARB_direct_state_access specification says:
240b8e80941Smrg    *
241b8e80941Smrg    *    "<vaobj> is [compatibility profile:
242b8e80941Smrg    *     zero, indicating the default vertex array object, or]
243b8e80941Smrg    *     the name of the vertex array object."
244b8e80941Smrg    */
245b8e80941Smrg   if (id == 0) {
246b8e80941Smrg      if (ctx->API == API_OPENGL_CORE) {
247b8e80941Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
248b8e80941Smrg                     "%s(zero is not valid vaobj name in a core profile "
249b8e80941Smrg                     "context)", caller);
250b8e80941Smrg         return NULL;
251b8e80941Smrg      }
252b8e80941Smrg
253b8e80941Smrg      return ctx->Array.DefaultVAO;
254b8e80941Smrg   } else {
255b8e80941Smrg      struct gl_vertex_array_object *vao;
256b8e80941Smrg
257b8e80941Smrg      if (ctx->Array.LastLookedUpVAO &&
258b8e80941Smrg          ctx->Array.LastLookedUpVAO->Name == id) {
259b8e80941Smrg         vao = ctx->Array.LastLookedUpVAO;
260b8e80941Smrg      } else {
261b8e80941Smrg         vao = (struct gl_vertex_array_object *)
262b8e80941Smrg            _mesa_HashLookupLocked(ctx->Array.Objects, id);
263b8e80941Smrg
264b8e80941Smrg         /* The ARB_direct_state_access specification says:
265b8e80941Smrg          *
266b8e80941Smrg          *    "An INVALID_OPERATION error is generated if <vaobj> is not
267b8e80941Smrg          *     [compatibility profile: zero or] the name of an existing
268b8e80941Smrg          *     vertex array object."
269b8e80941Smrg          */
270b8e80941Smrg         if (!vao || !vao->EverBound) {
271b8e80941Smrg            _mesa_error(ctx, GL_INVALID_OPERATION,
272b8e80941Smrg                        "%s(non-existent vaobj=%u)", caller, id);
273b8e80941Smrg            return NULL;
274b8e80941Smrg         }
275b8e80941Smrg
276b8e80941Smrg         _mesa_reference_vao(ctx, &ctx->Array.LastLookedUpVAO, vao);
277b8e80941Smrg      }
278b8e80941Smrg
279b8e80941Smrg      return vao;
280b8e80941Smrg   }
281848b8605Smrg}
282848b8605Smrg
283848b8605Smrg
284848b8605Smrg/**
285848b8605Smrg * For all the vertex binding points in the array object, unbind any pointers
286848b8605Smrg * to any buffer objects (VBOs).
287848b8605Smrg * This is done just prior to array object destruction.
288848b8605Smrg */
289848b8605Smrgstatic void
290848b8605Smrgunbind_array_object_vbos(struct gl_context *ctx, struct gl_vertex_array_object *obj)
291848b8605Smrg{
292848b8605Smrg   GLuint i;
293848b8605Smrg
294b8e80941Smrg   for (i = 0; i < ARRAY_SIZE(obj->BufferBinding); i++)
295b8e80941Smrg      _mesa_reference_buffer_object(ctx, &obj->BufferBinding[i].BufferObj, NULL);
296848b8605Smrg}
297848b8605Smrg
298848b8605Smrg
299848b8605Smrg/**
300848b8605Smrg * Allocate and initialize a new vertex array object.
301848b8605Smrg */
302848b8605Smrgstruct gl_vertex_array_object *
303848b8605Smrg_mesa_new_vao(struct gl_context *ctx, GLuint name)
304848b8605Smrg{
305848b8605Smrg   struct gl_vertex_array_object *obj = CALLOC_STRUCT(gl_vertex_array_object);
306848b8605Smrg   if (obj)
307848b8605Smrg      _mesa_initialize_vao(ctx, obj, name);
308848b8605Smrg   return obj;
309848b8605Smrg}
310848b8605Smrg
311848b8605Smrg
312848b8605Smrg/**
313848b8605Smrg * Delete an array object.
314848b8605Smrg */
315848b8605Smrgvoid
316848b8605Smrg_mesa_delete_vao(struct gl_context *ctx, struct gl_vertex_array_object *obj)
317848b8605Smrg{
318848b8605Smrg   unbind_array_object_vbos(ctx, obj);
319848b8605Smrg   _mesa_reference_buffer_object(ctx, &obj->IndexBufferObj, NULL);
320848b8605Smrg   free(obj->Label);
321848b8605Smrg   free(obj);
322848b8605Smrg}
323848b8605Smrg
324848b8605Smrg
325848b8605Smrg/**
326848b8605Smrg * Set ptr to vao w/ reference counting.
327848b8605Smrg * Note: this should only be called from the _mesa_reference_vao()
328848b8605Smrg * inline function.
329848b8605Smrg */
330848b8605Smrgvoid
331848b8605Smrg_mesa_reference_vao_(struct gl_context *ctx,
332848b8605Smrg                     struct gl_vertex_array_object **ptr,
333848b8605Smrg                     struct gl_vertex_array_object *vao)
334848b8605Smrg{
335848b8605Smrg   assert(*ptr != vao);
336848b8605Smrg
337848b8605Smrg   if (*ptr) {
338848b8605Smrg      /* Unreference the old array object */
339848b8605Smrg      struct gl_vertex_array_object *oldObj = *ptr;
340848b8605Smrg
341b8e80941Smrg      bool deleteFlag;
342b8e80941Smrg      if (oldObj->SharedAndImmutable) {
343b8e80941Smrg         deleteFlag = p_atomic_dec_zero(&oldObj->RefCount);
344b8e80941Smrg      } else {
345b8e80941Smrg         assert(oldObj->RefCount > 0);
346b8e80941Smrg         oldObj->RefCount--;
347b8e80941Smrg         deleteFlag = (oldObj->RefCount == 0);
348848b8605Smrg      }
349848b8605Smrg
350b8e80941Smrg      if (deleteFlag)
351b8e80941Smrg         _mesa_delete_vao(ctx, oldObj);
352b8e80941Smrg
353848b8605Smrg      *ptr = NULL;
354848b8605Smrg   }
355b8e80941Smrg   assert(!*ptr);
356848b8605Smrg
357848b8605Smrg   if (vao) {
358848b8605Smrg      /* reference new array object */
359b8e80941Smrg      if (vao->SharedAndImmutable) {
360b8e80941Smrg         p_atomic_inc(&vao->RefCount);
361b8e80941Smrg      } else {
362b8e80941Smrg         assert(vao->RefCount > 0);
363848b8605Smrg         vao->RefCount++;
364848b8605Smrg      }
365b8e80941Smrg
366b8e80941Smrg      *ptr = vao;
367848b8605Smrg   }
368848b8605Smrg}
369848b8605Smrg
370848b8605Smrg
371b8e80941Smrg/**
372b8e80941Smrg * Initialize attributes of a vertex array within a vertex array object.
373b8e80941Smrg * \param vao  the container vertex array object
374b8e80941Smrg * \param index  which array in the VAO to initialize
375b8e80941Smrg * \param size  number of components (1, 2, 3 or 4) per attribute
376b8e80941Smrg * \param type  datatype of the attribute (GL_FLOAT, GL_INT, etc).
377b8e80941Smrg */
378848b8605Smrgstatic void
379848b8605Smrginit_array(struct gl_context *ctx,
380b8e80941Smrg           struct gl_vertex_array_object *vao,
381b8e80941Smrg           gl_vert_attrib index, GLint size, GLint type)
382848b8605Smrg{
383b8e80941Smrg   assert(index < ARRAY_SIZE(vao->VertexAttrib));
384b8e80941Smrg   struct gl_array_attributes *array = &vao->VertexAttrib[index];
385b8e80941Smrg   assert(index < ARRAY_SIZE(vao->BufferBinding));
386b8e80941Smrg   struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[index];
387848b8605Smrg
388b8e80941Smrg   _mesa_set_vertex_format(&array->Format, size, type, GL_RGBA,
389b8e80941Smrg                           GL_FALSE, GL_FALSE, GL_FALSE);
390848b8605Smrg   array->Stride = 0;
391848b8605Smrg   array->Ptr = NULL;
392848b8605Smrg   array->RelativeOffset = 0;
393b8e80941Smrg   ASSERT_BITFIELD_SIZE(struct gl_array_attributes, BufferBindingIndex,
394b8e80941Smrg                        VERT_ATTRIB_MAX - 1);
395b8e80941Smrg   array->BufferBindingIndex = index;
396848b8605Smrg
397848b8605Smrg   binding->Offset = 0;
398b8e80941Smrg   binding->Stride = array->Format._ElementSize;
399848b8605Smrg   binding->BufferObj = NULL;
400b8e80941Smrg   binding->_BoundArrays = BITFIELD_BIT(index);
401848b8605Smrg
402848b8605Smrg   /* Vertex array buffers */
403848b8605Smrg   _mesa_reference_buffer_object(ctx, &binding->BufferObj,
404848b8605Smrg                                 ctx->Shared->NullBufferObj);
405848b8605Smrg}
406848b8605Smrg
407848b8605Smrg
408848b8605Smrg/**
409848b8605Smrg * Initialize a gl_vertex_array_object's arrays.
410848b8605Smrg */
411848b8605Smrgvoid
412848b8605Smrg_mesa_initialize_vao(struct gl_context *ctx,
413b8e80941Smrg                     struct gl_vertex_array_object *vao,
414848b8605Smrg                     GLuint name)
415848b8605Smrg{
416848b8605Smrg   GLuint i;
417848b8605Smrg
418b8e80941Smrg   vao->Name = name;
419848b8605Smrg
420b8e80941Smrg   vao->RefCount = 1;
421b8e80941Smrg   vao->SharedAndImmutable = false;
422848b8605Smrg
423848b8605Smrg   /* Init the individual arrays */
424b8e80941Smrg   for (i = 0; i < ARRAY_SIZE(vao->VertexAttrib); i++) {
425848b8605Smrg      switch (i) {
426848b8605Smrg      case VERT_ATTRIB_NORMAL:
427b8e80941Smrg         init_array(ctx, vao, VERT_ATTRIB_NORMAL, 3, GL_FLOAT);
428848b8605Smrg         break;
429848b8605Smrg      case VERT_ATTRIB_COLOR1:
430b8e80941Smrg         init_array(ctx, vao, VERT_ATTRIB_COLOR1, 3, GL_FLOAT);
431848b8605Smrg         break;
432848b8605Smrg      case VERT_ATTRIB_FOG:
433b8e80941Smrg         init_array(ctx, vao, VERT_ATTRIB_FOG, 1, GL_FLOAT);
434848b8605Smrg         break;
435848b8605Smrg      case VERT_ATTRIB_COLOR_INDEX:
436b8e80941Smrg         init_array(ctx, vao, VERT_ATTRIB_COLOR_INDEX, 1, GL_FLOAT);
437848b8605Smrg         break;
438848b8605Smrg      case VERT_ATTRIB_EDGEFLAG:
439b8e80941Smrg         init_array(ctx, vao, VERT_ATTRIB_EDGEFLAG, 1, GL_UNSIGNED_BYTE);
440848b8605Smrg         break;
441848b8605Smrg      case VERT_ATTRIB_POINT_SIZE:
442b8e80941Smrg         init_array(ctx, vao, VERT_ATTRIB_POINT_SIZE, 1, GL_FLOAT);
443848b8605Smrg         break;
444848b8605Smrg      default:
445b8e80941Smrg         init_array(ctx, vao, i, 4, GL_FLOAT);
446848b8605Smrg         break;
447848b8605Smrg      }
448848b8605Smrg   }
449848b8605Smrg
450b8e80941Smrg   vao->_AttributeMapMode = ATTRIBUTE_MAP_MODE_IDENTITY;
451b8e80941Smrg
452b8e80941Smrg   _mesa_reference_buffer_object(ctx, &vao->IndexBufferObj,
453848b8605Smrg                                 ctx->Shared->NullBufferObj);
454848b8605Smrg}
455848b8605Smrg
456848b8605Smrg
457848b8605Smrg/**
458b8e80941Smrg * Compute the offset range for the provided binding.
459b8e80941Smrg *
460b8e80941Smrg * This is a helper function for the below.
461848b8605Smrg */
462848b8605Smrgstatic void
463b8e80941Smrgcompute_vbo_offset_range(const struct gl_vertex_array_object *vao,
464b8e80941Smrg                         const struct gl_vertex_buffer_binding *binding,
465b8e80941Smrg                         GLsizeiptr* min, GLsizeiptr* max)
466848b8605Smrg{
467b8e80941Smrg   /* The function is meant to work on VBO bindings */
468b8e80941Smrg   assert(_mesa_is_bufferobj(binding->BufferObj));
469b8e80941Smrg
470b8e80941Smrg   /* Start with an inverted range of relative offsets. */
471b8e80941Smrg   GLuint min_offset = ~(GLuint)0;
472b8e80941Smrg   GLuint max_offset = 0;
473b8e80941Smrg
474b8e80941Smrg   /* We work on the unmapped originaly VAO array entries. */
475b8e80941Smrg   GLbitfield mask = vao->Enabled & binding->_BoundArrays;
476b8e80941Smrg   /* The binding should be active somehow, not to return inverted ranges */
477b8e80941Smrg   assert(mask);
478b8e80941Smrg   while (mask) {
479b8e80941Smrg      const int i = u_bit_scan(&mask);
480b8e80941Smrg      const GLuint off = vao->VertexAttrib[i].RelativeOffset;
481b8e80941Smrg      min_offset = MIN2(off, min_offset);
482b8e80941Smrg      max_offset = MAX2(off, max_offset);
483848b8605Smrg   }
484b8e80941Smrg
485b8e80941Smrg   *min = binding->Offset + (GLsizeiptr)min_offset;
486b8e80941Smrg   *max = binding->Offset + (GLsizeiptr)max_offset;
487848b8605Smrg}
488848b8605Smrg
489848b8605Smrg
490848b8605Smrg/**
491b8e80941Smrg * Update the unique binding and pos/generic0 map tracking in the vao.
492b8e80941Smrg *
493b8e80941Smrg * The idea is to build up information in the vao so that a consuming
494b8e80941Smrg * backend can execute the following to set up buffer and vertex element
495b8e80941Smrg * information:
496b8e80941Smrg *
497b8e80941Smrg * const GLbitfield inputs_read = VERT_BIT_ALL; // backend vp inputs
498b8e80941Smrg *
499b8e80941Smrg * // Attribute data is in a VBO.
500b8e80941Smrg * GLbitfield vbomask = inputs_read & _mesa_draw_vbo_array_bits(ctx);
501b8e80941Smrg * while (vbomask) {
502b8e80941Smrg *    // The attribute index to start pulling a binding
503b8e80941Smrg *    const gl_vert_attrib i = ffs(vbomask) - 1;
504b8e80941Smrg *    const struct gl_vertex_buffer_binding *const binding
505b8e80941Smrg *       = _mesa_draw_buffer_binding(vao, i);
506b8e80941Smrg *
507b8e80941Smrg *    <insert code to handle the vertex buffer object at binding>
508b8e80941Smrg *
509b8e80941Smrg *    const GLbitfield boundmask = _mesa_draw_bound_attrib_bits(binding);
510b8e80941Smrg *    GLbitfield attrmask = vbomask & boundmask;
511b8e80941Smrg *    assert(attrmask);
512b8e80941Smrg *    // Walk attributes belonging to the binding
513b8e80941Smrg *    while (attrmask) {
514b8e80941Smrg *       const gl_vert_attrib attr = u_bit_scan(&attrmask);
515b8e80941Smrg *       const struct gl_array_attributes *const attrib
516b8e80941Smrg *          = _mesa_draw_array_attrib(vao, attr);
517b8e80941Smrg *
518b8e80941Smrg *       <insert code to handle the vertex element refering to the binding>
519b8e80941Smrg *    }
520b8e80941Smrg *    vbomask &= ~boundmask;
521b8e80941Smrg * }
522b8e80941Smrg *
523b8e80941Smrg * // Process user space buffers
524b8e80941Smrg * GLbitfield usermask = inputs_read & _mesa_draw_user_array_bits(ctx);
525b8e80941Smrg * while (usermask) {
526b8e80941Smrg *    // The attribute index to start pulling a binding
527b8e80941Smrg *    const gl_vert_attrib i = ffs(usermask) - 1;
528b8e80941Smrg *    const struct gl_vertex_buffer_binding *const binding
529b8e80941Smrg *       = _mesa_draw_buffer_binding(vao, i);
530b8e80941Smrg *
531b8e80941Smrg *    <insert code to handle a set of interleaved user space arrays at binding>
532b8e80941Smrg *
533b8e80941Smrg *    const GLbitfield boundmask = _mesa_draw_bound_attrib_bits(binding);
534b8e80941Smrg *    GLbitfield attrmask = usermask & boundmask;
535b8e80941Smrg *    assert(attrmask);
536b8e80941Smrg *    // Walk interleaved attributes with a common stride and instance divisor
537b8e80941Smrg *    while (attrmask) {
538b8e80941Smrg *       const gl_vert_attrib attr = u_bit_scan(&attrmask);
539b8e80941Smrg *       const struct gl_array_attributes *const attrib
540b8e80941Smrg *          = _mesa_draw_array_attrib(vao, attr);
541b8e80941Smrg *
542b8e80941Smrg *       <insert code to handle non vbo vertex arrays>
543b8e80941Smrg *    }
544b8e80941Smrg *    usermask &= ~boundmask;
545b8e80941Smrg * }
546b8e80941Smrg *
547b8e80941Smrg * // Process values that should have better been uniforms in the application
548b8e80941Smrg * GLbitfield curmask = inputs_read & _mesa_draw_current_bits(ctx);
549b8e80941Smrg * while (curmask) {
550b8e80941Smrg *    const gl_vert_attrib attr = u_bit_scan(&curmask);
551b8e80941Smrg *    const struct gl_array_attributes *const attrib
552b8e80941Smrg *       = _mesa_draw_current_attrib(ctx, attr);
553b8e80941Smrg *
554b8e80941Smrg *    <insert code to handle current values>
555b8e80941Smrg * }
556b8e80941Smrg *
557b8e80941Smrg *
558b8e80941Smrg * Note that the scan below must not incoporate any context state.
559b8e80941Smrg * The rationale is that once a VAO is finalized it should not
560b8e80941Smrg * be touched anymore. That means, do not incorporate the
561b8e80941Smrg * gl_context::Array._DrawVAOEnabledAttribs bitmask into this scan.
562b8e80941Smrg * A backend driver may further reduce the handled vertex processing
563b8e80941Smrg * inputs based on their vertex shader inputs. But scanning for
564b8e80941Smrg * collapsable binding points to reduce relocs is done based on the
565b8e80941Smrg * enabled arrays.
566b8e80941Smrg * Also VAOs may be shared between contexts due to their use in dlists
567b8e80941Smrg * thus no context state should bleed into the VAO.
568848b8605Smrg */
569b8e80941Smrgvoid
570b8e80941Smrg_mesa_update_vao_derived_arrays(struct gl_context *ctx,
571b8e80941Smrg                                struct gl_vertex_array_object *vao)
572848b8605Smrg{
573b8e80941Smrg   /* Make sure we do not run into problems with shared objects */
574b8e80941Smrg   assert(!vao->SharedAndImmutable || vao->NewArrays == 0);
575b8e80941Smrg
576b8e80941Smrg   /* Limit used for common binding scanning below. */
577b8e80941Smrg   const GLsizeiptr MaxRelativeOffset =
578b8e80941Smrg      ctx->Const.MaxVertexAttribRelativeOffset;
579b8e80941Smrg
580b8e80941Smrg   /* The gl_vertex_array_object::_AttributeMapMode denotes the way
581b8e80941Smrg    * VERT_ATTRIB_{POS,GENERIC0} mapping is done.
582b8e80941Smrg    *
583b8e80941Smrg    * This mapping is used to map between the OpenGL api visible
584b8e80941Smrg    * VERT_ATTRIB_* arrays to mesa driver arrayinputs or shader inputs.
585b8e80941Smrg    * The mapping only depends on the enabled bits of the
586b8e80941Smrg    * VERT_ATTRIB_{POS,GENERIC0} arrays and is tracked in the VAO.
587b8e80941Smrg    *
588b8e80941Smrg    * This map needs to be applied when finally translating to the bitmasks
589b8e80941Smrg    * as consumed by the driver backends. The duplicate scanning is here
590b8e80941Smrg    * can as well be done in the OpenGL API numbering without this map.
591b8e80941Smrg    */
592b8e80941Smrg   const gl_attribute_map_mode mode = vao->_AttributeMapMode;
593b8e80941Smrg   /* Enabled array bits. */
594b8e80941Smrg   const GLbitfield enabled = vao->Enabled;
595b8e80941Smrg   /* VBO array bits. */
596b8e80941Smrg   const GLbitfield vbos = vao->VertexAttribBufferMask;
597b8e80941Smrg
598b8e80941Smrg   /* Compute and store effectively enabled and mapped vbo arrays */
599b8e80941Smrg   vao->_EffEnabledVBO = _mesa_vao_enable_to_vp_inputs(mode, enabled & vbos);
600b8e80941Smrg   /* Walk those enabled arrays that have a real vbo attached */
601b8e80941Smrg   GLbitfield mask = enabled;
602b8e80941Smrg   while (mask) {
603b8e80941Smrg      /* Do not use u_bit_scan as we can walk multiple attrib arrays at once */
604b8e80941Smrg      const int i = ffs(mask) - 1;
605b8e80941Smrg      /* The binding from the first to be processed attribute. */
606b8e80941Smrg      const GLuint bindex = vao->VertexAttrib[i].BufferBindingIndex;
607b8e80941Smrg      struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[bindex];
608b8e80941Smrg
609b8e80941Smrg      /* The scan goes different for user space arrays than vbos */
610b8e80941Smrg      if (_mesa_is_bufferobj(binding->BufferObj)) {
611b8e80941Smrg         /* The bound arrays. */
612b8e80941Smrg         const GLbitfield bound = enabled & binding->_BoundArrays;
613b8e80941Smrg
614b8e80941Smrg         /* Start this current effective binding with the actual bound arrays */
615b8e80941Smrg         GLbitfield eff_bound_arrays = bound;
616b8e80941Smrg
617b8e80941Smrg         /*
618b8e80941Smrg          * If there is nothing left to scan just update the effective binding
619b8e80941Smrg          * information. If the VAO is already only using a single binding point
620b8e80941Smrg          * we end up here. So the overhead of this scan for an application
621b8e80941Smrg          * carefully preparing the VAO for draw is low.
622b8e80941Smrg          */
623b8e80941Smrg
624b8e80941Smrg         GLbitfield scanmask = mask & vbos & ~bound;
625b8e80941Smrg         /* Is there something left to scan? */
626b8e80941Smrg         if (scanmask == 0) {
627b8e80941Smrg            /* Just update the back reference from the attrib to the binding and
628b8e80941Smrg             * the effective offset.
629b8e80941Smrg             */
630b8e80941Smrg            GLbitfield attrmask = eff_bound_arrays;
631b8e80941Smrg            while (attrmask) {
632b8e80941Smrg               const int j = u_bit_scan(&attrmask);
633b8e80941Smrg               struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j];
634b8e80941Smrg
635b8e80941Smrg               /* Update the index into the common binding point and offset */
636b8e80941Smrg               attrib2->_EffBufferBindingIndex = bindex;
637b8e80941Smrg               attrib2->_EffRelativeOffset = attrib2->RelativeOffset;
638b8e80941Smrg               assert(attrib2->_EffRelativeOffset <= MaxRelativeOffset);
639b8e80941Smrg            }
640b8e80941Smrg            /* Finally this is the set of effectively bound arrays with the
641b8e80941Smrg             * original binding offset.
642b8e80941Smrg             */
643b8e80941Smrg            binding->_EffOffset = binding->Offset;
644b8e80941Smrg            /* The bound arrays past the VERT_ATTRIB_{POS,GENERIC0} mapping. */
645b8e80941Smrg            binding->_EffBoundArrays =
646b8e80941Smrg               _mesa_vao_enable_to_vp_inputs(mode, eff_bound_arrays);
647b8e80941Smrg
648b8e80941Smrg         } else {
649b8e80941Smrg            /* In the VBO case, scan for attribute/binding
650b8e80941Smrg             * combinations with relative bindings in the range of
651b8e80941Smrg             * [0, ctx->Const.MaxVertexAttribRelativeOffset].
652b8e80941Smrg             * Note that this does also go beyond just interleaved arrays
653b8e80941Smrg             * as long as they use the same VBO, binding parameters and the
654b8e80941Smrg             * offsets stay within bounds that the backend still can handle.
655b8e80941Smrg             */
656b8e80941Smrg
657b8e80941Smrg            GLsizeiptr min_offset, max_offset;
658b8e80941Smrg            compute_vbo_offset_range(vao, binding, &min_offset, &max_offset);
659b8e80941Smrg            assert(max_offset <= min_offset + MaxRelativeOffset);
660b8e80941Smrg
661b8e80941Smrg            /* Now scan. */
662b8e80941Smrg            while (scanmask) {
663b8e80941Smrg               /* Do not use u_bit_scan as we can walk multiple
664b8e80941Smrg                * attrib arrays at once
665b8e80941Smrg                */
666b8e80941Smrg               const int j = ffs(scanmask) - 1;
667b8e80941Smrg               const struct gl_array_attributes *attrib2 =
668b8e80941Smrg                  &vao->VertexAttrib[j];
669b8e80941Smrg               const struct gl_vertex_buffer_binding *binding2 =
670b8e80941Smrg                  &vao->BufferBinding[attrib2->BufferBindingIndex];
671b8e80941Smrg
672b8e80941Smrg               /* Remove those attrib bits from the mask that are bound to the
673b8e80941Smrg                * same effective binding point.
674b8e80941Smrg                */
675b8e80941Smrg               const GLbitfield bound2 = enabled & binding2->_BoundArrays;
676b8e80941Smrg               scanmask &= ~bound2;
677b8e80941Smrg
678b8e80941Smrg               /* Check if we have an identical binding */
679b8e80941Smrg               if (binding->Stride != binding2->Stride)
680b8e80941Smrg                  continue;
681b8e80941Smrg               if (binding->InstanceDivisor != binding2->InstanceDivisor)
682b8e80941Smrg                  continue;
683b8e80941Smrg               if (binding->BufferObj != binding2->BufferObj)
684b8e80941Smrg                  continue;
685b8e80941Smrg               /* Check if we can fold both bindings into a common binding */
686b8e80941Smrg               GLsizeiptr min_offset2, max_offset2;
687b8e80941Smrg               compute_vbo_offset_range(vao, binding2,
688b8e80941Smrg                                        &min_offset2, &max_offset2);
689b8e80941Smrg               /* If the relative offset is within the limits ... */
690b8e80941Smrg               if (min_offset + MaxRelativeOffset < max_offset2)
691b8e80941Smrg                  continue;
692b8e80941Smrg               if (min_offset2 + MaxRelativeOffset < max_offset)
693b8e80941Smrg                  continue;
694b8e80941Smrg               /* ... add this array to the effective binding */
695b8e80941Smrg               eff_bound_arrays |= bound2;
696b8e80941Smrg               min_offset = MIN2(min_offset, min_offset2);
697b8e80941Smrg               max_offset = MAX2(max_offset, max_offset2);
698b8e80941Smrg               assert(max_offset <= min_offset + MaxRelativeOffset);
699b8e80941Smrg            }
700b8e80941Smrg
701b8e80941Smrg            /* Update the back reference from the attrib to the binding */
702b8e80941Smrg            GLbitfield attrmask = eff_bound_arrays;
703b8e80941Smrg            while (attrmask) {
704b8e80941Smrg               const int j = u_bit_scan(&attrmask);
705b8e80941Smrg               struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j];
706b8e80941Smrg               const struct gl_vertex_buffer_binding *binding2 =
707b8e80941Smrg                  &vao->BufferBinding[attrib2->BufferBindingIndex];
708b8e80941Smrg
709b8e80941Smrg               /* Update the index into the common binding point and offset */
710b8e80941Smrg               attrib2->_EffBufferBindingIndex = bindex;
711b8e80941Smrg               attrib2->_EffRelativeOffset =
712b8e80941Smrg                  binding2->Offset + attrib2->RelativeOffset - min_offset;
713b8e80941Smrg               assert(attrib2->_EffRelativeOffset <= MaxRelativeOffset);
714b8e80941Smrg            }
715b8e80941Smrg            /* Finally this is the set of effectively bound arrays */
716b8e80941Smrg            binding->_EffOffset = min_offset;
717b8e80941Smrg            /* The bound arrays past the VERT_ATTRIB_{POS,GENERIC0} mapping. */
718b8e80941Smrg            binding->_EffBoundArrays =
719b8e80941Smrg               _mesa_vao_enable_to_vp_inputs(mode, eff_bound_arrays);
720b8e80941Smrg         }
721b8e80941Smrg
722b8e80941Smrg         /* Mark all the effective bound arrays as processed. */
723b8e80941Smrg         mask &= ~eff_bound_arrays;
724b8e80941Smrg
725b8e80941Smrg      } else {
726b8e80941Smrg         /* Scanning of common bindings for user space arrays.
727b8e80941Smrg          */
728b8e80941Smrg
729b8e80941Smrg         const struct gl_array_attributes *attrib = &vao->VertexAttrib[i];
730b8e80941Smrg         const GLbitfield bound = VERT_BIT(i);
731b8e80941Smrg
732b8e80941Smrg         /* Note that user space array pointers can only happen using a one
733b8e80941Smrg          * to one binding point to array mapping.
734b8e80941Smrg          * The OpenGL 4.x/ARB_vertex_attrib_binding api does not support
735b8e80941Smrg          * user space arrays collected at multiple binding points.
736b8e80941Smrg          * The only provider of user space interleaved arrays with a single
737b8e80941Smrg          * binding point is the mesa internal vbo module. But that one
738b8e80941Smrg          * provides a perfect interleaved set of arrays.
739b8e80941Smrg          *
740b8e80941Smrg          * If this would not be true we would potentially get attribute arrays
741b8e80941Smrg          * with user space pointers that may not lie within the
742b8e80941Smrg          * MaxRelativeOffset range but still attached to a single binding.
743b8e80941Smrg          * Then we would need to store the effective attribute and binding
744b8e80941Smrg          * grouping information in a seperate array beside
745b8e80941Smrg          * gl_array_attributes/gl_vertex_buffer_binding.
746b8e80941Smrg          */
747b8e80941Smrg         assert(util_bitcount(binding->_BoundArrays & vao->Enabled) == 1
748b8e80941Smrg                || (vao->Enabled & ~binding->_BoundArrays) == 0);
749b8e80941Smrg
750b8e80941Smrg         /* Start this current effective binding with the array */
751b8e80941Smrg         GLbitfield eff_bound_arrays = bound;
752b8e80941Smrg
753b8e80941Smrg         const GLubyte *ptr = attrib->Ptr;
754b8e80941Smrg         unsigned vertex_end = attrib->Format._ElementSize;
755b8e80941Smrg
756b8e80941Smrg         /* Walk other user space arrays and see which are interleaved
757b8e80941Smrg          * using the same binding parameters.
758b8e80941Smrg          */
759b8e80941Smrg         GLbitfield scanmask = mask & ~vbos & ~bound;
760b8e80941Smrg         while (scanmask) {
761b8e80941Smrg            const int j = u_bit_scan(&scanmask);
762b8e80941Smrg            const struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j];
763b8e80941Smrg            const struct gl_vertex_buffer_binding *binding2 =
764b8e80941Smrg               &vao->BufferBinding[attrib2->BufferBindingIndex];
765b8e80941Smrg
766b8e80941Smrg            /* See the comment at the same assert above. */
767b8e80941Smrg            assert(util_bitcount(binding2->_BoundArrays & vao->Enabled) == 1
768b8e80941Smrg                   || (vao->Enabled & ~binding->_BoundArrays) == 0);
769b8e80941Smrg
770b8e80941Smrg            /* Check if we have an identical binding */
771b8e80941Smrg            if (binding->Stride != binding2->Stride)
772b8e80941Smrg               continue;
773b8e80941Smrg            if (binding->InstanceDivisor != binding2->InstanceDivisor)
774b8e80941Smrg               continue;
775b8e80941Smrg            if (ptr <= attrib2->Ptr) {
776b8e80941Smrg               if (ptr + binding->Stride < attrib2->Ptr +
777b8e80941Smrg                   attrib2->Format._ElementSize)
778b8e80941Smrg                  continue;
779b8e80941Smrg               unsigned end = attrib2->Ptr + attrib2->Format._ElementSize - ptr;
780b8e80941Smrg               vertex_end = MAX2(vertex_end, end);
781b8e80941Smrg            } else {
782b8e80941Smrg               if (attrib2->Ptr + binding->Stride < ptr + vertex_end)
783b8e80941Smrg                  continue;
784b8e80941Smrg               vertex_end += (GLsizei)(ptr - attrib2->Ptr);
785b8e80941Smrg               ptr = attrib2->Ptr;
786b8e80941Smrg            }
787b8e80941Smrg
788b8e80941Smrg            /* User space buffer object */
789b8e80941Smrg            assert(!_mesa_is_bufferobj(binding2->BufferObj));
790b8e80941Smrg
791b8e80941Smrg            eff_bound_arrays |= VERT_BIT(j);
792b8e80941Smrg         }
793b8e80941Smrg
794b8e80941Smrg         /* Update the back reference from the attrib to the binding */
795b8e80941Smrg         GLbitfield attrmask = eff_bound_arrays;
796b8e80941Smrg         while (attrmask) {
797b8e80941Smrg            const int j = u_bit_scan(&attrmask);
798b8e80941Smrg            struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j];
799b8e80941Smrg
800b8e80941Smrg            /* Update the index into the common binding point and the offset */
801b8e80941Smrg            attrib2->_EffBufferBindingIndex = bindex;
802b8e80941Smrg            attrib2->_EffRelativeOffset = attrib2->Ptr - ptr;
803b8e80941Smrg            assert(attrib2->_EffRelativeOffset <= binding->Stride);
804b8e80941Smrg         }
805b8e80941Smrg         /* Finally this is the set of effectively bound arrays */
806b8e80941Smrg         binding->_EffOffset = (GLintptr)ptr;
807b8e80941Smrg         /* The bound arrays past the VERT_ATTRIB_{POS,GENERIC0} mapping. */
808b8e80941Smrg         binding->_EffBoundArrays =
809b8e80941Smrg            _mesa_vao_enable_to_vp_inputs(mode, eff_bound_arrays);
810b8e80941Smrg
811b8e80941Smrg         /* Mark all the effective bound arrays as processed. */
812b8e80941Smrg         mask &= ~eff_bound_arrays;
813b8e80941Smrg      }
814848b8605Smrg   }
815b8e80941Smrg
816b8e80941Smrg#ifndef NDEBUG
817b8e80941Smrg   /* Make sure the above code works as expected. */
818b8e80941Smrg   for (gl_vert_attrib attr = 0; attr < VERT_ATTRIB_MAX; ++attr) {
819b8e80941Smrg      /* Query the original api defined attrib/binding information ... */
820b8e80941Smrg      const unsigned char *const map =_mesa_vao_attribute_map[mode];
821b8e80941Smrg      if (vao->Enabled & VERT_BIT(map[attr])) {
822b8e80941Smrg         const struct gl_array_attributes *attrib =
823b8e80941Smrg            &vao->VertexAttrib[map[attr]];
824b8e80941Smrg         const struct gl_vertex_buffer_binding *binding =
825b8e80941Smrg            &vao->BufferBinding[attrib->BufferBindingIndex];
826b8e80941Smrg         /* ... and compare that with the computed attrib/binding */
827b8e80941Smrg         const struct gl_vertex_buffer_binding *binding2 =
828b8e80941Smrg            &vao->BufferBinding[attrib->_EffBufferBindingIndex];
829b8e80941Smrg         assert(binding->Stride == binding2->Stride);
830b8e80941Smrg         assert(binding->InstanceDivisor == binding2->InstanceDivisor);
831b8e80941Smrg         assert(binding->BufferObj == binding2->BufferObj);
832b8e80941Smrg         if (_mesa_is_bufferobj(binding->BufferObj)) {
833b8e80941Smrg            assert(attrib->_EffRelativeOffset <= MaxRelativeOffset);
834b8e80941Smrg            assert(binding->Offset + attrib->RelativeOffset ==
835b8e80941Smrg                   binding2->_EffOffset + attrib->_EffRelativeOffset);
836b8e80941Smrg         } else {
837b8e80941Smrg            assert(attrib->_EffRelativeOffset < binding->Stride);
838b8e80941Smrg            assert((GLintptr)attrib->Ptr ==
839b8e80941Smrg                   binding2->_EffOffset + attrib->_EffRelativeOffset);
840b8e80941Smrg         }
841b8e80941Smrg      }
842b8e80941Smrg   }
843b8e80941Smrg#endif
844b8e80941Smrg}
845b8e80941Smrg
846b8e80941Smrg
847b8e80941Smrgvoid
848b8e80941Smrg_mesa_set_vao_immutable(struct gl_context *ctx,
849b8e80941Smrg                        struct gl_vertex_array_object *vao)
850b8e80941Smrg{
851b8e80941Smrg   _mesa_update_vao_derived_arrays(ctx, vao);
852b8e80941Smrg   vao->NewArrays = 0;
853b8e80941Smrg   vao->SharedAndImmutable = true;
854848b8605Smrg}
855848b8605Smrg
856848b8605Smrg
857b8e80941Smrgbool
858b8e80941Smrg_mesa_all_varyings_in_vbos(const struct gl_vertex_array_object *vao)
859b8e80941Smrg{
860b8e80941Smrg   /* Walk those enabled arrays that have the default vbo attached */
861b8e80941Smrg   GLbitfield mask = vao->Enabled & ~vao->VertexAttribBufferMask;
862848b8605Smrg
863b8e80941Smrg   while (mask) {
864b8e80941Smrg      /* Do not use u_bit_scan64 as we can walk multiple
865b8e80941Smrg       * attrib arrays at once
866b8e80941Smrg       */
867b8e80941Smrg      const int i = ffs(mask) - 1;
868b8e80941Smrg      const struct gl_array_attributes *attrib_array =
869b8e80941Smrg         &vao->VertexAttrib[i];
870b8e80941Smrg      const struct gl_vertex_buffer_binding *buffer_binding =
871b8e80941Smrg         &vao->BufferBinding[attrib_array->BufferBindingIndex];
872b8e80941Smrg
873b8e80941Smrg      /* We have already masked out vao->VertexAttribBufferMask  */
874b8e80941Smrg      assert(!_mesa_is_bufferobj(buffer_binding->BufferObj));
875b8e80941Smrg
876b8e80941Smrg      /* Bail out once we find the first non vbo with a non zero stride */
877b8e80941Smrg      if (buffer_binding->Stride != 0)
878b8e80941Smrg         return false;
879b8e80941Smrg
880b8e80941Smrg      /* Note that we cannot use the xor variant since the _BoundArray mask
881b8e80941Smrg       * may contain array attributes that are bound but not enabled.
882b8e80941Smrg       */
883b8e80941Smrg      mask &= ~buffer_binding->_BoundArrays;
884b8e80941Smrg   }
885b8e80941Smrg
886b8e80941Smrg   return true;
887b8e80941Smrg}
888b8e80941Smrg
889b8e80941Smrgbool
890b8e80941Smrg_mesa_all_buffers_are_unmapped(const struct gl_vertex_array_object *vao)
891848b8605Smrg{
892b8e80941Smrg   /* Walk the enabled arrays that have a vbo attached */
893b8e80941Smrg   GLbitfield mask = vao->Enabled & vao->VertexAttribBufferMask;
894b8e80941Smrg
895b8e80941Smrg   while (mask) {
896b8e80941Smrg      const int i = ffs(mask) - 1;
897b8e80941Smrg      const struct gl_array_attributes *attrib_array =
898b8e80941Smrg         &vao->VertexAttrib[i];
899b8e80941Smrg      const struct gl_vertex_buffer_binding *buffer_binding =
900b8e80941Smrg         &vao->BufferBinding[attrib_array->BufferBindingIndex];
901848b8605Smrg
902b8e80941Smrg      /* We have already masked with vao->VertexAttribBufferMask  */
903b8e80941Smrg      assert(_mesa_is_bufferobj(buffer_binding->BufferObj));
904848b8605Smrg
905b8e80941Smrg      /* Bail out once we find the first disallowed mapping */
906b8e80941Smrg      if (_mesa_check_disallowed_mapping(buffer_binding->BufferObj))
907b8e80941Smrg         return false;
908b8e80941Smrg
909b8e80941Smrg      /* We have handled everything that is bound to this buffer_binding. */
910b8e80941Smrg      mask &= ~buffer_binding->_BoundArrays;
911848b8605Smrg   }
912848b8605Smrg
913b8e80941Smrg   return true;
914848b8605Smrg}
915848b8605Smrg
916848b8605Smrg
917848b8605Smrg/**
918b8e80941Smrg * Map buffer objects used in attribute arrays.
919848b8605Smrg */
920848b8605Smrgvoid
921b8e80941Smrg_mesa_vao_map_arrays(struct gl_context *ctx, struct gl_vertex_array_object *vao,
922b8e80941Smrg                     GLbitfield access)
923848b8605Smrg{
924b8e80941Smrg   GLbitfield mask = vao->Enabled & vao->VertexAttribBufferMask;
925b8e80941Smrg   while (mask) {
926b8e80941Smrg      /* Do not use u_bit_scan as we can walk multiple attrib arrays at once */
927b8e80941Smrg      const gl_vert_attrib attr = ffs(mask) - 1;
928b8e80941Smrg      const GLubyte bindex = vao->VertexAttrib[attr].BufferBindingIndex;
929b8e80941Smrg      struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[bindex];
930b8e80941Smrg      mask &= ~binding->_BoundArrays;
931b8e80941Smrg
932b8e80941Smrg      struct gl_buffer_object *bo = binding->BufferObj;
933b8e80941Smrg      assert(_mesa_is_bufferobj(bo));
934b8e80941Smrg      if (_mesa_bufferobj_mapped(bo, MAP_INTERNAL))
935b8e80941Smrg         continue;
936b8e80941Smrg
937b8e80941Smrg      ctx->Driver.MapBufferRange(ctx, 0, bo->Size, access, bo, MAP_INTERNAL);
938848b8605Smrg   }
939848b8605Smrg}
940848b8605Smrg
941848b8605Smrg
942848b8605Smrg/**
943b8e80941Smrg * Map buffer objects used in the vao, attribute arrays and index buffer.
944848b8605Smrg */
945848b8605Smrgvoid
946b8e80941Smrg_mesa_vao_map(struct gl_context *ctx, struct gl_vertex_array_object *vao,
947b8e80941Smrg              GLbitfield access)
948848b8605Smrg{
949b8e80941Smrg   struct gl_buffer_object *bo = vao->IndexBufferObj;
950848b8605Smrg
951b8e80941Smrg   /* map the index buffer, if there is one, and not already mapped */
952b8e80941Smrg   if (_mesa_is_bufferobj(bo) && !_mesa_bufferobj_mapped(bo, MAP_INTERNAL))
953b8e80941Smrg      ctx->Driver.MapBufferRange(ctx, 0, bo->Size, access, bo, MAP_INTERNAL);
954848b8605Smrg
955b8e80941Smrg   _mesa_vao_map_arrays(ctx, vao, access);
956b8e80941Smrg}
957848b8605Smrg
958848b8605Smrg
959b8e80941Smrg/**
960b8e80941Smrg * Unmap buffer objects used in attribute arrays.
961b8e80941Smrg */
962b8e80941Smrgvoid
963b8e80941Smrg_mesa_vao_unmap_arrays(struct gl_context *ctx,
964b8e80941Smrg                       struct gl_vertex_array_object *vao)
965b8e80941Smrg{
966b8e80941Smrg   GLbitfield mask = vao->Enabled & vao->VertexAttribBufferMask;
967b8e80941Smrg   while (mask) {
968b8e80941Smrg      /* Do not use u_bit_scan as we can walk multiple attrib arrays at once */
969b8e80941Smrg      const gl_vert_attrib attr = ffs(mask) - 1;
970b8e80941Smrg      const GLubyte bindex = vao->VertexAttrib[attr].BufferBindingIndex;
971b8e80941Smrg      struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[bindex];
972b8e80941Smrg      mask &= ~binding->_BoundArrays;
973b8e80941Smrg
974b8e80941Smrg      struct gl_buffer_object *bo = binding->BufferObj;
975b8e80941Smrg      assert(_mesa_is_bufferobj(bo));
976b8e80941Smrg      if (!_mesa_bufferobj_mapped(bo, MAP_INTERNAL))
977b8e80941Smrg         continue;
978b8e80941Smrg
979b8e80941Smrg      ctx->Driver.UnmapBuffer(ctx, bo, MAP_INTERNAL);
980848b8605Smrg   }
981848b8605Smrg}
982848b8605Smrg
983848b8605Smrg
984b8e80941Smrg/**
985b8e80941Smrg * Unmap buffer objects used in the vao, attribute arrays and index buffer.
986b8e80941Smrg */
987b8e80941Smrgvoid
988b8e80941Smrg_mesa_vao_unmap(struct gl_context *ctx, struct gl_vertex_array_object *vao)
989b8e80941Smrg{
990b8e80941Smrg   struct gl_buffer_object *bo = vao->IndexBufferObj;
991b8e80941Smrg
992b8e80941Smrg   /* unmap the index buffer, if there is one, and still mapped */
993b8e80941Smrg   if (_mesa_is_bufferobj(bo) && _mesa_bufferobj_mapped(bo, MAP_INTERNAL))
994b8e80941Smrg      ctx->Driver.UnmapBuffer(ctx, bo, MAP_INTERNAL);
995b8e80941Smrg
996b8e80941Smrg   _mesa_vao_unmap_arrays(ctx, vao);
997b8e80941Smrg}
998b8e80941Smrg
999b8e80941Smrg
1000848b8605Smrg/**********************************************************************/
1001848b8605Smrg/* API Functions                                                      */
1002848b8605Smrg/**********************************************************************/
1003848b8605Smrg
1004848b8605Smrg
1005848b8605Smrg/**
1006b8e80941Smrg * ARB version of glBindVertexArray()
1007848b8605Smrg */
1008b8e80941Smrgstatic ALWAYS_INLINE void
1009b8e80941Smrgbind_vertex_array(struct gl_context *ctx, GLuint id, bool no_error)
1010848b8605Smrg{
1011b8e80941Smrg   struct gl_vertex_array_object *const oldObj = ctx->Array.VAO;
1012848b8605Smrg   struct gl_vertex_array_object *newObj = NULL;
1013848b8605Smrg
1014b8e80941Smrg   assert(oldObj != NULL);
1015848b8605Smrg
1016b8e80941Smrg   if (oldObj->Name == id)
1017848b8605Smrg      return;   /* rebinding the same array object- no change */
1018848b8605Smrg
1019848b8605Smrg   /*
1020848b8605Smrg    * Get pointer to new array object (newObj)
1021848b8605Smrg    */
1022848b8605Smrg   if (id == 0) {
1023848b8605Smrg      /* The spec says there is no array object named 0, but we use
1024848b8605Smrg       * one internally because it simplifies things.
1025848b8605Smrg       */
1026848b8605Smrg      newObj = ctx->Array.DefaultVAO;
1027848b8605Smrg   }
1028848b8605Smrg   else {
1029848b8605Smrg      /* non-default array object */
1030848b8605Smrg      newObj = _mesa_lookup_vao(ctx, id);
1031b8e80941Smrg      if (!no_error && !newObj) {
1032b8e80941Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
1033b8e80941Smrg                     "glBindVertexArray(non-gen name)");
1034b8e80941Smrg         return;
1035848b8605Smrg      }
1036848b8605Smrg
1037b8e80941Smrg      newObj->EverBound = GL_TRUE;
1038848b8605Smrg   }
1039848b8605Smrg
1040b8e80941Smrg   /* The _DrawArrays pointer is pointing at the VAO being unbound and
1041b8e80941Smrg    * that VAO may be in the process of being deleted. If it's not going
1042b8e80941Smrg    * to be deleted, this will have no effect, because the pointer needs
1043b8e80941Smrg    * to be updated by the VBO module anyway.
1044b8e80941Smrg    *
1045b8e80941Smrg    * Before the VBO module can update the pointer, we have to set it
1046b8e80941Smrg    * to NULL for drivers not to set up arrays which are not bound,
1047b8e80941Smrg    * or to prevent a crash if the VAO being unbound is going to be
1048b8e80941Smrg    * deleted.
1049b8e80941Smrg    */
1050b8e80941Smrg   _mesa_set_draw_vao(ctx, ctx->Array._EmptyVAO, 0);
1051848b8605Smrg
1052848b8605Smrg   _mesa_reference_vao(ctx, &ctx->Array.VAO, newObj);
1053848b8605Smrg}
1054848b8605Smrg
1055848b8605Smrg
1056848b8605Smrgvoid GLAPIENTRY
1057b8e80941Smrg_mesa_BindVertexArray_no_error(GLuint id)
1058848b8605Smrg{
1059848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
1060b8e80941Smrg   bind_vertex_array(ctx, id, true);
1061848b8605Smrg}
1062848b8605Smrg
1063848b8605Smrg
1064848b8605Smrgvoid GLAPIENTRY
1065b8e80941Smrg_mesa_BindVertexArray(GLuint id)
1066848b8605Smrg{
1067848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
1068b8e80941Smrg   bind_vertex_array(ctx, id, false);
1069848b8605Smrg}
1070848b8605Smrg
1071848b8605Smrg
1072848b8605Smrg/**
1073848b8605Smrg * Delete a set of array objects.
1074848b8605Smrg *
1075848b8605Smrg * \param n      Number of array objects to delete.
1076848b8605Smrg * \param ids    Array of \c n array object IDs.
1077848b8605Smrg */
1078b8e80941Smrgstatic void
1079b8e80941Smrgdelete_vertex_arrays(struct gl_context *ctx, GLsizei n, const GLuint *ids)
1080848b8605Smrg{
1081848b8605Smrg   GLsizei i;
1082848b8605Smrg
1083848b8605Smrg   for (i = 0; i < n; i++) {
1084b8e80941Smrg      /* IDs equal to 0 should be silently ignored. */
1085b8e80941Smrg      if (!ids[i])
1086b8e80941Smrg         continue;
1087b8e80941Smrg
1088848b8605Smrg      struct gl_vertex_array_object *obj = _mesa_lookup_vao(ctx, ids[i]);
1089848b8605Smrg
1090b8e80941Smrg      if (obj) {
1091b8e80941Smrg         assert(obj->Name == ids[i]);
1092848b8605Smrg
1093b8e80941Smrg         /* If the array object is currently bound, the spec says "the binding
1094b8e80941Smrg          * for that object reverts to zero and the default vertex array
1095b8e80941Smrg          * becomes current."
1096b8e80941Smrg          */
1097b8e80941Smrg         if (obj == ctx->Array.VAO)
1098b8e80941Smrg            _mesa_BindVertexArray_no_error(0);
1099b8e80941Smrg
1100b8e80941Smrg         /* The ID is immediately freed for re-use */
1101b8e80941Smrg         _mesa_HashRemoveLocked(ctx->Array.Objects, obj->Name);
1102848b8605Smrg
1103b8e80941Smrg         if (ctx->Array.LastLookedUpVAO == obj)
1104b8e80941Smrg            _mesa_reference_vao(ctx, &ctx->Array.LastLookedUpVAO, NULL);
1105b8e80941Smrg         if (ctx->Array._DrawVAO == obj)
1106b8e80941Smrg            _mesa_set_draw_vao(ctx, ctx->Array._EmptyVAO, 0);
1107848b8605Smrg
1108848b8605Smrg         /* Unreference the array object.
1109848b8605Smrg          * If refcount hits zero, the object will be deleted.
1110848b8605Smrg          */
1111848b8605Smrg         _mesa_reference_vao(ctx, &obj, NULL);
1112848b8605Smrg      }
1113848b8605Smrg   }
1114848b8605Smrg}
1115848b8605Smrg
1116848b8605Smrg
1117b8e80941Smrgvoid GLAPIENTRY
1118b8e80941Smrg_mesa_DeleteVertexArrays_no_error(GLsizei n, const GLuint *ids)
1119b8e80941Smrg{
1120b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
1121b8e80941Smrg   delete_vertex_arrays(ctx, n, ids);
1122b8e80941Smrg}
1123b8e80941Smrg
1124b8e80941Smrg
1125b8e80941Smrgvoid GLAPIENTRY
1126b8e80941Smrg_mesa_DeleteVertexArrays(GLsizei n, const GLuint *ids)
1127b8e80941Smrg{
1128b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
1129b8e80941Smrg
1130b8e80941Smrg   if (n < 0) {
1131b8e80941Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteVertexArray(n)");
1132b8e80941Smrg      return;
1133b8e80941Smrg   }
1134b8e80941Smrg
1135b8e80941Smrg   delete_vertex_arrays(ctx, n, ids);
1136b8e80941Smrg}
1137b8e80941Smrg
1138b8e80941Smrg
1139848b8605Smrg/**
1140848b8605Smrg * Generate a set of unique array object IDs and store them in \c arrays.
1141b8e80941Smrg * Helper for _mesa_GenVertexArrays() and _mesa_CreateVertexArrays()
1142b8e80941Smrg * below.
1143b8e80941Smrg *
1144848b8605Smrg * \param n       Number of IDs to generate.
1145848b8605Smrg * \param arrays  Array of \c n locations to store the IDs.
1146b8e80941Smrg * \param create  Indicates that the objects should also be created.
1147b8e80941Smrg * \param func    The name of the GL entry point.
1148848b8605Smrg */
1149848b8605Smrgstatic void
1150b8e80941Smrggen_vertex_arrays(struct gl_context *ctx, GLsizei n, GLuint *arrays,
1151b8e80941Smrg                  bool create, const char *func)
1152848b8605Smrg{
1153848b8605Smrg   GLuint first;
1154848b8605Smrg   GLint i;
1155848b8605Smrg
1156b8e80941Smrg   if (!arrays)
1157848b8605Smrg      return;
1158848b8605Smrg
1159848b8605Smrg   first = _mesa_HashFindFreeKeyBlock(ctx->Array.Objects, n);
1160848b8605Smrg
1161b8e80941Smrg   /* For the sake of simplicity we create the array objects in both
1162b8e80941Smrg    * the Gen* and Create* cases.  The only difference is the value of
1163b8e80941Smrg    * EverBound, which is set to true in the Create* case.
1164b8e80941Smrg    */
1165848b8605Smrg   for (i = 0; i < n; i++) {
1166848b8605Smrg      struct gl_vertex_array_object *obj;
1167848b8605Smrg      GLuint name = first + i;
1168848b8605Smrg
1169b8e80941Smrg      obj = _mesa_new_vao(ctx, name);
1170848b8605Smrg      if (!obj) {
1171b8e80941Smrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
1172848b8605Smrg         return;
1173848b8605Smrg      }
1174b8e80941Smrg      obj->EverBound = create;
1175b8e80941Smrg      _mesa_HashInsertLocked(ctx->Array.Objects, obj->Name, obj);
1176848b8605Smrg      arrays[i] = first + i;
1177848b8605Smrg   }
1178848b8605Smrg}
1179848b8605Smrg
1180848b8605Smrg
1181b8e80941Smrgstatic void
1182b8e80941Smrggen_vertex_arrays_err(struct gl_context *ctx, GLsizei n, GLuint *arrays,
1183b8e80941Smrg                      bool create, const char *func)
1184b8e80941Smrg{
1185b8e80941Smrg   if (n < 0) {
1186b8e80941Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
1187b8e80941Smrg      return;
1188b8e80941Smrg   }
1189b8e80941Smrg
1190b8e80941Smrg   gen_vertex_arrays(ctx, n, arrays, create, func);
1191b8e80941Smrg}
1192b8e80941Smrg
1193b8e80941Smrg
1194848b8605Smrg/**
1195848b8605Smrg * ARB version of glGenVertexArrays()
1196848b8605Smrg * All arrays will be required to live in VBOs.
1197848b8605Smrg */
1198b8e80941Smrgvoid GLAPIENTRY
1199b8e80941Smrg_mesa_GenVertexArrays_no_error(GLsizei n, GLuint *arrays)
1200b8e80941Smrg{
1201b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
1202b8e80941Smrg   gen_vertex_arrays(ctx, n, arrays, false, "glGenVertexArrays");
1203b8e80941Smrg}
1204b8e80941Smrg
1205b8e80941Smrg
1206848b8605Smrgvoid GLAPIENTRY
1207848b8605Smrg_mesa_GenVertexArrays(GLsizei n, GLuint *arrays)
1208848b8605Smrg{
1209848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
1210b8e80941Smrg   gen_vertex_arrays_err(ctx, n, arrays, false, "glGenVertexArrays");
1211848b8605Smrg}
1212848b8605Smrg
1213848b8605Smrg
1214848b8605Smrg/**
1215b8e80941Smrg * ARB_direct_state_access
1216b8e80941Smrg * Generates ID's and creates the array objects.
1217848b8605Smrg */
1218848b8605Smrgvoid GLAPIENTRY
1219b8e80941Smrg_mesa_CreateVertexArrays_no_error(GLsizei n, GLuint *arrays)
1220b8e80941Smrg{
1221b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
1222b8e80941Smrg   gen_vertex_arrays(ctx, n, arrays, true, "glCreateVertexArrays");
1223b8e80941Smrg}
1224b8e80941Smrg
1225b8e80941Smrg
1226b8e80941Smrgvoid GLAPIENTRY
1227b8e80941Smrg_mesa_CreateVertexArrays(GLsizei n, GLuint *arrays)
1228848b8605Smrg{
1229848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
1230b8e80941Smrg   gen_vertex_arrays_err(ctx, n, arrays, true, "glCreateVertexArrays");
1231848b8605Smrg}
1232848b8605Smrg
1233848b8605Smrg
1234848b8605Smrg/**
1235848b8605Smrg * Determine if ID is the name of an array object.
1236848b8605Smrg *
1237848b8605Smrg * \param id  ID of the potential array object.
1238848b8605Smrg * \return  \c GL_TRUE if \c id is the name of a array object,
1239848b8605Smrg *          \c GL_FALSE otherwise.
1240848b8605Smrg */
1241848b8605SmrgGLboolean GLAPIENTRY
1242848b8605Smrg_mesa_IsVertexArray( GLuint id )
1243848b8605Smrg{
1244848b8605Smrg   struct gl_vertex_array_object * obj;
1245848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
1246848b8605Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1247848b8605Smrg
1248848b8605Smrg   obj = _mesa_lookup_vao(ctx, id);
1249848b8605Smrg
1250b8e80941Smrg   return obj != NULL && obj->EverBound;
1251b8e80941Smrg}
1252b8e80941Smrg
1253b8e80941Smrg
1254b8e80941Smrg/**
1255b8e80941Smrg * Sets the element array buffer binding of a vertex array object.
1256b8e80941Smrg *
1257b8e80941Smrg * This is the ARB_direct_state_access equivalent of
1258b8e80941Smrg * glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer).
1259b8e80941Smrg */
1260b8e80941Smrgstatic ALWAYS_INLINE void
1261b8e80941Smrgvertex_array_element_buffer(struct gl_context *ctx, GLuint vaobj, GLuint buffer,
1262b8e80941Smrg                            bool no_error)
1263b8e80941Smrg{
1264b8e80941Smrg   struct gl_vertex_array_object *vao;
1265b8e80941Smrg   struct gl_buffer_object *bufObj;
1266b8e80941Smrg
1267b8e80941Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
1268b8e80941Smrg
1269b8e80941Smrg   if (!no_error) {
1270b8e80941Smrg      /* The GL_ARB_direct_state_access specification says:
1271b8e80941Smrg       *
1272b8e80941Smrg       *    "An INVALID_OPERATION error is generated by
1273b8e80941Smrg       *     VertexArrayElementBuffer if <vaobj> is not [compatibility profile:
1274b8e80941Smrg       *     zero or] the name of an existing vertex array object."
1275b8e80941Smrg       */
1276b8e80941Smrg      vao =_mesa_lookup_vao_err(ctx, vaobj, "glVertexArrayElementBuffer");
1277b8e80941Smrg      if (!vao)
1278b8e80941Smrg         return;
1279b8e80941Smrg   } else {
1280b8e80941Smrg      vao = _mesa_lookup_vao(ctx, vaobj);
1281b8e80941Smrg   }
1282b8e80941Smrg
1283b8e80941Smrg   if (buffer != 0) {
1284b8e80941Smrg      if (!no_error) {
1285b8e80941Smrg         /* The GL_ARB_direct_state_access specification says:
1286b8e80941Smrg          *
1287b8e80941Smrg          *    "An INVALID_OPERATION error is generated if <buffer> is not zero
1288b8e80941Smrg          *     or the name of an existing buffer object."
1289b8e80941Smrg          */
1290b8e80941Smrg         bufObj = _mesa_lookup_bufferobj_err(ctx, buffer,
1291b8e80941Smrg                                             "glVertexArrayElementBuffer");
1292b8e80941Smrg      } else {
1293b8e80941Smrg         bufObj = _mesa_lookup_bufferobj(ctx, buffer);
1294b8e80941Smrg      }
1295b8e80941Smrg   } else {
1296b8e80941Smrg      bufObj = ctx->Shared->NullBufferObj;
1297b8e80941Smrg   }
1298b8e80941Smrg
1299b8e80941Smrg   if (bufObj) {
1300b8e80941Smrg      bufObj->UsageHistory |= USAGE_ELEMENT_ARRAY_BUFFER;
1301b8e80941Smrg      _mesa_reference_buffer_object(ctx, &vao->IndexBufferObj, bufObj);
1302b8e80941Smrg   }
1303b8e80941Smrg}
1304b8e80941Smrg
1305b8e80941Smrg
1306b8e80941Smrgvoid GLAPIENTRY
1307b8e80941Smrg_mesa_VertexArrayElementBuffer_no_error(GLuint vaobj, GLuint buffer)
1308b8e80941Smrg{
1309b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
1310b8e80941Smrg   vertex_array_element_buffer(ctx, vaobj, buffer, true);
1311b8e80941Smrg}
1312b8e80941Smrg
1313b8e80941Smrg
1314b8e80941Smrgvoid GLAPIENTRY
1315b8e80941Smrg_mesa_VertexArrayElementBuffer(GLuint vaobj, GLuint buffer)
1316b8e80941Smrg{
1317b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
1318b8e80941Smrg   vertex_array_element_buffer(ctx, vaobj, buffer, false);
1319b8e80941Smrg}
1320b8e80941Smrg
1321b8e80941Smrg
1322b8e80941Smrgvoid GLAPIENTRY
1323b8e80941Smrg_mesa_GetVertexArrayiv(GLuint vaobj, GLenum pname, GLint *param)
1324b8e80941Smrg{
1325b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
1326b8e80941Smrg   struct gl_vertex_array_object *vao;
1327b8e80941Smrg
1328b8e80941Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
1329b8e80941Smrg
1330b8e80941Smrg   /* The GL_ARB_direct_state_access specification says:
1331b8e80941Smrg    *
1332b8e80941Smrg    *   "An INVALID_OPERATION error is generated if <vaobj> is not
1333b8e80941Smrg    *    [compatibility profile: zero or] the name of an existing
1334b8e80941Smrg    *    vertex array object."
1335b8e80941Smrg    */
1336b8e80941Smrg   vao =_mesa_lookup_vao_err(ctx, vaobj, "glGetVertexArrayiv");
1337b8e80941Smrg   if (!vao)
1338b8e80941Smrg      return;
1339b8e80941Smrg
1340b8e80941Smrg   /* The GL_ARB_direct_state_access specification says:
1341b8e80941Smrg    *
1342b8e80941Smrg    *   "An INVALID_ENUM error is generated if <pname> is not
1343b8e80941Smrg    *    ELEMENT_ARRAY_BUFFER_BINDING."
1344b8e80941Smrg    */
1345b8e80941Smrg   if (pname != GL_ELEMENT_ARRAY_BUFFER_BINDING) {
1346b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
1347b8e80941Smrg                  "glGetVertexArrayiv(pname != "
1348b8e80941Smrg                  "GL_ELEMENT_ARRAY_BUFFER_BINDING)");
1349b8e80941Smrg      return;
1350b8e80941Smrg   }
1351b8e80941Smrg
1352b8e80941Smrg   param[0] = vao->IndexBufferObj->Name;
1353848b8605Smrg}
1354