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