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