17117f1b4Smrg/* 27117f1b4Smrg * Mesa 3-D graphics library 37117f1b4Smrg * 4c1f859d4Smrg * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 57117f1b4Smrg * (C) Copyright IBM Corporation 2006 64a49301eSmrg * Copyright (C) 2009 VMware, Inc. All Rights Reserved. 77117f1b4Smrg * 87117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 97117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 107117f1b4Smrg * to deal in the Software without restriction, including without limitation 117117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 127117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 137117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 147117f1b4Smrg * 157117f1b4Smrg * The above copyright notice and this permission notice shall be included 167117f1b4Smrg * in all copies or substantial portions of the Software. 177117f1b4Smrg * 187117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 197117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 207117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 22af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 257117f1b4Smrg */ 267117f1b4Smrg 277117f1b4Smrg 287117f1b4Smrg/** 297117f1b4Smrg * \file arrayobj.c 30af69d88dSmrg * 3101e04c3fSmrg * Implementation of Vertex Array Objects (VAOs), from OpenGL 3.1+ / 3201e04c3fSmrg * the GL_ARB_vertex_array_object extension. 337117f1b4Smrg * 347117f1b4Smrg * \todo 357117f1b4Smrg * The code in this file borrows a lot from bufferobj.c. There's a certain 367117f1b4Smrg * amount of cruft left over from that origin that may be unnecessary. 377117f1b4Smrg * 387117f1b4Smrg * \author Ian Romanick <idr@us.ibm.com> 397117f1b4Smrg * \author Brian Paul 407117f1b4Smrg */ 417117f1b4Smrg 427117f1b4Smrg 437117f1b4Smrg#include "glheader.h" 447117f1b4Smrg#include "hash.h" 453464ebd5Sriastradh#include "image.h" 467ec681f3Smrg 477117f1b4Smrg#include "context.h" 487117f1b4Smrg#include "bufferobj.h" 497117f1b4Smrg#include "arrayobj.h" 507ec681f3Smrg#include "draw_validate.h" 514a49301eSmrg#include "macros.h" 523464ebd5Sriastradh#include "mtypes.h" 5301e04c3fSmrg#include "state.h" 543464ebd5Sriastradh#include "varray.h" 5501e04c3fSmrg#include "util/bitscan.h" 5601e04c3fSmrg#include "util/u_atomic.h" 5701e04c3fSmrg#include "util/u_math.h" 587ec681f3Smrg#include "util/u_memory.h" 5901e04c3fSmrg 6001e04c3fSmrg 6101e04c3fSmrgconst GLubyte 6201e04c3fSmrg_mesa_vao_attribute_map[ATTRIBUTE_MAP_MODE_MAX][VERT_ATTRIB_MAX] = 6301e04c3fSmrg{ 6401e04c3fSmrg /* ATTRIBUTE_MAP_MODE_IDENTITY 6501e04c3fSmrg * 6601e04c3fSmrg * Grab vertex processing attribute VERT_ATTRIB_POS from 6701e04c3fSmrg * the VAO attribute VERT_ATTRIB_POS, and grab vertex processing 6801e04c3fSmrg * attribute VERT_ATTRIB_GENERIC0 from the VAO attribute 6901e04c3fSmrg * VERT_ATTRIB_GENERIC0. 7001e04c3fSmrg */ 7101e04c3fSmrg { 7201e04c3fSmrg VERT_ATTRIB_POS, /* VERT_ATTRIB_POS */ 7301e04c3fSmrg VERT_ATTRIB_NORMAL, /* VERT_ATTRIB_NORMAL */ 7401e04c3fSmrg VERT_ATTRIB_COLOR0, /* VERT_ATTRIB_COLOR0 */ 7501e04c3fSmrg VERT_ATTRIB_COLOR1, /* VERT_ATTRIB_COLOR1 */ 7601e04c3fSmrg VERT_ATTRIB_FOG, /* VERT_ATTRIB_FOG */ 7701e04c3fSmrg VERT_ATTRIB_COLOR_INDEX, /* VERT_ATTRIB_COLOR_INDEX */ 7801e04c3fSmrg VERT_ATTRIB_TEX0, /* VERT_ATTRIB_TEX0 */ 7901e04c3fSmrg VERT_ATTRIB_TEX1, /* VERT_ATTRIB_TEX1 */ 8001e04c3fSmrg VERT_ATTRIB_TEX2, /* VERT_ATTRIB_TEX2 */ 8101e04c3fSmrg VERT_ATTRIB_TEX3, /* VERT_ATTRIB_TEX3 */ 8201e04c3fSmrg VERT_ATTRIB_TEX4, /* VERT_ATTRIB_TEX4 */ 8301e04c3fSmrg VERT_ATTRIB_TEX5, /* VERT_ATTRIB_TEX5 */ 8401e04c3fSmrg VERT_ATTRIB_TEX6, /* VERT_ATTRIB_TEX6 */ 8501e04c3fSmrg VERT_ATTRIB_TEX7, /* VERT_ATTRIB_TEX7 */ 8601e04c3fSmrg VERT_ATTRIB_POINT_SIZE, /* VERT_ATTRIB_POINT_SIZE */ 8701e04c3fSmrg VERT_ATTRIB_GENERIC0, /* VERT_ATTRIB_GENERIC0 */ 8801e04c3fSmrg VERT_ATTRIB_GENERIC1, /* VERT_ATTRIB_GENERIC1 */ 8901e04c3fSmrg VERT_ATTRIB_GENERIC2, /* VERT_ATTRIB_GENERIC2 */ 9001e04c3fSmrg VERT_ATTRIB_GENERIC3, /* VERT_ATTRIB_GENERIC3 */ 9101e04c3fSmrg VERT_ATTRIB_GENERIC4, /* VERT_ATTRIB_GENERIC4 */ 9201e04c3fSmrg VERT_ATTRIB_GENERIC5, /* VERT_ATTRIB_GENERIC5 */ 9301e04c3fSmrg VERT_ATTRIB_GENERIC6, /* VERT_ATTRIB_GENERIC6 */ 9401e04c3fSmrg VERT_ATTRIB_GENERIC7, /* VERT_ATTRIB_GENERIC7 */ 9501e04c3fSmrg VERT_ATTRIB_GENERIC8, /* VERT_ATTRIB_GENERIC8 */ 9601e04c3fSmrg VERT_ATTRIB_GENERIC9, /* VERT_ATTRIB_GENERIC9 */ 9701e04c3fSmrg VERT_ATTRIB_GENERIC10, /* VERT_ATTRIB_GENERIC10 */ 9801e04c3fSmrg VERT_ATTRIB_GENERIC11, /* VERT_ATTRIB_GENERIC11 */ 9901e04c3fSmrg VERT_ATTRIB_GENERIC12, /* VERT_ATTRIB_GENERIC12 */ 10001e04c3fSmrg VERT_ATTRIB_GENERIC13, /* VERT_ATTRIB_GENERIC13 */ 10101e04c3fSmrg VERT_ATTRIB_GENERIC14, /* VERT_ATTRIB_GENERIC14 */ 1027ec681f3Smrg VERT_ATTRIB_GENERIC15, /* VERT_ATTRIB_GENERIC15 */ 1037ec681f3Smrg VERT_ATTRIB_EDGEFLAG, /* VERT_ATTRIB_EDGEFLAG */ 10401e04c3fSmrg }, 10501e04c3fSmrg 10601e04c3fSmrg /* ATTRIBUTE_MAP_MODE_POSITION 10701e04c3fSmrg * 10801e04c3fSmrg * Grab vertex processing attribute VERT_ATTRIB_POS as well as 10901e04c3fSmrg * vertex processing attribute VERT_ATTRIB_GENERIC0 from the 11001e04c3fSmrg * VAO attribute VERT_ATTRIB_POS. 11101e04c3fSmrg */ 11201e04c3fSmrg { 11301e04c3fSmrg VERT_ATTRIB_POS, /* VERT_ATTRIB_POS */ 11401e04c3fSmrg VERT_ATTRIB_NORMAL, /* VERT_ATTRIB_NORMAL */ 11501e04c3fSmrg VERT_ATTRIB_COLOR0, /* VERT_ATTRIB_COLOR0 */ 11601e04c3fSmrg VERT_ATTRIB_COLOR1, /* VERT_ATTRIB_COLOR1 */ 11701e04c3fSmrg VERT_ATTRIB_FOG, /* VERT_ATTRIB_FOG */ 11801e04c3fSmrg VERT_ATTRIB_COLOR_INDEX, /* VERT_ATTRIB_COLOR_INDEX */ 11901e04c3fSmrg VERT_ATTRIB_TEX0, /* VERT_ATTRIB_TEX0 */ 12001e04c3fSmrg VERT_ATTRIB_TEX1, /* VERT_ATTRIB_TEX1 */ 12101e04c3fSmrg VERT_ATTRIB_TEX2, /* VERT_ATTRIB_TEX2 */ 12201e04c3fSmrg VERT_ATTRIB_TEX3, /* VERT_ATTRIB_TEX3 */ 12301e04c3fSmrg VERT_ATTRIB_TEX4, /* VERT_ATTRIB_TEX4 */ 12401e04c3fSmrg VERT_ATTRIB_TEX5, /* VERT_ATTRIB_TEX5 */ 12501e04c3fSmrg VERT_ATTRIB_TEX6, /* VERT_ATTRIB_TEX6 */ 12601e04c3fSmrg VERT_ATTRIB_TEX7, /* VERT_ATTRIB_TEX7 */ 12701e04c3fSmrg VERT_ATTRIB_POINT_SIZE, /* VERT_ATTRIB_POINT_SIZE */ 12801e04c3fSmrg VERT_ATTRIB_POS, /* VERT_ATTRIB_GENERIC0 */ 12901e04c3fSmrg VERT_ATTRIB_GENERIC1, /* VERT_ATTRIB_GENERIC1 */ 13001e04c3fSmrg VERT_ATTRIB_GENERIC2, /* VERT_ATTRIB_GENERIC2 */ 13101e04c3fSmrg VERT_ATTRIB_GENERIC3, /* VERT_ATTRIB_GENERIC3 */ 13201e04c3fSmrg VERT_ATTRIB_GENERIC4, /* VERT_ATTRIB_GENERIC4 */ 13301e04c3fSmrg VERT_ATTRIB_GENERIC5, /* VERT_ATTRIB_GENERIC5 */ 13401e04c3fSmrg VERT_ATTRIB_GENERIC6, /* VERT_ATTRIB_GENERIC6 */ 13501e04c3fSmrg VERT_ATTRIB_GENERIC7, /* VERT_ATTRIB_GENERIC7 */ 13601e04c3fSmrg VERT_ATTRIB_GENERIC8, /* VERT_ATTRIB_GENERIC8 */ 13701e04c3fSmrg VERT_ATTRIB_GENERIC9, /* VERT_ATTRIB_GENERIC9 */ 13801e04c3fSmrg VERT_ATTRIB_GENERIC10, /* VERT_ATTRIB_GENERIC10 */ 13901e04c3fSmrg VERT_ATTRIB_GENERIC11, /* VERT_ATTRIB_GENERIC11 */ 14001e04c3fSmrg VERT_ATTRIB_GENERIC12, /* VERT_ATTRIB_GENERIC12 */ 14101e04c3fSmrg VERT_ATTRIB_GENERIC13, /* VERT_ATTRIB_GENERIC13 */ 14201e04c3fSmrg VERT_ATTRIB_GENERIC14, /* VERT_ATTRIB_GENERIC14 */ 1437ec681f3Smrg VERT_ATTRIB_GENERIC15, /* VERT_ATTRIB_GENERIC15 */ 1447ec681f3Smrg VERT_ATTRIB_EDGEFLAG, /* VERT_ATTRIB_EDGEFLAG */ 14501e04c3fSmrg }, 14601e04c3fSmrg 14701e04c3fSmrg /* ATTRIBUTE_MAP_MODE_GENERIC0 14801e04c3fSmrg * 14901e04c3fSmrg * Grab vertex processing attribute VERT_ATTRIB_POS as well as 15001e04c3fSmrg * vertex processing attribute VERT_ATTRIB_GENERIC0 from the 15101e04c3fSmrg * VAO attribute VERT_ATTRIB_GENERIC0. 15201e04c3fSmrg */ 15301e04c3fSmrg { 15401e04c3fSmrg VERT_ATTRIB_GENERIC0, /* VERT_ATTRIB_POS */ 15501e04c3fSmrg VERT_ATTRIB_NORMAL, /* VERT_ATTRIB_NORMAL */ 15601e04c3fSmrg VERT_ATTRIB_COLOR0, /* VERT_ATTRIB_COLOR0 */ 15701e04c3fSmrg VERT_ATTRIB_COLOR1, /* VERT_ATTRIB_COLOR1 */ 15801e04c3fSmrg VERT_ATTRIB_FOG, /* VERT_ATTRIB_FOG */ 15901e04c3fSmrg VERT_ATTRIB_COLOR_INDEX, /* VERT_ATTRIB_COLOR_INDEX */ 16001e04c3fSmrg VERT_ATTRIB_TEX0, /* VERT_ATTRIB_TEX0 */ 16101e04c3fSmrg VERT_ATTRIB_TEX1, /* VERT_ATTRIB_TEX1 */ 16201e04c3fSmrg VERT_ATTRIB_TEX2, /* VERT_ATTRIB_TEX2 */ 16301e04c3fSmrg VERT_ATTRIB_TEX3, /* VERT_ATTRIB_TEX3 */ 16401e04c3fSmrg VERT_ATTRIB_TEX4, /* VERT_ATTRIB_TEX4 */ 16501e04c3fSmrg VERT_ATTRIB_TEX5, /* VERT_ATTRIB_TEX5 */ 16601e04c3fSmrg VERT_ATTRIB_TEX6, /* VERT_ATTRIB_TEX6 */ 16701e04c3fSmrg VERT_ATTRIB_TEX7, /* VERT_ATTRIB_TEX7 */ 16801e04c3fSmrg VERT_ATTRIB_POINT_SIZE, /* VERT_ATTRIB_POINT_SIZE */ 16901e04c3fSmrg VERT_ATTRIB_GENERIC0, /* VERT_ATTRIB_GENERIC0 */ 17001e04c3fSmrg VERT_ATTRIB_GENERIC1, /* VERT_ATTRIB_GENERIC1 */ 17101e04c3fSmrg VERT_ATTRIB_GENERIC2, /* VERT_ATTRIB_GENERIC2 */ 17201e04c3fSmrg VERT_ATTRIB_GENERIC3, /* VERT_ATTRIB_GENERIC3 */ 17301e04c3fSmrg VERT_ATTRIB_GENERIC4, /* VERT_ATTRIB_GENERIC4 */ 17401e04c3fSmrg VERT_ATTRIB_GENERIC5, /* VERT_ATTRIB_GENERIC5 */ 17501e04c3fSmrg VERT_ATTRIB_GENERIC6, /* VERT_ATTRIB_GENERIC6 */ 17601e04c3fSmrg VERT_ATTRIB_GENERIC7, /* VERT_ATTRIB_GENERIC7 */ 17701e04c3fSmrg VERT_ATTRIB_GENERIC8, /* VERT_ATTRIB_GENERIC8 */ 17801e04c3fSmrg VERT_ATTRIB_GENERIC9, /* VERT_ATTRIB_GENERIC9 */ 17901e04c3fSmrg VERT_ATTRIB_GENERIC10, /* VERT_ATTRIB_GENERIC10 */ 18001e04c3fSmrg VERT_ATTRIB_GENERIC11, /* VERT_ATTRIB_GENERIC11 */ 18101e04c3fSmrg VERT_ATTRIB_GENERIC12, /* VERT_ATTRIB_GENERIC12 */ 18201e04c3fSmrg VERT_ATTRIB_GENERIC13, /* VERT_ATTRIB_GENERIC13 */ 18301e04c3fSmrg VERT_ATTRIB_GENERIC14, /* VERT_ATTRIB_GENERIC14 */ 1847ec681f3Smrg VERT_ATTRIB_GENERIC15, /* VERT_ATTRIB_GENERIC15 */ 1857ec681f3Smrg VERT_ATTRIB_EDGEFLAG, /* VERT_ATTRIB_EDGEFLAG */ 18601e04c3fSmrg } 18701e04c3fSmrg}; 1887117f1b4Smrg 1897117f1b4Smrg 1907117f1b4Smrg/** 1917117f1b4Smrg * Look up the array object for the given ID. 192af69d88dSmrg * 1937117f1b4Smrg * \returns 1947117f1b4Smrg * Either a pointer to the array object with the specified ID or \c NULL for 1957117f1b4Smrg * a non-existent ID. The spec defines ID 0 as being technically 1967117f1b4Smrg * non-existent. 1977117f1b4Smrg */ 1987117f1b4Smrg 199af69d88dSmrgstruct gl_vertex_array_object * 200af69d88dSmrg_mesa_lookup_vao(struct gl_context *ctx, GLuint id) 2017117f1b4Smrg{ 20201e04c3fSmrg /* The ARB_direct_state_access specification says: 20301e04c3fSmrg * 20401e04c3fSmrg * "<vaobj> is [compatibility profile: 20501e04c3fSmrg * zero, indicating the default vertex array object, or] 20601e04c3fSmrg * the name of the vertex array object." 20701e04c3fSmrg */ 20801e04c3fSmrg if (id == 0) { 20901e04c3fSmrg if (ctx->API == API_OPENGL_COMPAT) 21001e04c3fSmrg return ctx->Array.DefaultVAO; 21101e04c3fSmrg 2124a49301eSmrg return NULL; 21301e04c3fSmrg } else { 21401e04c3fSmrg struct gl_vertex_array_object *vao; 21501e04c3fSmrg 21601e04c3fSmrg if (ctx->Array.LastLookedUpVAO && 21701e04c3fSmrg ctx->Array.LastLookedUpVAO->Name == id) { 21801e04c3fSmrg vao = ctx->Array.LastLookedUpVAO; 21901e04c3fSmrg } else { 22001e04c3fSmrg vao = (struct gl_vertex_array_object *) 22101e04c3fSmrg _mesa_HashLookupLocked(ctx->Array.Objects, id); 22201e04c3fSmrg 22301e04c3fSmrg _mesa_reference_vao(ctx, &ctx->Array.LastLookedUpVAO, vao); 22401e04c3fSmrg } 22501e04c3fSmrg 22601e04c3fSmrg return vao; 22701e04c3fSmrg } 22801e04c3fSmrg} 22901e04c3fSmrg 23001e04c3fSmrg 23101e04c3fSmrg/** 23201e04c3fSmrg * Looks up the array object for the given ID. 23301e04c3fSmrg * 2347ec681f3Smrg * While _mesa_lookup_vao doesn't generate an error if the object does not 2357ec681f3Smrg * exist, this function comes in two variants. 2367ec681f3Smrg * If is_ext_dsa is false, this function generates a GL_INVALID_OPERATION 23701e04c3fSmrg * error if the array object does not exist. It also returns the default 23801e04c3fSmrg * array object when ctx is a compatibility profile context and id is zero. 2397ec681f3Smrg * If is_ext_dsa is true, 0 is not a valid name. If the name exists but 2407ec681f3Smrg * the object has never been bound, it is initialized. 24101e04c3fSmrg */ 24201e04c3fSmrgstruct gl_vertex_array_object * 2437ec681f3Smrg_mesa_lookup_vao_err(struct gl_context *ctx, GLuint id, 2447ec681f3Smrg bool is_ext_dsa, const char *caller) 24501e04c3fSmrg{ 24601e04c3fSmrg /* The ARB_direct_state_access specification says: 24701e04c3fSmrg * 24801e04c3fSmrg * "<vaobj> is [compatibility profile: 24901e04c3fSmrg * zero, indicating the default vertex array object, or] 25001e04c3fSmrg * the name of the vertex array object." 25101e04c3fSmrg */ 25201e04c3fSmrg if (id == 0) { 2537ec681f3Smrg if (is_ext_dsa || ctx->API == API_OPENGL_CORE) { 25401e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 2557ec681f3Smrg "%s(zero is not valid vaobj name%s)", 2567ec681f3Smrg caller, 2577ec681f3Smrg is_ext_dsa ? "" : " in a core profile context"); 25801e04c3fSmrg return NULL; 25901e04c3fSmrg } 26001e04c3fSmrg 26101e04c3fSmrg return ctx->Array.DefaultVAO; 26201e04c3fSmrg } else { 26301e04c3fSmrg struct gl_vertex_array_object *vao; 26401e04c3fSmrg 26501e04c3fSmrg if (ctx->Array.LastLookedUpVAO && 26601e04c3fSmrg ctx->Array.LastLookedUpVAO->Name == id) { 26701e04c3fSmrg vao = ctx->Array.LastLookedUpVAO; 26801e04c3fSmrg } else { 26901e04c3fSmrg vao = (struct gl_vertex_array_object *) 27001e04c3fSmrg _mesa_HashLookupLocked(ctx->Array.Objects, id); 27101e04c3fSmrg 27201e04c3fSmrg /* The ARB_direct_state_access specification says: 27301e04c3fSmrg * 27401e04c3fSmrg * "An INVALID_OPERATION error is generated if <vaobj> is not 27501e04c3fSmrg * [compatibility profile: zero or] the name of an existing 27601e04c3fSmrg * vertex array object." 27701e04c3fSmrg */ 2787ec681f3Smrg if (!vao || (!is_ext_dsa && !vao->EverBound)) { 27901e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 28001e04c3fSmrg "%s(non-existent vaobj=%u)", caller, id); 28101e04c3fSmrg return NULL; 28201e04c3fSmrg } 28301e04c3fSmrg 2847ec681f3Smrg /* The EXT_direct_state_access specification says: 2857ec681f3Smrg * 2867ec681f3Smrg * "If the vertex array object named by the vaobj parameter has not 2877ec681f3Smrg * been previously bound but has been generated (without subsequent 2887ec681f3Smrg * deletion) by GenVertexArrays, the GL first creates a new state 2897ec681f3Smrg * vector in the same manner as when BindVertexArray creates a new 2907ec681f3Smrg * vertex array object." 2917ec681f3Smrg */ 2927ec681f3Smrg if (vao && is_ext_dsa && !vao->EverBound) 2937ec681f3Smrg vao->EverBound = true; 2947ec681f3Smrg 29501e04c3fSmrg _mesa_reference_vao(ctx, &ctx->Array.LastLookedUpVAO, vao); 29601e04c3fSmrg } 29701e04c3fSmrg 29801e04c3fSmrg return vao; 29901e04c3fSmrg } 3004a49301eSmrg} 3014a49301eSmrg 3024a49301eSmrg 3034a49301eSmrg/** 304af69d88dSmrg * For all the vertex binding points in the array object, unbind any pointers 3054a49301eSmrg * to any buffer objects (VBOs). 3064a49301eSmrg * This is done just prior to array object destruction. 3074a49301eSmrg */ 3087ec681f3Smrgvoid 3097ec681f3Smrg_mesa_unbind_array_object_vbos(struct gl_context *ctx, 3107ec681f3Smrg struct gl_vertex_array_object *obj) 3114a49301eSmrg{ 3124a49301eSmrg GLuint i; 3134a49301eSmrg 31401e04c3fSmrg for (i = 0; i < ARRAY_SIZE(obj->BufferBinding); i++) 31501e04c3fSmrg _mesa_reference_buffer_object(ctx, &obj->BufferBinding[i].BufferObj, NULL); 3167117f1b4Smrg} 3177117f1b4Smrg 3187117f1b4Smrg 3197117f1b4Smrg/** 3207117f1b4Smrg * Allocate and initialize a new vertex array object. 3217117f1b4Smrg */ 322af69d88dSmrgstruct gl_vertex_array_object * 323af69d88dSmrg_mesa_new_vao(struct gl_context *ctx, GLuint name) 3247117f1b4Smrg{ 3257ec681f3Smrg struct gl_vertex_array_object *obj = MALLOC_STRUCT(gl_vertex_array_object); 3267117f1b4Smrg if (obj) 327af69d88dSmrg _mesa_initialize_vao(ctx, obj, name); 3287117f1b4Smrg return obj; 3297117f1b4Smrg} 3307117f1b4Smrg 3317117f1b4Smrg 3327117f1b4Smrg/** 3337117f1b4Smrg * Delete an array object. 3347117f1b4Smrg */ 3357117f1b4Smrgvoid 336af69d88dSmrg_mesa_delete_vao(struct gl_context *ctx, struct gl_vertex_array_object *obj) 3377117f1b4Smrg{ 3387ec681f3Smrg _mesa_unbind_array_object_vbos(ctx, obj); 339af69d88dSmrg _mesa_reference_buffer_object(ctx, &obj->IndexBufferObj, NULL); 340af69d88dSmrg free(obj->Label); 341cdc920a0Smrg free(obj); 3427117f1b4Smrg} 3437117f1b4Smrg 3447117f1b4Smrg 3454a49301eSmrg/** 346af69d88dSmrg * Set ptr to vao w/ reference counting. 347af69d88dSmrg * Note: this should only be called from the _mesa_reference_vao() 348af69d88dSmrg * inline function. 3494a49301eSmrg */ 3504a49301eSmrgvoid 351af69d88dSmrg_mesa_reference_vao_(struct gl_context *ctx, 352af69d88dSmrg struct gl_vertex_array_object **ptr, 353af69d88dSmrg struct gl_vertex_array_object *vao) 3544a49301eSmrg{ 355af69d88dSmrg assert(*ptr != vao); 3564a49301eSmrg 3574a49301eSmrg if (*ptr) { 3584a49301eSmrg /* Unreference the old array object */ 359af69d88dSmrg struct gl_vertex_array_object *oldObj = *ptr; 3604a49301eSmrg 36101e04c3fSmrg bool deleteFlag; 36201e04c3fSmrg if (oldObj->SharedAndImmutable) { 36301e04c3fSmrg deleteFlag = p_atomic_dec_zero(&oldObj->RefCount); 36401e04c3fSmrg } else { 36501e04c3fSmrg assert(oldObj->RefCount > 0); 36601e04c3fSmrg oldObj->RefCount--; 36701e04c3fSmrg deleteFlag = (oldObj->RefCount == 0); 3684a49301eSmrg } 3694a49301eSmrg 37001e04c3fSmrg if (deleteFlag) 37101e04c3fSmrg _mesa_delete_vao(ctx, oldObj); 37201e04c3fSmrg 3734a49301eSmrg *ptr = NULL; 3744a49301eSmrg } 37501e04c3fSmrg assert(!*ptr); 3764a49301eSmrg 377af69d88dSmrg if (vao) { 3784a49301eSmrg /* reference new array object */ 37901e04c3fSmrg if (vao->SharedAndImmutable) { 38001e04c3fSmrg p_atomic_inc(&vao->RefCount); 38101e04c3fSmrg } else { 38201e04c3fSmrg assert(vao->RefCount > 0); 383af69d88dSmrg vao->RefCount++; 3844a49301eSmrg } 38501e04c3fSmrg 38601e04c3fSmrg *ptr = vao; 3874a49301eSmrg } 3884a49301eSmrg} 3894a49301eSmrg 3904a49301eSmrg 3914a49301eSmrg/** 392af69d88dSmrg * Initialize a gl_vertex_array_object's arrays. 3934a49301eSmrg */ 3947117f1b4Smrgvoid 395af69d88dSmrg_mesa_initialize_vao(struct gl_context *ctx, 39601e04c3fSmrg struct gl_vertex_array_object *vao, 397af69d88dSmrg GLuint name) 3987117f1b4Smrg{ 3997ec681f3Smrg memcpy(vao, &ctx->Array.DefaultVAOState, sizeof(*vao)); 40001e04c3fSmrg vao->Name = name; 4017117f1b4Smrg} 4027117f1b4Smrg 4037117f1b4Smrg 4047117f1b4Smrg/** 40501e04c3fSmrg * Compute the offset range for the provided binding. 40601e04c3fSmrg * 40701e04c3fSmrg * This is a helper function for the below. 4087117f1b4Smrg */ 4094a49301eSmrgstatic void 41001e04c3fSmrgcompute_vbo_offset_range(const struct gl_vertex_array_object *vao, 41101e04c3fSmrg const struct gl_vertex_buffer_binding *binding, 41201e04c3fSmrg GLsizeiptr* min, GLsizeiptr* max) 4137117f1b4Smrg{ 41401e04c3fSmrg /* The function is meant to work on VBO bindings */ 4157ec681f3Smrg assert(binding->BufferObj); 41601e04c3fSmrg 41701e04c3fSmrg /* Start with an inverted range of relative offsets. */ 41801e04c3fSmrg GLuint min_offset = ~(GLuint)0; 41901e04c3fSmrg GLuint max_offset = 0; 42001e04c3fSmrg 42101e04c3fSmrg /* We work on the unmapped originaly VAO array entries. */ 422a8bb7a65Smaya GLbitfield mask = vao->Enabled & binding->_BoundArrays; 42301e04c3fSmrg /* The binding should be active somehow, not to return inverted ranges */ 42401e04c3fSmrg assert(mask); 42501e04c3fSmrg while (mask) { 42601e04c3fSmrg const int i = u_bit_scan(&mask); 42701e04c3fSmrg const GLuint off = vao->VertexAttrib[i].RelativeOffset; 42801e04c3fSmrg min_offset = MIN2(off, min_offset); 42901e04c3fSmrg max_offset = MAX2(off, max_offset); 4307117f1b4Smrg } 43101e04c3fSmrg 43201e04c3fSmrg *min = binding->Offset + (GLsizeiptr)min_offset; 43301e04c3fSmrg *max = binding->Offset + (GLsizeiptr)max_offset; 4347117f1b4Smrg} 4357117f1b4Smrg 4367117f1b4Smrg 4377117f1b4Smrg/** 43801e04c3fSmrg * Update the unique binding and pos/generic0 map tracking in the vao. 43901e04c3fSmrg * 44001e04c3fSmrg * The idea is to build up information in the vao so that a consuming 44101e04c3fSmrg * backend can execute the following to set up buffer and vertex element 44201e04c3fSmrg * information: 44301e04c3fSmrg * 44401e04c3fSmrg * const GLbitfield inputs_read = VERT_BIT_ALL; // backend vp inputs 44501e04c3fSmrg * 44601e04c3fSmrg * // Attribute data is in a VBO. 44701e04c3fSmrg * GLbitfield vbomask = inputs_read & _mesa_draw_vbo_array_bits(ctx); 44801e04c3fSmrg * while (vbomask) { 44901e04c3fSmrg * // The attribute index to start pulling a binding 45001e04c3fSmrg * const gl_vert_attrib i = ffs(vbomask) - 1; 45101e04c3fSmrg * const struct gl_vertex_buffer_binding *const binding 45201e04c3fSmrg * = _mesa_draw_buffer_binding(vao, i); 45301e04c3fSmrg * 45401e04c3fSmrg * <insert code to handle the vertex buffer object at binding> 45501e04c3fSmrg * 45601e04c3fSmrg * const GLbitfield boundmask = _mesa_draw_bound_attrib_bits(binding); 45701e04c3fSmrg * GLbitfield attrmask = vbomask & boundmask; 45801e04c3fSmrg * assert(attrmask); 45901e04c3fSmrg * // Walk attributes belonging to the binding 46001e04c3fSmrg * while (attrmask) { 46101e04c3fSmrg * const gl_vert_attrib attr = u_bit_scan(&attrmask); 46201e04c3fSmrg * const struct gl_array_attributes *const attrib 46301e04c3fSmrg * = _mesa_draw_array_attrib(vao, attr); 46401e04c3fSmrg * 46501e04c3fSmrg * <insert code to handle the vertex element refering to the binding> 46601e04c3fSmrg * } 46701e04c3fSmrg * vbomask &= ~boundmask; 46801e04c3fSmrg * } 46901e04c3fSmrg * 47001e04c3fSmrg * // Process user space buffers 47101e04c3fSmrg * GLbitfield usermask = inputs_read & _mesa_draw_user_array_bits(ctx); 47201e04c3fSmrg * while (usermask) { 47301e04c3fSmrg * // The attribute index to start pulling a binding 47401e04c3fSmrg * const gl_vert_attrib i = ffs(usermask) - 1; 47501e04c3fSmrg * const struct gl_vertex_buffer_binding *const binding 47601e04c3fSmrg * = _mesa_draw_buffer_binding(vao, i); 47701e04c3fSmrg * 47801e04c3fSmrg * <insert code to handle a set of interleaved user space arrays at binding> 47901e04c3fSmrg * 48001e04c3fSmrg * const GLbitfield boundmask = _mesa_draw_bound_attrib_bits(binding); 48101e04c3fSmrg * GLbitfield attrmask = usermask & boundmask; 48201e04c3fSmrg * assert(attrmask); 48301e04c3fSmrg * // Walk interleaved attributes with a common stride and instance divisor 48401e04c3fSmrg * while (attrmask) { 48501e04c3fSmrg * const gl_vert_attrib attr = u_bit_scan(&attrmask); 48601e04c3fSmrg * const struct gl_array_attributes *const attrib 48701e04c3fSmrg * = _mesa_draw_array_attrib(vao, attr); 48801e04c3fSmrg * 48901e04c3fSmrg * <insert code to handle non vbo vertex arrays> 49001e04c3fSmrg * } 49101e04c3fSmrg * usermask &= ~boundmask; 49201e04c3fSmrg * } 49301e04c3fSmrg * 49401e04c3fSmrg * // Process values that should have better been uniforms in the application 49501e04c3fSmrg * GLbitfield curmask = inputs_read & _mesa_draw_current_bits(ctx); 49601e04c3fSmrg * while (curmask) { 49701e04c3fSmrg * const gl_vert_attrib attr = u_bit_scan(&curmask); 49801e04c3fSmrg * const struct gl_array_attributes *const attrib 49901e04c3fSmrg * = _mesa_draw_current_attrib(ctx, attr); 50001e04c3fSmrg * 50101e04c3fSmrg * <insert code to handle current values> 50201e04c3fSmrg * } 50301e04c3fSmrg * 50401e04c3fSmrg * 50501e04c3fSmrg * Note that the scan below must not incoporate any context state. 50601e04c3fSmrg * The rationale is that once a VAO is finalized it should not 50701e04c3fSmrg * be touched anymore. That means, do not incorporate the 50801e04c3fSmrg * gl_context::Array._DrawVAOEnabledAttribs bitmask into this scan. 50901e04c3fSmrg * A backend driver may further reduce the handled vertex processing 51001e04c3fSmrg * inputs based on their vertex shader inputs. But scanning for 51101e04c3fSmrg * collapsable binding points to reduce relocs is done based on the 51201e04c3fSmrg * enabled arrays. 51301e04c3fSmrg * Also VAOs may be shared between contexts due to their use in dlists 51401e04c3fSmrg * thus no context state should bleed into the VAO. 5157117f1b4Smrg */ 51601e04c3fSmrgvoid 51701e04c3fSmrg_mesa_update_vao_derived_arrays(struct gl_context *ctx, 51801e04c3fSmrg struct gl_vertex_array_object *vao) 5197117f1b4Smrg{ 52001e04c3fSmrg /* Make sure we do not run into problems with shared objects */ 52101e04c3fSmrg assert(!vao->SharedAndImmutable || vao->NewArrays == 0); 52201e04c3fSmrg 52301e04c3fSmrg /* Limit used for common binding scanning below. */ 52401e04c3fSmrg const GLsizeiptr MaxRelativeOffset = 52501e04c3fSmrg ctx->Const.MaxVertexAttribRelativeOffset; 52601e04c3fSmrg 52701e04c3fSmrg /* The gl_vertex_array_object::_AttributeMapMode denotes the way 52801e04c3fSmrg * VERT_ATTRIB_{POS,GENERIC0} mapping is done. 52901e04c3fSmrg * 53001e04c3fSmrg * This mapping is used to map between the OpenGL api visible 53101e04c3fSmrg * VERT_ATTRIB_* arrays to mesa driver arrayinputs or shader inputs. 53201e04c3fSmrg * The mapping only depends on the enabled bits of the 53301e04c3fSmrg * VERT_ATTRIB_{POS,GENERIC0} arrays and is tracked in the VAO. 53401e04c3fSmrg * 53501e04c3fSmrg * This map needs to be applied when finally translating to the bitmasks 53601e04c3fSmrg * as consumed by the driver backends. The duplicate scanning is here 53701e04c3fSmrg * can as well be done in the OpenGL API numbering without this map. 53801e04c3fSmrg */ 53901e04c3fSmrg const gl_attribute_map_mode mode = vao->_AttributeMapMode; 54001e04c3fSmrg /* Enabled array bits. */ 541a8bb7a65Smaya const GLbitfield enabled = vao->Enabled; 54201e04c3fSmrg /* VBO array bits. */ 54301e04c3fSmrg const GLbitfield vbos = vao->VertexAttribBufferMask; 5447ec681f3Smrg const GLbitfield divisor_is_nonzero = vao->NonZeroDivisorMask; 54501e04c3fSmrg 54601e04c3fSmrg /* Compute and store effectively enabled and mapped vbo arrays */ 54701e04c3fSmrg vao->_EffEnabledVBO = _mesa_vao_enable_to_vp_inputs(mode, enabled & vbos); 5487ec681f3Smrg vao->_EffEnabledNonZeroDivisor = 5497ec681f3Smrg _mesa_vao_enable_to_vp_inputs(mode, enabled & divisor_is_nonzero); 5507ec681f3Smrg 5517ec681f3Smrg /* Fast path when the VAO is updated too often. */ 5527ec681f3Smrg if (vao->IsDynamic) 5537ec681f3Smrg return; 5547ec681f3Smrg 5557ec681f3Smrg /* More than 4 updates turn the VAO to dynamic. */ 5567ec681f3Smrg if (ctx->Const.AllowDynamicVAOFastPath && ++vao->NumUpdates > 4) { 5577ec681f3Smrg vao->IsDynamic = true; 5587ec681f3Smrg return; 5597ec681f3Smrg } 5607ec681f3Smrg 56101e04c3fSmrg /* Walk those enabled arrays that have a real vbo attached */ 56201e04c3fSmrg GLbitfield mask = enabled; 56301e04c3fSmrg while (mask) { 56401e04c3fSmrg /* Do not use u_bit_scan as we can walk multiple attrib arrays at once */ 56501e04c3fSmrg const int i = ffs(mask) - 1; 56601e04c3fSmrg /* The binding from the first to be processed attribute. */ 56701e04c3fSmrg const GLuint bindex = vao->VertexAttrib[i].BufferBindingIndex; 56801e04c3fSmrg struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[bindex]; 56901e04c3fSmrg 57001e04c3fSmrg /* The scan goes different for user space arrays than vbos */ 5717ec681f3Smrg if (binding->BufferObj) { 57201e04c3fSmrg /* The bound arrays. */ 57301e04c3fSmrg const GLbitfield bound = enabled & binding->_BoundArrays; 57401e04c3fSmrg 57501e04c3fSmrg /* Start this current effective binding with the actual bound arrays */ 57601e04c3fSmrg GLbitfield eff_bound_arrays = bound; 57701e04c3fSmrg 57801e04c3fSmrg /* 57901e04c3fSmrg * If there is nothing left to scan just update the effective binding 58001e04c3fSmrg * information. If the VAO is already only using a single binding point 58101e04c3fSmrg * we end up here. So the overhead of this scan for an application 58201e04c3fSmrg * carefully preparing the VAO for draw is low. 58301e04c3fSmrg */ 5847117f1b4Smrg 58501e04c3fSmrg GLbitfield scanmask = mask & vbos & ~bound; 58601e04c3fSmrg /* Is there something left to scan? */ 58701e04c3fSmrg if (scanmask == 0) { 58801e04c3fSmrg /* Just update the back reference from the attrib to the binding and 58901e04c3fSmrg * the effective offset. 59001e04c3fSmrg */ 59101e04c3fSmrg GLbitfield attrmask = eff_bound_arrays; 59201e04c3fSmrg while (attrmask) { 59301e04c3fSmrg const int j = u_bit_scan(&attrmask); 59401e04c3fSmrg struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j]; 59501e04c3fSmrg 59601e04c3fSmrg /* Update the index into the common binding point and offset */ 59701e04c3fSmrg attrib2->_EffBufferBindingIndex = bindex; 59801e04c3fSmrg attrib2->_EffRelativeOffset = attrib2->RelativeOffset; 59901e04c3fSmrg assert(attrib2->_EffRelativeOffset <= MaxRelativeOffset); 60001e04c3fSmrg } 60101e04c3fSmrg /* Finally this is the set of effectively bound arrays with the 60201e04c3fSmrg * original binding offset. 60301e04c3fSmrg */ 60401e04c3fSmrg binding->_EffOffset = binding->Offset; 60501e04c3fSmrg /* The bound arrays past the VERT_ATTRIB_{POS,GENERIC0} mapping. */ 60601e04c3fSmrg binding->_EffBoundArrays = 60701e04c3fSmrg _mesa_vao_enable_to_vp_inputs(mode, eff_bound_arrays); 60801e04c3fSmrg 60901e04c3fSmrg } else { 61001e04c3fSmrg /* In the VBO case, scan for attribute/binding 61101e04c3fSmrg * combinations with relative bindings in the range of 61201e04c3fSmrg * [0, ctx->Const.MaxVertexAttribRelativeOffset]. 61301e04c3fSmrg * Note that this does also go beyond just interleaved arrays 61401e04c3fSmrg * as long as they use the same VBO, binding parameters and the 61501e04c3fSmrg * offsets stay within bounds that the backend still can handle. 61601e04c3fSmrg */ 61701e04c3fSmrg 61801e04c3fSmrg GLsizeiptr min_offset, max_offset; 61901e04c3fSmrg compute_vbo_offset_range(vao, binding, &min_offset, &max_offset); 62001e04c3fSmrg assert(max_offset <= min_offset + MaxRelativeOffset); 62101e04c3fSmrg 62201e04c3fSmrg /* Now scan. */ 62301e04c3fSmrg while (scanmask) { 62401e04c3fSmrg /* Do not use u_bit_scan as we can walk multiple 62501e04c3fSmrg * attrib arrays at once 62601e04c3fSmrg */ 62701e04c3fSmrg const int j = ffs(scanmask) - 1; 62801e04c3fSmrg const struct gl_array_attributes *attrib2 = 62901e04c3fSmrg &vao->VertexAttrib[j]; 63001e04c3fSmrg const struct gl_vertex_buffer_binding *binding2 = 63101e04c3fSmrg &vao->BufferBinding[attrib2->BufferBindingIndex]; 63201e04c3fSmrg 63301e04c3fSmrg /* Remove those attrib bits from the mask that are bound to the 63401e04c3fSmrg * same effective binding point. 63501e04c3fSmrg */ 63601e04c3fSmrg const GLbitfield bound2 = enabled & binding2->_BoundArrays; 63701e04c3fSmrg scanmask &= ~bound2; 63801e04c3fSmrg 63901e04c3fSmrg /* Check if we have an identical binding */ 64001e04c3fSmrg if (binding->Stride != binding2->Stride) 64101e04c3fSmrg continue; 64201e04c3fSmrg if (binding->InstanceDivisor != binding2->InstanceDivisor) 64301e04c3fSmrg continue; 64401e04c3fSmrg if (binding->BufferObj != binding2->BufferObj) 64501e04c3fSmrg continue; 64601e04c3fSmrg /* Check if we can fold both bindings into a common binding */ 64701e04c3fSmrg GLsizeiptr min_offset2, max_offset2; 64801e04c3fSmrg compute_vbo_offset_range(vao, binding2, 64901e04c3fSmrg &min_offset2, &max_offset2); 65001e04c3fSmrg /* If the relative offset is within the limits ... */ 65101e04c3fSmrg if (min_offset + MaxRelativeOffset < max_offset2) 65201e04c3fSmrg continue; 65301e04c3fSmrg if (min_offset2 + MaxRelativeOffset < max_offset) 65401e04c3fSmrg continue; 65501e04c3fSmrg /* ... add this array to the effective binding */ 65601e04c3fSmrg eff_bound_arrays |= bound2; 65701e04c3fSmrg min_offset = MIN2(min_offset, min_offset2); 65801e04c3fSmrg max_offset = MAX2(max_offset, max_offset2); 65901e04c3fSmrg assert(max_offset <= min_offset + MaxRelativeOffset); 66001e04c3fSmrg } 66101e04c3fSmrg 66201e04c3fSmrg /* Update the back reference from the attrib to the binding */ 66301e04c3fSmrg GLbitfield attrmask = eff_bound_arrays; 66401e04c3fSmrg while (attrmask) { 66501e04c3fSmrg const int j = u_bit_scan(&attrmask); 66601e04c3fSmrg struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j]; 66701e04c3fSmrg const struct gl_vertex_buffer_binding *binding2 = 66801e04c3fSmrg &vao->BufferBinding[attrib2->BufferBindingIndex]; 66901e04c3fSmrg 67001e04c3fSmrg /* Update the index into the common binding point and offset */ 67101e04c3fSmrg attrib2->_EffBufferBindingIndex = bindex; 67201e04c3fSmrg attrib2->_EffRelativeOffset = 67301e04c3fSmrg binding2->Offset + attrib2->RelativeOffset - min_offset; 67401e04c3fSmrg assert(attrib2->_EffRelativeOffset <= MaxRelativeOffset); 67501e04c3fSmrg } 67601e04c3fSmrg /* Finally this is the set of effectively bound arrays */ 67701e04c3fSmrg binding->_EffOffset = min_offset; 67801e04c3fSmrg /* The bound arrays past the VERT_ATTRIB_{POS,GENERIC0} mapping. */ 67901e04c3fSmrg binding->_EffBoundArrays = 68001e04c3fSmrg _mesa_vao_enable_to_vp_inputs(mode, eff_bound_arrays); 68101e04c3fSmrg } 6827117f1b4Smrg 68301e04c3fSmrg /* Mark all the effective bound arrays as processed. */ 68401e04c3fSmrg mask &= ~eff_bound_arrays; 6854a49301eSmrg 68601e04c3fSmrg } else { 68701e04c3fSmrg /* Scanning of common bindings for user space arrays. 68801e04c3fSmrg */ 689af69d88dSmrg 69001e04c3fSmrg const struct gl_array_attributes *attrib = &vao->VertexAttrib[i]; 69101e04c3fSmrg const GLbitfield bound = VERT_BIT(i); 692af69d88dSmrg 69301e04c3fSmrg /* Note that user space array pointers can only happen using a one 69401e04c3fSmrg * to one binding point to array mapping. 69501e04c3fSmrg * The OpenGL 4.x/ARB_vertex_attrib_binding api does not support 69601e04c3fSmrg * user space arrays collected at multiple binding points. 69701e04c3fSmrg * The only provider of user space interleaved arrays with a single 69801e04c3fSmrg * binding point is the mesa internal vbo module. But that one 69901e04c3fSmrg * provides a perfect interleaved set of arrays. 70001e04c3fSmrg * 70101e04c3fSmrg * If this would not be true we would potentially get attribute arrays 70201e04c3fSmrg * with user space pointers that may not lie within the 70301e04c3fSmrg * MaxRelativeOffset range but still attached to a single binding. 70401e04c3fSmrg * Then we would need to store the effective attribute and binding 70501e04c3fSmrg * grouping information in a seperate array beside 70601e04c3fSmrg * gl_array_attributes/gl_vertex_buffer_binding. 70701e04c3fSmrg */ 708a8bb7a65Smaya assert(util_bitcount(binding->_BoundArrays & vao->Enabled) == 1 709a8bb7a65Smaya || (vao->Enabled & ~binding->_BoundArrays) == 0); 710af69d88dSmrg 71101e04c3fSmrg /* Start this current effective binding with the array */ 71201e04c3fSmrg GLbitfield eff_bound_arrays = bound; 7134a49301eSmrg 71401e04c3fSmrg const GLubyte *ptr = attrib->Ptr; 715a8bb7a65Smaya unsigned vertex_end = attrib->Format._ElementSize; 7164a49301eSmrg 71701e04c3fSmrg /* Walk other user space arrays and see which are interleaved 71801e04c3fSmrg * using the same binding parameters. 71901e04c3fSmrg */ 72001e04c3fSmrg GLbitfield scanmask = mask & ~vbos & ~bound; 72101e04c3fSmrg while (scanmask) { 72201e04c3fSmrg const int j = u_bit_scan(&scanmask); 72301e04c3fSmrg const struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j]; 72401e04c3fSmrg const struct gl_vertex_buffer_binding *binding2 = 72501e04c3fSmrg &vao->BufferBinding[attrib2->BufferBindingIndex]; 72601e04c3fSmrg 72701e04c3fSmrg /* See the comment at the same assert above. */ 728a8bb7a65Smaya assert(util_bitcount(binding2->_BoundArrays & vao->Enabled) == 1 729a8bb7a65Smaya || (vao->Enabled & ~binding->_BoundArrays) == 0); 73001e04c3fSmrg 73101e04c3fSmrg /* Check if we have an identical binding */ 73201e04c3fSmrg if (binding->Stride != binding2->Stride) 73301e04c3fSmrg continue; 73401e04c3fSmrg if (binding->InstanceDivisor != binding2->InstanceDivisor) 73501e04c3fSmrg continue; 73601e04c3fSmrg if (ptr <= attrib2->Ptr) { 737a8bb7a65Smaya if (ptr + binding->Stride < attrib2->Ptr + 738a8bb7a65Smaya attrib2->Format._ElementSize) 73901e04c3fSmrg continue; 740a8bb7a65Smaya unsigned end = attrib2->Ptr + attrib2->Format._ElementSize - ptr; 74101e04c3fSmrg vertex_end = MAX2(vertex_end, end); 74201e04c3fSmrg } else { 74301e04c3fSmrg if (attrib2->Ptr + binding->Stride < ptr + vertex_end) 74401e04c3fSmrg continue; 74501e04c3fSmrg vertex_end += (GLsizei)(ptr - attrib2->Ptr); 74601e04c3fSmrg ptr = attrib2->Ptr; 74701e04c3fSmrg } 74801e04c3fSmrg 74901e04c3fSmrg /* User space buffer object */ 7507ec681f3Smrg assert(!binding2->BufferObj); 75101e04c3fSmrg 75201e04c3fSmrg eff_bound_arrays |= VERT_BIT(j); 75301e04c3fSmrg } 754af69d88dSmrg 75501e04c3fSmrg /* Update the back reference from the attrib to the binding */ 75601e04c3fSmrg GLbitfield attrmask = eff_bound_arrays; 75701e04c3fSmrg while (attrmask) { 75801e04c3fSmrg const int j = u_bit_scan(&attrmask); 75901e04c3fSmrg struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j]; 76001e04c3fSmrg 76101e04c3fSmrg /* Update the index into the common binding point and the offset */ 76201e04c3fSmrg attrib2->_EffBufferBindingIndex = bindex; 76301e04c3fSmrg attrib2->_EffRelativeOffset = attrib2->Ptr - ptr; 76401e04c3fSmrg assert(attrib2->_EffRelativeOffset <= binding->Stride); 76501e04c3fSmrg } 76601e04c3fSmrg /* Finally this is the set of effectively bound arrays */ 76701e04c3fSmrg binding->_EffOffset = (GLintptr)ptr; 76801e04c3fSmrg /* The bound arrays past the VERT_ATTRIB_{POS,GENERIC0} mapping. */ 76901e04c3fSmrg binding->_EffBoundArrays = 77001e04c3fSmrg _mesa_vao_enable_to_vp_inputs(mode, eff_bound_arrays); 77101e04c3fSmrg 77201e04c3fSmrg /* Mark all the effective bound arrays as processed. */ 77301e04c3fSmrg mask &= ~eff_bound_arrays; 77401e04c3fSmrg } 775af69d88dSmrg } 7764a49301eSmrg 77701e04c3fSmrg#ifndef NDEBUG 77801e04c3fSmrg /* Make sure the above code works as expected. */ 77901e04c3fSmrg for (gl_vert_attrib attr = 0; attr < VERT_ATTRIB_MAX; ++attr) { 78001e04c3fSmrg /* Query the original api defined attrib/binding information ... */ 78101e04c3fSmrg const unsigned char *const map =_mesa_vao_attribute_map[mode]; 782a8bb7a65Smaya if (vao->Enabled & VERT_BIT(map[attr])) { 783a8bb7a65Smaya const struct gl_array_attributes *attrib = 784a8bb7a65Smaya &vao->VertexAttrib[map[attr]]; 78501e04c3fSmrg const struct gl_vertex_buffer_binding *binding = 78601e04c3fSmrg &vao->BufferBinding[attrib->BufferBindingIndex]; 78701e04c3fSmrg /* ... and compare that with the computed attrib/binding */ 78801e04c3fSmrg const struct gl_vertex_buffer_binding *binding2 = 78901e04c3fSmrg &vao->BufferBinding[attrib->_EffBufferBindingIndex]; 79001e04c3fSmrg assert(binding->Stride == binding2->Stride); 79101e04c3fSmrg assert(binding->InstanceDivisor == binding2->InstanceDivisor); 79201e04c3fSmrg assert(binding->BufferObj == binding2->BufferObj); 7937ec681f3Smrg if (binding->BufferObj) { 79401e04c3fSmrg assert(attrib->_EffRelativeOffset <= MaxRelativeOffset); 79501e04c3fSmrg assert(binding->Offset + attrib->RelativeOffset == 79601e04c3fSmrg binding2->_EffOffset + attrib->_EffRelativeOffset); 79701e04c3fSmrg } else { 79801e04c3fSmrg assert(attrib->_EffRelativeOffset < binding->Stride); 79901e04c3fSmrg assert((GLintptr)attrib->Ptr == 80001e04c3fSmrg binding2->_EffOffset + attrib->_EffRelativeOffset); 80101e04c3fSmrg } 80201e04c3fSmrg } 80301e04c3fSmrg } 80401e04c3fSmrg#endif 805af69d88dSmrg} 806af69d88dSmrg 807af69d88dSmrg 808af69d88dSmrgvoid 80901e04c3fSmrg_mesa_set_vao_immutable(struct gl_context *ctx, 81001e04c3fSmrg struct gl_vertex_array_object *vao) 811af69d88dSmrg{ 81201e04c3fSmrg _mesa_update_vao_derived_arrays(ctx, vao); 81301e04c3fSmrg vao->NewArrays = 0; 81401e04c3fSmrg vao->SharedAndImmutable = true; 81501e04c3fSmrg} 816af69d88dSmrg 817af69d88dSmrg 81801e04c3fSmrgbool 81901e04c3fSmrg_mesa_all_varyings_in_vbos(const struct gl_vertex_array_object *vao) 82001e04c3fSmrg{ 82101e04c3fSmrg /* Walk those enabled arrays that have the default vbo attached */ 822a8bb7a65Smaya GLbitfield mask = vao->Enabled & ~vao->VertexAttribBufferMask; 823af69d88dSmrg 82401e04c3fSmrg while (mask) { 82501e04c3fSmrg /* Do not use u_bit_scan64 as we can walk multiple 82601e04c3fSmrg * attrib arrays at once 82701e04c3fSmrg */ 82801e04c3fSmrg const int i = ffs(mask) - 1; 82901e04c3fSmrg const struct gl_array_attributes *attrib_array = 83001e04c3fSmrg &vao->VertexAttrib[i]; 83101e04c3fSmrg const struct gl_vertex_buffer_binding *buffer_binding = 83201e04c3fSmrg &vao->BufferBinding[attrib_array->BufferBindingIndex]; 83301e04c3fSmrg 83401e04c3fSmrg /* We have already masked out vao->VertexAttribBufferMask */ 8357ec681f3Smrg assert(!buffer_binding->BufferObj); 83601e04c3fSmrg 83701e04c3fSmrg /* Bail out once we find the first non vbo with a non zero stride */ 83801e04c3fSmrg if (buffer_binding->Stride != 0) 83901e04c3fSmrg return false; 84001e04c3fSmrg 84101e04c3fSmrg /* Note that we cannot use the xor variant since the _BoundArray mask 84201e04c3fSmrg * may contain array attributes that are bound but not enabled. 84301e04c3fSmrg */ 84401e04c3fSmrg mask &= ~buffer_binding->_BoundArrays; 845af69d88dSmrg } 84601e04c3fSmrg 84701e04c3fSmrg return true; 848c1f859d4Smrg} 849c1f859d4Smrg 85001e04c3fSmrgbool 85101e04c3fSmrg_mesa_all_buffers_are_unmapped(const struct gl_vertex_array_object *vao) 85201e04c3fSmrg{ 85301e04c3fSmrg /* Walk the enabled arrays that have a vbo attached */ 854a8bb7a65Smaya GLbitfield mask = vao->Enabled & vao->VertexAttribBufferMask; 85501e04c3fSmrg 85601e04c3fSmrg while (mask) { 85701e04c3fSmrg const int i = ffs(mask) - 1; 85801e04c3fSmrg const struct gl_array_attributes *attrib_array = 85901e04c3fSmrg &vao->VertexAttrib[i]; 86001e04c3fSmrg const struct gl_vertex_buffer_binding *buffer_binding = 86101e04c3fSmrg &vao->BufferBinding[attrib_array->BufferBindingIndex]; 86201e04c3fSmrg 86301e04c3fSmrg /* We have already masked with vao->VertexAttribBufferMask */ 8647ec681f3Smrg assert(buffer_binding->BufferObj); 86501e04c3fSmrg 86601e04c3fSmrg /* Bail out once we find the first disallowed mapping */ 86701e04c3fSmrg if (_mesa_check_disallowed_mapping(buffer_binding->BufferObj)) 86801e04c3fSmrg return false; 86901e04c3fSmrg 87001e04c3fSmrg /* We have handled everything that is bound to this buffer_binding. */ 87101e04c3fSmrg mask &= ~buffer_binding->_BoundArrays; 87201e04c3fSmrg } 87301e04c3fSmrg 87401e04c3fSmrg return true; 87501e04c3fSmrg} 876c1f859d4Smrg 877a8bb7a65Smaya 878a8bb7a65Smaya/** 879a8bb7a65Smaya * Map buffer objects used in attribute arrays. 880a8bb7a65Smaya */ 881a8bb7a65Smayavoid 882a8bb7a65Smaya_mesa_vao_map_arrays(struct gl_context *ctx, struct gl_vertex_array_object *vao, 883a8bb7a65Smaya GLbitfield access) 884a8bb7a65Smaya{ 885a8bb7a65Smaya GLbitfield mask = vao->Enabled & vao->VertexAttribBufferMask; 886a8bb7a65Smaya while (mask) { 887a8bb7a65Smaya /* Do not use u_bit_scan as we can walk multiple attrib arrays at once */ 888a8bb7a65Smaya const gl_vert_attrib attr = ffs(mask) - 1; 889a8bb7a65Smaya const GLubyte bindex = vao->VertexAttrib[attr].BufferBindingIndex; 890a8bb7a65Smaya struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[bindex]; 891a8bb7a65Smaya mask &= ~binding->_BoundArrays; 892a8bb7a65Smaya 893a8bb7a65Smaya struct gl_buffer_object *bo = binding->BufferObj; 8947ec681f3Smrg assert(bo); 895a8bb7a65Smaya if (_mesa_bufferobj_mapped(bo, MAP_INTERNAL)) 896a8bb7a65Smaya continue; 897a8bb7a65Smaya 898a8bb7a65Smaya ctx->Driver.MapBufferRange(ctx, 0, bo->Size, access, bo, MAP_INTERNAL); 899a8bb7a65Smaya } 900a8bb7a65Smaya} 901a8bb7a65Smaya 902a8bb7a65Smaya 903a8bb7a65Smaya/** 904a8bb7a65Smaya * Map buffer objects used in the vao, attribute arrays and index buffer. 905a8bb7a65Smaya */ 906a8bb7a65Smayavoid 907a8bb7a65Smaya_mesa_vao_map(struct gl_context *ctx, struct gl_vertex_array_object *vao, 908a8bb7a65Smaya GLbitfield access) 909a8bb7a65Smaya{ 910a8bb7a65Smaya struct gl_buffer_object *bo = vao->IndexBufferObj; 911a8bb7a65Smaya 912a8bb7a65Smaya /* map the index buffer, if there is one, and not already mapped */ 9137ec681f3Smrg if (bo && !_mesa_bufferobj_mapped(bo, MAP_INTERNAL)) 914a8bb7a65Smaya ctx->Driver.MapBufferRange(ctx, 0, bo->Size, access, bo, MAP_INTERNAL); 915a8bb7a65Smaya 916a8bb7a65Smaya _mesa_vao_map_arrays(ctx, vao, access); 917a8bb7a65Smaya} 918a8bb7a65Smaya 919a8bb7a65Smaya 920a8bb7a65Smaya/** 921a8bb7a65Smaya * Unmap buffer objects used in attribute arrays. 922a8bb7a65Smaya */ 923a8bb7a65Smayavoid 924a8bb7a65Smaya_mesa_vao_unmap_arrays(struct gl_context *ctx, 925a8bb7a65Smaya struct gl_vertex_array_object *vao) 926a8bb7a65Smaya{ 927a8bb7a65Smaya GLbitfield mask = vao->Enabled & vao->VertexAttribBufferMask; 928a8bb7a65Smaya while (mask) { 929a8bb7a65Smaya /* Do not use u_bit_scan as we can walk multiple attrib arrays at once */ 930a8bb7a65Smaya const gl_vert_attrib attr = ffs(mask) - 1; 931a8bb7a65Smaya const GLubyte bindex = vao->VertexAttrib[attr].BufferBindingIndex; 932a8bb7a65Smaya struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[bindex]; 933a8bb7a65Smaya mask &= ~binding->_BoundArrays; 934a8bb7a65Smaya 935a8bb7a65Smaya struct gl_buffer_object *bo = binding->BufferObj; 9367ec681f3Smrg assert(bo); 937a8bb7a65Smaya if (!_mesa_bufferobj_mapped(bo, MAP_INTERNAL)) 938a8bb7a65Smaya continue; 939a8bb7a65Smaya 940a8bb7a65Smaya ctx->Driver.UnmapBuffer(ctx, bo, MAP_INTERNAL); 941a8bb7a65Smaya } 942a8bb7a65Smaya} 943a8bb7a65Smaya 944a8bb7a65Smaya 945a8bb7a65Smaya/** 946a8bb7a65Smaya * Unmap buffer objects used in the vao, attribute arrays and index buffer. 947a8bb7a65Smaya */ 948a8bb7a65Smayavoid 949a8bb7a65Smaya_mesa_vao_unmap(struct gl_context *ctx, struct gl_vertex_array_object *vao) 950a8bb7a65Smaya{ 951a8bb7a65Smaya struct gl_buffer_object *bo = vao->IndexBufferObj; 952a8bb7a65Smaya 953a8bb7a65Smaya /* unmap the index buffer, if there is one, and still mapped */ 9547ec681f3Smrg if (bo && _mesa_bufferobj_mapped(bo, MAP_INTERNAL)) 955a8bb7a65Smaya ctx->Driver.UnmapBuffer(ctx, bo, MAP_INTERNAL); 956a8bb7a65Smaya 957a8bb7a65Smaya _mesa_vao_unmap_arrays(ctx, vao); 958a8bb7a65Smaya} 959a8bb7a65Smaya 960a8bb7a65Smaya 9617117f1b4Smrg/**********************************************************************/ 9627117f1b4Smrg/* API Functions */ 9637117f1b4Smrg/**********************************************************************/ 9647117f1b4Smrg 9654a49301eSmrg 9667117f1b4Smrg/** 96701e04c3fSmrg * ARB version of glBindVertexArray() 9687117f1b4Smrg */ 96901e04c3fSmrgstatic ALWAYS_INLINE void 97001e04c3fSmrgbind_vertex_array(struct gl_context *ctx, GLuint id, bool no_error) 9717117f1b4Smrg{ 97201e04c3fSmrg struct gl_vertex_array_object *const oldObj = ctx->Array.VAO; 973af69d88dSmrg struct gl_vertex_array_object *newObj = NULL; 9747117f1b4Smrg 97501e04c3fSmrg assert(oldObj != NULL); 9767117f1b4Smrg 97701e04c3fSmrg if (oldObj->Name == id) 9787117f1b4Smrg return; /* rebinding the same array object- no change */ 9797117f1b4Smrg 9807117f1b4Smrg /* 9814a49301eSmrg * Get pointer to new array object (newObj) 9827117f1b4Smrg */ 9837117f1b4Smrg if (id == 0) { 9847117f1b4Smrg /* The spec says there is no array object named 0, but we use 9857117f1b4Smrg * one internally because it simplifies things. 9867117f1b4Smrg */ 987af69d88dSmrg newObj = ctx->Array.DefaultVAO; 9887117f1b4Smrg } 9897117f1b4Smrg else { 9907117f1b4Smrg /* non-default array object */ 991af69d88dSmrg newObj = _mesa_lookup_vao(ctx, id); 99201e04c3fSmrg if (!no_error && !newObj) { 99301e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 99401e04c3fSmrg "glBindVertexArray(non-gen name)"); 99501e04c3fSmrg return; 9967117f1b4Smrg } 997af69d88dSmrg 99801e04c3fSmrg newObj->EverBound = GL_TRUE; 999af69d88dSmrg } 1000af69d88dSmrg 100101e04c3fSmrg /* The _DrawArrays pointer is pointing at the VAO being unbound and 100201e04c3fSmrg * that VAO may be in the process of being deleted. If it's not going 100301e04c3fSmrg * to be deleted, this will have no effect, because the pointer needs 100401e04c3fSmrg * to be updated by the VBO module anyway. 100501e04c3fSmrg * 100601e04c3fSmrg * Before the VBO module can update the pointer, we have to set it 100701e04c3fSmrg * to NULL for drivers not to set up arrays which are not bound, 100801e04c3fSmrg * or to prevent a crash if the VAO being unbound is going to be 100901e04c3fSmrg * deleted. 101001e04c3fSmrg */ 101101e04c3fSmrg _mesa_set_draw_vao(ctx, ctx->Array._EmptyVAO, 0); 10127117f1b4Smrg 1013af69d88dSmrg _mesa_reference_vao(ctx, &ctx->Array.VAO, newObj); 10147ec681f3Smrg 10157ec681f3Smrg /* Update the valid-to-render state if binding on unbinding default VAO 10167ec681f3Smrg * if drawing with the default VAO is invalid. 10177ec681f3Smrg */ 10187ec681f3Smrg if (ctx->API == API_OPENGL_CORE && 10197ec681f3Smrg (oldObj == ctx->Array.DefaultVAO) != (newObj == ctx->Array.DefaultVAO)) 10207ec681f3Smrg _mesa_update_valid_to_render_state(ctx); 10214a49301eSmrg} 10224a49301eSmrg 10234a49301eSmrg 10244a49301eSmrgvoid GLAPIENTRY 102501e04c3fSmrg_mesa_BindVertexArray_no_error(GLuint id) 10264a49301eSmrg{ 10274a49301eSmrg GET_CURRENT_CONTEXT(ctx); 102801e04c3fSmrg bind_vertex_array(ctx, id, true); 10294a49301eSmrg} 10304a49301eSmrg 10314a49301eSmrg 10324a49301eSmrgvoid GLAPIENTRY 103301e04c3fSmrg_mesa_BindVertexArray(GLuint id) 10344a49301eSmrg{ 10354a49301eSmrg GET_CURRENT_CONTEXT(ctx); 103601e04c3fSmrg bind_vertex_array(ctx, id, false); 10377117f1b4Smrg} 10387117f1b4Smrg 10397117f1b4Smrg 10407117f1b4Smrg/** 10417117f1b4Smrg * Delete a set of array objects. 1042af69d88dSmrg * 10437117f1b4Smrg * \param n Number of array objects to delete. 10447117f1b4Smrg * \param ids Array of \c n array object IDs. 10457117f1b4Smrg */ 104601e04c3fSmrgstatic void 104701e04c3fSmrgdelete_vertex_arrays(struct gl_context *ctx, GLsizei n, const GLuint *ids) 10487117f1b4Smrg{ 10497117f1b4Smrg GLsizei i; 10507117f1b4Smrg 10517117f1b4Smrg for (i = 0; i < n; i++) { 105201e04c3fSmrg /* IDs equal to 0 should be silently ignored. */ 105301e04c3fSmrg if (!ids[i]) 105401e04c3fSmrg continue; 105501e04c3fSmrg 1056af69d88dSmrg struct gl_vertex_array_object *obj = _mesa_lookup_vao(ctx, ids[i]); 10577117f1b4Smrg 105801e04c3fSmrg if (obj) { 105901e04c3fSmrg assert(obj->Name == ids[i]); 10607117f1b4Smrg 106101e04c3fSmrg /* If the array object is currently bound, the spec says "the binding 106201e04c3fSmrg * for that object reverts to zero and the default vertex array 106301e04c3fSmrg * becomes current." 106401e04c3fSmrg */ 106501e04c3fSmrg if (obj == ctx->Array.VAO) 106601e04c3fSmrg _mesa_BindVertexArray_no_error(0); 10677117f1b4Smrg 106801e04c3fSmrg /* The ID is immediately freed for re-use */ 106901e04c3fSmrg _mesa_HashRemoveLocked(ctx->Array.Objects, obj->Name); 107001e04c3fSmrg 107101e04c3fSmrg if (ctx->Array.LastLookedUpVAO == obj) 107201e04c3fSmrg _mesa_reference_vao(ctx, &ctx->Array.LastLookedUpVAO, NULL); 107301e04c3fSmrg if (ctx->Array._DrawVAO == obj) 107401e04c3fSmrg _mesa_set_draw_vao(ctx, ctx->Array._EmptyVAO, 0); 10754a49301eSmrg 10767ec681f3Smrg /* Unreference the array object. 10774a49301eSmrg * If refcount hits zero, the object will be deleted. 10784a49301eSmrg */ 1079af69d88dSmrg _mesa_reference_vao(ctx, &obj, NULL); 10807117f1b4Smrg } 10817117f1b4Smrg } 10827117f1b4Smrg} 10837117f1b4Smrg 10847117f1b4Smrg 108501e04c3fSmrgvoid GLAPIENTRY 108601e04c3fSmrg_mesa_DeleteVertexArrays_no_error(GLsizei n, const GLuint *ids) 108701e04c3fSmrg{ 108801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 108901e04c3fSmrg delete_vertex_arrays(ctx, n, ids); 109001e04c3fSmrg} 109101e04c3fSmrg 109201e04c3fSmrg 109301e04c3fSmrgvoid GLAPIENTRY 109401e04c3fSmrg_mesa_DeleteVertexArrays(GLsizei n, const GLuint *ids) 109501e04c3fSmrg{ 109601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 109701e04c3fSmrg 109801e04c3fSmrg if (n < 0) { 109901e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteVertexArray(n)"); 110001e04c3fSmrg return; 110101e04c3fSmrg } 110201e04c3fSmrg 110301e04c3fSmrg delete_vertex_arrays(ctx, n, ids); 110401e04c3fSmrg} 110501e04c3fSmrg 110601e04c3fSmrg 11077117f1b4Smrg/** 11087117f1b4Smrg * Generate a set of unique array object IDs and store them in \c arrays. 110901e04c3fSmrg * Helper for _mesa_GenVertexArrays() and _mesa_CreateVertexArrays() 111001e04c3fSmrg * below. 111101e04c3fSmrg * 11127117f1b4Smrg * \param n Number of IDs to generate. 11137117f1b4Smrg * \param arrays Array of \c n locations to store the IDs. 111401e04c3fSmrg * \param create Indicates that the objects should also be created. 111501e04c3fSmrg * \param func The name of the GL entry point. 11167117f1b4Smrg */ 1117af69d88dSmrgstatic void 111801e04c3fSmrggen_vertex_arrays(struct gl_context *ctx, GLsizei n, GLuint *arrays, 111901e04c3fSmrg bool create, const char *func) 11207117f1b4Smrg{ 11217117f1b4Smrg GLint i; 11227117f1b4Smrg 112301e04c3fSmrg if (!arrays) 11247117f1b4Smrg return; 11257117f1b4Smrg 11267ec681f3Smrg _mesa_HashFindFreeKeys(ctx->Array.Objects, arrays, n); 11277117f1b4Smrg 112801e04c3fSmrg /* For the sake of simplicity we create the array objects in both 112901e04c3fSmrg * the Gen* and Create* cases. The only difference is the value of 113001e04c3fSmrg * EverBound, which is set to true in the Create* case. 113101e04c3fSmrg */ 11327117f1b4Smrg for (i = 0; i < n; i++) { 1133af69d88dSmrg struct gl_vertex_array_object *obj; 11347117f1b4Smrg 11357ec681f3Smrg obj = _mesa_new_vao(ctx, arrays[i]); 11367117f1b4Smrg if (!obj) { 113701e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); 11387117f1b4Smrg return; 11397117f1b4Smrg } 114001e04c3fSmrg obj->EverBound = create; 11417ec681f3Smrg _mesa_HashInsertLocked(ctx->Array.Objects, obj->Name, obj, true); 11427117f1b4Smrg } 11434a49301eSmrg} 11444a49301eSmrg 11454a49301eSmrg 114601e04c3fSmrgstatic void 114701e04c3fSmrggen_vertex_arrays_err(struct gl_context *ctx, GLsizei n, GLuint *arrays, 114801e04c3fSmrg bool create, const char *func) 114901e04c3fSmrg{ 115001e04c3fSmrg if (n < 0) { 115101e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func); 115201e04c3fSmrg return; 115301e04c3fSmrg } 115401e04c3fSmrg 115501e04c3fSmrg gen_vertex_arrays(ctx, n, arrays, create, func); 115601e04c3fSmrg} 115701e04c3fSmrg 115801e04c3fSmrg 11594a49301eSmrg/** 11604a49301eSmrg * ARB version of glGenVertexArrays() 11614a49301eSmrg * All arrays will be required to live in VBOs. 11624a49301eSmrg */ 116301e04c3fSmrgvoid GLAPIENTRY 116401e04c3fSmrg_mesa_GenVertexArrays_no_error(GLsizei n, GLuint *arrays) 116501e04c3fSmrg{ 116601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 116701e04c3fSmrg gen_vertex_arrays(ctx, n, arrays, false, "glGenVertexArrays"); 116801e04c3fSmrg} 116901e04c3fSmrg 117001e04c3fSmrg 11714a49301eSmrgvoid GLAPIENTRY 11724a49301eSmrg_mesa_GenVertexArrays(GLsizei n, GLuint *arrays) 11734a49301eSmrg{ 11744a49301eSmrg GET_CURRENT_CONTEXT(ctx); 117501e04c3fSmrg gen_vertex_arrays_err(ctx, n, arrays, false, "glGenVertexArrays"); 11764a49301eSmrg} 11774a49301eSmrg 11787117f1b4Smrg 11794a49301eSmrg/** 118001e04c3fSmrg * ARB_direct_state_access 118101e04c3fSmrg * Generates ID's and creates the array objects. 11824a49301eSmrg */ 11834a49301eSmrgvoid GLAPIENTRY 118401e04c3fSmrg_mesa_CreateVertexArrays_no_error(GLsizei n, GLuint *arrays) 11854a49301eSmrg{ 11864a49301eSmrg GET_CURRENT_CONTEXT(ctx); 118701e04c3fSmrg gen_vertex_arrays(ctx, n, arrays, true, "glCreateVertexArrays"); 118801e04c3fSmrg} 118901e04c3fSmrg 119001e04c3fSmrg 119101e04c3fSmrgvoid GLAPIENTRY 119201e04c3fSmrg_mesa_CreateVertexArrays(GLsizei n, GLuint *arrays) 119301e04c3fSmrg{ 119401e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 119501e04c3fSmrg gen_vertex_arrays_err(ctx, n, arrays, true, "glCreateVertexArrays"); 11967117f1b4Smrg} 11977117f1b4Smrg 11987117f1b4Smrg 11997117f1b4Smrg/** 12007117f1b4Smrg * Determine if ID is the name of an array object. 1201af69d88dSmrg * 12027117f1b4Smrg * \param id ID of the potential array object. 1203af69d88dSmrg * \return \c GL_TRUE if \c id is the name of a array object, 12047117f1b4Smrg * \c GL_FALSE otherwise. 12057117f1b4Smrg */ 12067117f1b4SmrgGLboolean GLAPIENTRY 1207af69d88dSmrg_mesa_IsVertexArray( GLuint id ) 12087117f1b4Smrg{ 1209af69d88dSmrg struct gl_vertex_array_object * obj; 12107117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 12117117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 12127117f1b4Smrg 1213af69d88dSmrg obj = _mesa_lookup_vao(ctx, id); 12147117f1b4Smrg 121501e04c3fSmrg return obj != NULL && obj->EverBound; 121601e04c3fSmrg} 121701e04c3fSmrg 121801e04c3fSmrg 121901e04c3fSmrg/** 122001e04c3fSmrg * Sets the element array buffer binding of a vertex array object. 122101e04c3fSmrg * 122201e04c3fSmrg * This is the ARB_direct_state_access equivalent of 122301e04c3fSmrg * glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer). 122401e04c3fSmrg */ 122501e04c3fSmrgstatic ALWAYS_INLINE void 122601e04c3fSmrgvertex_array_element_buffer(struct gl_context *ctx, GLuint vaobj, GLuint buffer, 122701e04c3fSmrg bool no_error) 122801e04c3fSmrg{ 122901e04c3fSmrg struct gl_vertex_array_object *vao; 123001e04c3fSmrg struct gl_buffer_object *bufObj; 123101e04c3fSmrg 123201e04c3fSmrg ASSERT_OUTSIDE_BEGIN_END(ctx); 123301e04c3fSmrg 123401e04c3fSmrg if (!no_error) { 123501e04c3fSmrg /* The GL_ARB_direct_state_access specification says: 123601e04c3fSmrg * 123701e04c3fSmrg * "An INVALID_OPERATION error is generated by 123801e04c3fSmrg * VertexArrayElementBuffer if <vaobj> is not [compatibility profile: 123901e04c3fSmrg * zero or] the name of an existing vertex array object." 124001e04c3fSmrg */ 12417ec681f3Smrg vao =_mesa_lookup_vao_err(ctx, vaobj, false, "glVertexArrayElementBuffer"); 124201e04c3fSmrg if (!vao) 124301e04c3fSmrg return; 124401e04c3fSmrg } else { 124501e04c3fSmrg vao = _mesa_lookup_vao(ctx, vaobj); 124601e04c3fSmrg } 124701e04c3fSmrg 124801e04c3fSmrg if (buffer != 0) { 124901e04c3fSmrg if (!no_error) { 125001e04c3fSmrg /* The GL_ARB_direct_state_access specification says: 125101e04c3fSmrg * 125201e04c3fSmrg * "An INVALID_OPERATION error is generated if <buffer> is not zero 125301e04c3fSmrg * or the name of an existing buffer object." 125401e04c3fSmrg */ 125501e04c3fSmrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, 125601e04c3fSmrg "glVertexArrayElementBuffer"); 125701e04c3fSmrg } else { 125801e04c3fSmrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 125901e04c3fSmrg } 126001e04c3fSmrg 12617ec681f3Smrg if (!bufObj) 12627ec681f3Smrg return; 12637ec681f3Smrg 1264a8bb7a65Smaya bufObj->UsageHistory |= USAGE_ELEMENT_ARRAY_BUFFER; 12657ec681f3Smrg } else { 12667ec681f3Smrg bufObj = NULL; 1267a8bb7a65Smaya } 12687ec681f3Smrg 12697ec681f3Smrg _mesa_reference_buffer_object(ctx, &vao->IndexBufferObj, bufObj); 127001e04c3fSmrg} 127101e04c3fSmrg 127201e04c3fSmrg 127301e04c3fSmrgvoid GLAPIENTRY 127401e04c3fSmrg_mesa_VertexArrayElementBuffer_no_error(GLuint vaobj, GLuint buffer) 127501e04c3fSmrg{ 127601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 127701e04c3fSmrg vertex_array_element_buffer(ctx, vaobj, buffer, true); 127801e04c3fSmrg} 127901e04c3fSmrg 128001e04c3fSmrg 128101e04c3fSmrgvoid GLAPIENTRY 128201e04c3fSmrg_mesa_VertexArrayElementBuffer(GLuint vaobj, GLuint buffer) 128301e04c3fSmrg{ 128401e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 128501e04c3fSmrg vertex_array_element_buffer(ctx, vaobj, buffer, false); 128601e04c3fSmrg} 128701e04c3fSmrg 128801e04c3fSmrg 128901e04c3fSmrgvoid GLAPIENTRY 129001e04c3fSmrg_mesa_GetVertexArrayiv(GLuint vaobj, GLenum pname, GLint *param) 129101e04c3fSmrg{ 129201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 129301e04c3fSmrg struct gl_vertex_array_object *vao; 129401e04c3fSmrg 129501e04c3fSmrg ASSERT_OUTSIDE_BEGIN_END(ctx); 129601e04c3fSmrg 129701e04c3fSmrg /* The GL_ARB_direct_state_access specification says: 129801e04c3fSmrg * 129901e04c3fSmrg * "An INVALID_OPERATION error is generated if <vaobj> is not 130001e04c3fSmrg * [compatibility profile: zero or] the name of an existing 130101e04c3fSmrg * vertex array object." 130201e04c3fSmrg */ 13037ec681f3Smrg vao = _mesa_lookup_vao_err(ctx, vaobj, false, "glGetVertexArrayiv"); 130401e04c3fSmrg if (!vao) 130501e04c3fSmrg return; 130601e04c3fSmrg 130701e04c3fSmrg /* The GL_ARB_direct_state_access specification says: 130801e04c3fSmrg * 130901e04c3fSmrg * "An INVALID_ENUM error is generated if <pname> is not 131001e04c3fSmrg * ELEMENT_ARRAY_BUFFER_BINDING." 131101e04c3fSmrg */ 131201e04c3fSmrg if (pname != GL_ELEMENT_ARRAY_BUFFER_BINDING) { 131301e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 131401e04c3fSmrg "glGetVertexArrayiv(pname != " 131501e04c3fSmrg "GL_ELEMENT_ARRAY_BUFFER_BINDING)"); 131601e04c3fSmrg return; 131701e04c3fSmrg } 131801e04c3fSmrg 13197ec681f3Smrg param[0] = vao->IndexBufferObj ? vao->IndexBufferObj->Name : 0; 13207117f1b4Smrg} 1321