arrayobj.c revision a8bb7a65
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" 467117f1b4Smrg#include "imports.h" 477117f1b4Smrg#include "context.h" 487117f1b4Smrg#include "bufferobj.h" 497117f1b4Smrg#include "arrayobj.h" 504a49301eSmrg#include "macros.h" 513464ebd5Sriastradh#include "mtypes.h" 5201e04c3fSmrg#include "state.h" 533464ebd5Sriastradh#include "varray.h" 5401e04c3fSmrg#include "util/bitscan.h" 5501e04c3fSmrg#include "util/u_atomic.h" 5601e04c3fSmrg#include "util/u_math.h" 5701e04c3fSmrg 5801e04c3fSmrg 5901e04c3fSmrgconst GLubyte 6001e04c3fSmrg_mesa_vao_attribute_map[ATTRIBUTE_MAP_MODE_MAX][VERT_ATTRIB_MAX] = 6101e04c3fSmrg{ 6201e04c3fSmrg /* ATTRIBUTE_MAP_MODE_IDENTITY 6301e04c3fSmrg * 6401e04c3fSmrg * Grab vertex processing attribute VERT_ATTRIB_POS from 6501e04c3fSmrg * the VAO attribute VERT_ATTRIB_POS, and grab vertex processing 6601e04c3fSmrg * attribute VERT_ATTRIB_GENERIC0 from the VAO attribute 6701e04c3fSmrg * VERT_ATTRIB_GENERIC0. 6801e04c3fSmrg */ 6901e04c3fSmrg { 7001e04c3fSmrg VERT_ATTRIB_POS, /* VERT_ATTRIB_POS */ 7101e04c3fSmrg VERT_ATTRIB_NORMAL, /* VERT_ATTRIB_NORMAL */ 7201e04c3fSmrg VERT_ATTRIB_COLOR0, /* VERT_ATTRIB_COLOR0 */ 7301e04c3fSmrg VERT_ATTRIB_COLOR1, /* VERT_ATTRIB_COLOR1 */ 7401e04c3fSmrg VERT_ATTRIB_FOG, /* VERT_ATTRIB_FOG */ 7501e04c3fSmrg VERT_ATTRIB_COLOR_INDEX, /* VERT_ATTRIB_COLOR_INDEX */ 7601e04c3fSmrg VERT_ATTRIB_EDGEFLAG, /* VERT_ATTRIB_EDGEFLAG */ 7701e04c3fSmrg VERT_ATTRIB_TEX0, /* VERT_ATTRIB_TEX0 */ 7801e04c3fSmrg VERT_ATTRIB_TEX1, /* VERT_ATTRIB_TEX1 */ 7901e04c3fSmrg VERT_ATTRIB_TEX2, /* VERT_ATTRIB_TEX2 */ 8001e04c3fSmrg VERT_ATTRIB_TEX3, /* VERT_ATTRIB_TEX3 */ 8101e04c3fSmrg VERT_ATTRIB_TEX4, /* VERT_ATTRIB_TEX4 */ 8201e04c3fSmrg VERT_ATTRIB_TEX5, /* VERT_ATTRIB_TEX5 */ 8301e04c3fSmrg VERT_ATTRIB_TEX6, /* VERT_ATTRIB_TEX6 */ 8401e04c3fSmrg VERT_ATTRIB_TEX7, /* VERT_ATTRIB_TEX7 */ 8501e04c3fSmrg VERT_ATTRIB_POINT_SIZE, /* VERT_ATTRIB_POINT_SIZE */ 8601e04c3fSmrg VERT_ATTRIB_GENERIC0, /* VERT_ATTRIB_GENERIC0 */ 8701e04c3fSmrg VERT_ATTRIB_GENERIC1, /* VERT_ATTRIB_GENERIC1 */ 8801e04c3fSmrg VERT_ATTRIB_GENERIC2, /* VERT_ATTRIB_GENERIC2 */ 8901e04c3fSmrg VERT_ATTRIB_GENERIC3, /* VERT_ATTRIB_GENERIC3 */ 9001e04c3fSmrg VERT_ATTRIB_GENERIC4, /* VERT_ATTRIB_GENERIC4 */ 9101e04c3fSmrg VERT_ATTRIB_GENERIC5, /* VERT_ATTRIB_GENERIC5 */ 9201e04c3fSmrg VERT_ATTRIB_GENERIC6, /* VERT_ATTRIB_GENERIC6 */ 9301e04c3fSmrg VERT_ATTRIB_GENERIC7, /* VERT_ATTRIB_GENERIC7 */ 9401e04c3fSmrg VERT_ATTRIB_GENERIC8, /* VERT_ATTRIB_GENERIC8 */ 9501e04c3fSmrg VERT_ATTRIB_GENERIC9, /* VERT_ATTRIB_GENERIC9 */ 9601e04c3fSmrg VERT_ATTRIB_GENERIC10, /* VERT_ATTRIB_GENERIC10 */ 9701e04c3fSmrg VERT_ATTRIB_GENERIC11, /* VERT_ATTRIB_GENERIC11 */ 9801e04c3fSmrg VERT_ATTRIB_GENERIC12, /* VERT_ATTRIB_GENERIC12 */ 9901e04c3fSmrg VERT_ATTRIB_GENERIC13, /* VERT_ATTRIB_GENERIC13 */ 10001e04c3fSmrg VERT_ATTRIB_GENERIC14, /* VERT_ATTRIB_GENERIC14 */ 10101e04c3fSmrg VERT_ATTRIB_GENERIC15 /* VERT_ATTRIB_GENERIC15 */ 10201e04c3fSmrg }, 10301e04c3fSmrg 10401e04c3fSmrg /* ATTRIBUTE_MAP_MODE_POSITION 10501e04c3fSmrg * 10601e04c3fSmrg * Grab vertex processing attribute VERT_ATTRIB_POS as well as 10701e04c3fSmrg * vertex processing attribute VERT_ATTRIB_GENERIC0 from the 10801e04c3fSmrg * VAO attribute VERT_ATTRIB_POS. 10901e04c3fSmrg */ 11001e04c3fSmrg { 11101e04c3fSmrg VERT_ATTRIB_POS, /* VERT_ATTRIB_POS */ 11201e04c3fSmrg VERT_ATTRIB_NORMAL, /* VERT_ATTRIB_NORMAL */ 11301e04c3fSmrg VERT_ATTRIB_COLOR0, /* VERT_ATTRIB_COLOR0 */ 11401e04c3fSmrg VERT_ATTRIB_COLOR1, /* VERT_ATTRIB_COLOR1 */ 11501e04c3fSmrg VERT_ATTRIB_FOG, /* VERT_ATTRIB_FOG */ 11601e04c3fSmrg VERT_ATTRIB_COLOR_INDEX, /* VERT_ATTRIB_COLOR_INDEX */ 11701e04c3fSmrg VERT_ATTRIB_EDGEFLAG, /* VERT_ATTRIB_EDGEFLAG */ 11801e04c3fSmrg VERT_ATTRIB_TEX0, /* VERT_ATTRIB_TEX0 */ 11901e04c3fSmrg VERT_ATTRIB_TEX1, /* VERT_ATTRIB_TEX1 */ 12001e04c3fSmrg VERT_ATTRIB_TEX2, /* VERT_ATTRIB_TEX2 */ 12101e04c3fSmrg VERT_ATTRIB_TEX3, /* VERT_ATTRIB_TEX3 */ 12201e04c3fSmrg VERT_ATTRIB_TEX4, /* VERT_ATTRIB_TEX4 */ 12301e04c3fSmrg VERT_ATTRIB_TEX5, /* VERT_ATTRIB_TEX5 */ 12401e04c3fSmrg VERT_ATTRIB_TEX6, /* VERT_ATTRIB_TEX6 */ 12501e04c3fSmrg VERT_ATTRIB_TEX7, /* VERT_ATTRIB_TEX7 */ 12601e04c3fSmrg VERT_ATTRIB_POINT_SIZE, /* VERT_ATTRIB_POINT_SIZE */ 12701e04c3fSmrg VERT_ATTRIB_POS, /* VERT_ATTRIB_GENERIC0 */ 12801e04c3fSmrg VERT_ATTRIB_GENERIC1, /* VERT_ATTRIB_GENERIC1 */ 12901e04c3fSmrg VERT_ATTRIB_GENERIC2, /* VERT_ATTRIB_GENERIC2 */ 13001e04c3fSmrg VERT_ATTRIB_GENERIC3, /* VERT_ATTRIB_GENERIC3 */ 13101e04c3fSmrg VERT_ATTRIB_GENERIC4, /* VERT_ATTRIB_GENERIC4 */ 13201e04c3fSmrg VERT_ATTRIB_GENERIC5, /* VERT_ATTRIB_GENERIC5 */ 13301e04c3fSmrg VERT_ATTRIB_GENERIC6, /* VERT_ATTRIB_GENERIC6 */ 13401e04c3fSmrg VERT_ATTRIB_GENERIC7, /* VERT_ATTRIB_GENERIC7 */ 13501e04c3fSmrg VERT_ATTRIB_GENERIC8, /* VERT_ATTRIB_GENERIC8 */ 13601e04c3fSmrg VERT_ATTRIB_GENERIC9, /* VERT_ATTRIB_GENERIC9 */ 13701e04c3fSmrg VERT_ATTRIB_GENERIC10, /* VERT_ATTRIB_GENERIC10 */ 13801e04c3fSmrg VERT_ATTRIB_GENERIC11, /* VERT_ATTRIB_GENERIC11 */ 13901e04c3fSmrg VERT_ATTRIB_GENERIC12, /* VERT_ATTRIB_GENERIC12 */ 14001e04c3fSmrg VERT_ATTRIB_GENERIC13, /* VERT_ATTRIB_GENERIC13 */ 14101e04c3fSmrg VERT_ATTRIB_GENERIC14, /* VERT_ATTRIB_GENERIC14 */ 14201e04c3fSmrg VERT_ATTRIB_GENERIC15 /* VERT_ATTRIB_GENERIC15 */ 14301e04c3fSmrg }, 14401e04c3fSmrg 14501e04c3fSmrg /* ATTRIBUTE_MAP_MODE_GENERIC0 14601e04c3fSmrg * 14701e04c3fSmrg * Grab vertex processing attribute VERT_ATTRIB_POS as well as 14801e04c3fSmrg * vertex processing attribute VERT_ATTRIB_GENERIC0 from the 14901e04c3fSmrg * VAO attribute VERT_ATTRIB_GENERIC0. 15001e04c3fSmrg */ 15101e04c3fSmrg { 15201e04c3fSmrg VERT_ATTRIB_GENERIC0, /* VERT_ATTRIB_POS */ 15301e04c3fSmrg VERT_ATTRIB_NORMAL, /* VERT_ATTRIB_NORMAL */ 15401e04c3fSmrg VERT_ATTRIB_COLOR0, /* VERT_ATTRIB_COLOR0 */ 15501e04c3fSmrg VERT_ATTRIB_COLOR1, /* VERT_ATTRIB_COLOR1 */ 15601e04c3fSmrg VERT_ATTRIB_FOG, /* VERT_ATTRIB_FOG */ 15701e04c3fSmrg VERT_ATTRIB_COLOR_INDEX, /* VERT_ATTRIB_COLOR_INDEX */ 15801e04c3fSmrg VERT_ATTRIB_EDGEFLAG, /* VERT_ATTRIB_EDGEFLAG */ 15901e04c3fSmrg VERT_ATTRIB_TEX0, /* VERT_ATTRIB_TEX0 */ 16001e04c3fSmrg VERT_ATTRIB_TEX1, /* VERT_ATTRIB_TEX1 */ 16101e04c3fSmrg VERT_ATTRIB_TEX2, /* VERT_ATTRIB_TEX2 */ 16201e04c3fSmrg VERT_ATTRIB_TEX3, /* VERT_ATTRIB_TEX3 */ 16301e04c3fSmrg VERT_ATTRIB_TEX4, /* VERT_ATTRIB_TEX4 */ 16401e04c3fSmrg VERT_ATTRIB_TEX5, /* VERT_ATTRIB_TEX5 */ 16501e04c3fSmrg VERT_ATTRIB_TEX6, /* VERT_ATTRIB_TEX6 */ 16601e04c3fSmrg VERT_ATTRIB_TEX7, /* VERT_ATTRIB_TEX7 */ 16701e04c3fSmrg VERT_ATTRIB_POINT_SIZE, /* VERT_ATTRIB_POINT_SIZE */ 16801e04c3fSmrg VERT_ATTRIB_GENERIC0, /* VERT_ATTRIB_GENERIC0 */ 16901e04c3fSmrg VERT_ATTRIB_GENERIC1, /* VERT_ATTRIB_GENERIC1 */ 17001e04c3fSmrg VERT_ATTRIB_GENERIC2, /* VERT_ATTRIB_GENERIC2 */ 17101e04c3fSmrg VERT_ATTRIB_GENERIC3, /* VERT_ATTRIB_GENERIC3 */ 17201e04c3fSmrg VERT_ATTRIB_GENERIC4, /* VERT_ATTRIB_GENERIC4 */ 17301e04c3fSmrg VERT_ATTRIB_GENERIC5, /* VERT_ATTRIB_GENERIC5 */ 17401e04c3fSmrg VERT_ATTRIB_GENERIC6, /* VERT_ATTRIB_GENERIC6 */ 17501e04c3fSmrg VERT_ATTRIB_GENERIC7, /* VERT_ATTRIB_GENERIC7 */ 17601e04c3fSmrg VERT_ATTRIB_GENERIC8, /* VERT_ATTRIB_GENERIC8 */ 17701e04c3fSmrg VERT_ATTRIB_GENERIC9, /* VERT_ATTRIB_GENERIC9 */ 17801e04c3fSmrg VERT_ATTRIB_GENERIC10, /* VERT_ATTRIB_GENERIC10 */ 17901e04c3fSmrg VERT_ATTRIB_GENERIC11, /* VERT_ATTRIB_GENERIC11 */ 18001e04c3fSmrg VERT_ATTRIB_GENERIC12, /* VERT_ATTRIB_GENERIC12 */ 18101e04c3fSmrg VERT_ATTRIB_GENERIC13, /* VERT_ATTRIB_GENERIC13 */ 18201e04c3fSmrg VERT_ATTRIB_GENERIC14, /* VERT_ATTRIB_GENERIC14 */ 18301e04c3fSmrg VERT_ATTRIB_GENERIC15 /* VERT_ATTRIB_GENERIC15 */ 18401e04c3fSmrg } 18501e04c3fSmrg}; 1867117f1b4Smrg 1877117f1b4Smrg 1887117f1b4Smrg/** 1897117f1b4Smrg * Look up the array object for the given ID. 190af69d88dSmrg * 1917117f1b4Smrg * \returns 1927117f1b4Smrg * Either a pointer to the array object with the specified ID or \c NULL for 1937117f1b4Smrg * a non-existent ID. The spec defines ID 0 as being technically 1947117f1b4Smrg * non-existent. 1957117f1b4Smrg */ 1967117f1b4Smrg 197af69d88dSmrgstruct gl_vertex_array_object * 198af69d88dSmrg_mesa_lookup_vao(struct gl_context *ctx, GLuint id) 1997117f1b4Smrg{ 20001e04c3fSmrg /* The ARB_direct_state_access specification says: 20101e04c3fSmrg * 20201e04c3fSmrg * "<vaobj> is [compatibility profile: 20301e04c3fSmrg * zero, indicating the default vertex array object, or] 20401e04c3fSmrg * the name of the vertex array object." 20501e04c3fSmrg */ 20601e04c3fSmrg if (id == 0) { 20701e04c3fSmrg if (ctx->API == API_OPENGL_COMPAT) 20801e04c3fSmrg return ctx->Array.DefaultVAO; 20901e04c3fSmrg 2104a49301eSmrg return NULL; 21101e04c3fSmrg } else { 21201e04c3fSmrg struct gl_vertex_array_object *vao; 21301e04c3fSmrg 21401e04c3fSmrg if (ctx->Array.LastLookedUpVAO && 21501e04c3fSmrg ctx->Array.LastLookedUpVAO->Name == id) { 21601e04c3fSmrg vao = ctx->Array.LastLookedUpVAO; 21701e04c3fSmrg } else { 21801e04c3fSmrg vao = (struct gl_vertex_array_object *) 21901e04c3fSmrg _mesa_HashLookupLocked(ctx->Array.Objects, id); 22001e04c3fSmrg 22101e04c3fSmrg _mesa_reference_vao(ctx, &ctx->Array.LastLookedUpVAO, vao); 22201e04c3fSmrg } 22301e04c3fSmrg 22401e04c3fSmrg return vao; 22501e04c3fSmrg } 22601e04c3fSmrg} 22701e04c3fSmrg 22801e04c3fSmrg 22901e04c3fSmrg/** 23001e04c3fSmrg * Looks up the array object for the given ID. 23101e04c3fSmrg * 23201e04c3fSmrg * Unlike _mesa_lookup_vao, this function generates a GL_INVALID_OPERATION 23301e04c3fSmrg * error if the array object does not exist. It also returns the default 23401e04c3fSmrg * array object when ctx is a compatibility profile context and id is zero. 23501e04c3fSmrg */ 23601e04c3fSmrgstruct gl_vertex_array_object * 23701e04c3fSmrg_mesa_lookup_vao_err(struct gl_context *ctx, GLuint id, const char *caller) 23801e04c3fSmrg{ 23901e04c3fSmrg /* The ARB_direct_state_access specification says: 24001e04c3fSmrg * 24101e04c3fSmrg * "<vaobj> is [compatibility profile: 24201e04c3fSmrg * zero, indicating the default vertex array object, or] 24301e04c3fSmrg * the name of the vertex array object." 24401e04c3fSmrg */ 24501e04c3fSmrg if (id == 0) { 24601e04c3fSmrg if (ctx->API == API_OPENGL_CORE) { 24701e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 24801e04c3fSmrg "%s(zero is not valid vaobj name in a core profile " 24901e04c3fSmrg "context)", caller); 25001e04c3fSmrg return NULL; 25101e04c3fSmrg } 25201e04c3fSmrg 25301e04c3fSmrg return ctx->Array.DefaultVAO; 25401e04c3fSmrg } else { 25501e04c3fSmrg struct gl_vertex_array_object *vao; 25601e04c3fSmrg 25701e04c3fSmrg if (ctx->Array.LastLookedUpVAO && 25801e04c3fSmrg ctx->Array.LastLookedUpVAO->Name == id) { 25901e04c3fSmrg vao = ctx->Array.LastLookedUpVAO; 26001e04c3fSmrg } else { 26101e04c3fSmrg vao = (struct gl_vertex_array_object *) 26201e04c3fSmrg _mesa_HashLookupLocked(ctx->Array.Objects, id); 26301e04c3fSmrg 26401e04c3fSmrg /* The ARB_direct_state_access specification says: 26501e04c3fSmrg * 26601e04c3fSmrg * "An INVALID_OPERATION error is generated if <vaobj> is not 26701e04c3fSmrg * [compatibility profile: zero or] the name of an existing 26801e04c3fSmrg * vertex array object." 26901e04c3fSmrg */ 27001e04c3fSmrg if (!vao || !vao->EverBound) { 27101e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 27201e04c3fSmrg "%s(non-existent vaobj=%u)", caller, id); 27301e04c3fSmrg return NULL; 27401e04c3fSmrg } 27501e04c3fSmrg 27601e04c3fSmrg _mesa_reference_vao(ctx, &ctx->Array.LastLookedUpVAO, vao); 27701e04c3fSmrg } 27801e04c3fSmrg 27901e04c3fSmrg return vao; 28001e04c3fSmrg } 2814a49301eSmrg} 2824a49301eSmrg 2834a49301eSmrg 2844a49301eSmrg/** 285af69d88dSmrg * For all the vertex binding points in the array object, unbind any pointers 2864a49301eSmrg * to any buffer objects (VBOs). 2874a49301eSmrg * This is done just prior to array object destruction. 2884a49301eSmrg */ 2894a49301eSmrgstatic void 290af69d88dSmrgunbind_array_object_vbos(struct gl_context *ctx, struct gl_vertex_array_object *obj) 2914a49301eSmrg{ 2924a49301eSmrg GLuint i; 2934a49301eSmrg 29401e04c3fSmrg for (i = 0; i < ARRAY_SIZE(obj->BufferBinding); i++) 29501e04c3fSmrg _mesa_reference_buffer_object(ctx, &obj->BufferBinding[i].BufferObj, NULL); 2967117f1b4Smrg} 2977117f1b4Smrg 2987117f1b4Smrg 2997117f1b4Smrg/** 3007117f1b4Smrg * Allocate and initialize a new vertex array object. 3017117f1b4Smrg */ 302af69d88dSmrgstruct gl_vertex_array_object * 303af69d88dSmrg_mesa_new_vao(struct gl_context *ctx, GLuint name) 3047117f1b4Smrg{ 305af69d88dSmrg struct gl_vertex_array_object *obj = CALLOC_STRUCT(gl_vertex_array_object); 3067117f1b4Smrg if (obj) 307af69d88dSmrg _mesa_initialize_vao(ctx, obj, name); 3087117f1b4Smrg return obj; 3097117f1b4Smrg} 3107117f1b4Smrg 3117117f1b4Smrg 3127117f1b4Smrg/** 3137117f1b4Smrg * Delete an array object. 3147117f1b4Smrg */ 3157117f1b4Smrgvoid 316af69d88dSmrg_mesa_delete_vao(struct gl_context *ctx, struct gl_vertex_array_object *obj) 3177117f1b4Smrg{ 3184a49301eSmrg unbind_array_object_vbos(ctx, obj); 319af69d88dSmrg _mesa_reference_buffer_object(ctx, &obj->IndexBufferObj, NULL); 320af69d88dSmrg free(obj->Label); 321cdc920a0Smrg free(obj); 3227117f1b4Smrg} 3237117f1b4Smrg 3247117f1b4Smrg 3254a49301eSmrg/** 326af69d88dSmrg * Set ptr to vao w/ reference counting. 327af69d88dSmrg * Note: this should only be called from the _mesa_reference_vao() 328af69d88dSmrg * inline function. 3294a49301eSmrg */ 3304a49301eSmrgvoid 331af69d88dSmrg_mesa_reference_vao_(struct gl_context *ctx, 332af69d88dSmrg struct gl_vertex_array_object **ptr, 333af69d88dSmrg struct gl_vertex_array_object *vao) 3344a49301eSmrg{ 335af69d88dSmrg assert(*ptr != vao); 3364a49301eSmrg 3374a49301eSmrg if (*ptr) { 3384a49301eSmrg /* Unreference the old array object */ 339af69d88dSmrg struct gl_vertex_array_object *oldObj = *ptr; 3404a49301eSmrg 34101e04c3fSmrg bool deleteFlag; 34201e04c3fSmrg if (oldObj->SharedAndImmutable) { 34301e04c3fSmrg deleteFlag = p_atomic_dec_zero(&oldObj->RefCount); 34401e04c3fSmrg } else { 34501e04c3fSmrg assert(oldObj->RefCount > 0); 34601e04c3fSmrg oldObj->RefCount--; 34701e04c3fSmrg deleteFlag = (oldObj->RefCount == 0); 3484a49301eSmrg } 3494a49301eSmrg 35001e04c3fSmrg if (deleteFlag) 35101e04c3fSmrg _mesa_delete_vao(ctx, oldObj); 35201e04c3fSmrg 3534a49301eSmrg *ptr = NULL; 3544a49301eSmrg } 35501e04c3fSmrg assert(!*ptr); 3564a49301eSmrg 357af69d88dSmrg if (vao) { 3584a49301eSmrg /* reference new array object */ 35901e04c3fSmrg if (vao->SharedAndImmutable) { 36001e04c3fSmrg p_atomic_inc(&vao->RefCount); 36101e04c3fSmrg } else { 36201e04c3fSmrg assert(vao->RefCount > 0); 363af69d88dSmrg vao->RefCount++; 3644a49301eSmrg } 36501e04c3fSmrg 36601e04c3fSmrg *ptr = vao; 3674a49301eSmrg } 3684a49301eSmrg} 3694a49301eSmrg 3704a49301eSmrg 37101e04c3fSmrg/** 37201e04c3fSmrg * Initialize attributes of a vertex array within a vertex array object. 37301e04c3fSmrg * \param vao the container vertex array object 37401e04c3fSmrg * \param index which array in the VAO to initialize 37501e04c3fSmrg * \param size number of components (1, 2, 3 or 4) per attribute 37601e04c3fSmrg * \param type datatype of the attribute (GL_FLOAT, GL_INT, etc). 37701e04c3fSmrg */ 3784a49301eSmrgstatic void 3793464ebd5Sriastradhinit_array(struct gl_context *ctx, 38001e04c3fSmrg struct gl_vertex_array_object *vao, 38101e04c3fSmrg gl_vert_attrib index, GLint size, GLint type) 3824a49301eSmrg{ 38301e04c3fSmrg assert(index < ARRAY_SIZE(vao->VertexAttrib)); 38401e04c3fSmrg struct gl_array_attributes *array = &vao->VertexAttrib[index]; 38501e04c3fSmrg assert(index < ARRAY_SIZE(vao->BufferBinding)); 38601e04c3fSmrg struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[index]; 387af69d88dSmrg 388a8bb7a65Smaya _mesa_set_vertex_format(&array->Format, size, type, GL_RGBA, 389a8bb7a65Smaya GL_FALSE, GL_FALSE, GL_FALSE); 3904a49301eSmrg array->Stride = 0; 3914a49301eSmrg array->Ptr = NULL; 392af69d88dSmrg array->RelativeOffset = 0; 39301e04c3fSmrg ASSERT_BITFIELD_SIZE(struct gl_array_attributes, BufferBindingIndex, 39401e04c3fSmrg VERT_ATTRIB_MAX - 1); 39501e04c3fSmrg array->BufferBindingIndex = index; 396af69d88dSmrg 397af69d88dSmrg binding->Offset = 0; 398a8bb7a65Smaya binding->Stride = array->Format._ElementSize; 399af69d88dSmrg binding->BufferObj = NULL; 40001e04c3fSmrg binding->_BoundArrays = BITFIELD_BIT(index); 401af69d88dSmrg 4024a49301eSmrg /* Vertex array buffers */ 403af69d88dSmrg _mesa_reference_buffer_object(ctx, &binding->BufferObj, 4044a49301eSmrg ctx->Shared->NullBufferObj); 4054a49301eSmrg} 4064a49301eSmrg 4074a49301eSmrg 4084a49301eSmrg/** 409af69d88dSmrg * Initialize a gl_vertex_array_object's arrays. 4104a49301eSmrg */ 4117117f1b4Smrgvoid 412af69d88dSmrg_mesa_initialize_vao(struct gl_context *ctx, 41301e04c3fSmrg struct gl_vertex_array_object *vao, 414af69d88dSmrg GLuint name) 4157117f1b4Smrg{ 4167117f1b4Smrg GLuint i; 4177117f1b4Smrg 41801e04c3fSmrg vao->Name = name; 4197117f1b4Smrg 42001e04c3fSmrg vao->RefCount = 1; 42101e04c3fSmrg vao->SharedAndImmutable = false; 4224a49301eSmrg 4234a49301eSmrg /* Init the individual arrays */ 42401e04c3fSmrg for (i = 0; i < ARRAY_SIZE(vao->VertexAttrib); i++) { 425af69d88dSmrg switch (i) { 426af69d88dSmrg case VERT_ATTRIB_NORMAL: 42701e04c3fSmrg init_array(ctx, vao, VERT_ATTRIB_NORMAL, 3, GL_FLOAT); 428af69d88dSmrg break; 429af69d88dSmrg case VERT_ATTRIB_COLOR1: 43001e04c3fSmrg init_array(ctx, vao, VERT_ATTRIB_COLOR1, 3, GL_FLOAT); 431af69d88dSmrg break; 432af69d88dSmrg case VERT_ATTRIB_FOG: 43301e04c3fSmrg init_array(ctx, vao, VERT_ATTRIB_FOG, 1, GL_FLOAT); 434af69d88dSmrg break; 435af69d88dSmrg case VERT_ATTRIB_COLOR_INDEX: 43601e04c3fSmrg init_array(ctx, vao, VERT_ATTRIB_COLOR_INDEX, 1, GL_FLOAT); 437af69d88dSmrg break; 438af69d88dSmrg case VERT_ATTRIB_EDGEFLAG: 439a8bb7a65Smaya init_array(ctx, vao, VERT_ATTRIB_EDGEFLAG, 1, GL_UNSIGNED_BYTE); 440af69d88dSmrg break; 441af69d88dSmrg case VERT_ATTRIB_POINT_SIZE: 44201e04c3fSmrg init_array(ctx, vao, VERT_ATTRIB_POINT_SIZE, 1, GL_FLOAT); 443af69d88dSmrg break; 444af69d88dSmrg default: 44501e04c3fSmrg init_array(ctx, vao, i, 4, GL_FLOAT); 446af69d88dSmrg break; 447af69d88dSmrg } 4487117f1b4Smrg } 4497117f1b4Smrg 45001e04c3fSmrg vao->_AttributeMapMode = ATTRIBUTE_MAP_MODE_IDENTITY; 45101e04c3fSmrg 45201e04c3fSmrg _mesa_reference_buffer_object(ctx, &vao->IndexBufferObj, 453af69d88dSmrg ctx->Shared->NullBufferObj); 4547117f1b4Smrg} 4557117f1b4Smrg 4567117f1b4Smrg 4577117f1b4Smrg/** 45801e04c3fSmrg * Compute the offset range for the provided binding. 45901e04c3fSmrg * 46001e04c3fSmrg * This is a helper function for the below. 4617117f1b4Smrg */ 4624a49301eSmrgstatic void 46301e04c3fSmrgcompute_vbo_offset_range(const struct gl_vertex_array_object *vao, 46401e04c3fSmrg const struct gl_vertex_buffer_binding *binding, 46501e04c3fSmrg GLsizeiptr* min, GLsizeiptr* max) 4667117f1b4Smrg{ 46701e04c3fSmrg /* The function is meant to work on VBO bindings */ 46801e04c3fSmrg assert(_mesa_is_bufferobj(binding->BufferObj)); 46901e04c3fSmrg 47001e04c3fSmrg /* Start with an inverted range of relative offsets. */ 47101e04c3fSmrg GLuint min_offset = ~(GLuint)0; 47201e04c3fSmrg GLuint max_offset = 0; 47301e04c3fSmrg 47401e04c3fSmrg /* We work on the unmapped originaly VAO array entries. */ 475a8bb7a65Smaya GLbitfield mask = vao->Enabled & binding->_BoundArrays; 47601e04c3fSmrg /* The binding should be active somehow, not to return inverted ranges */ 47701e04c3fSmrg assert(mask); 47801e04c3fSmrg while (mask) { 47901e04c3fSmrg const int i = u_bit_scan(&mask); 48001e04c3fSmrg const GLuint off = vao->VertexAttrib[i].RelativeOffset; 48101e04c3fSmrg min_offset = MIN2(off, min_offset); 48201e04c3fSmrg max_offset = MAX2(off, max_offset); 4837117f1b4Smrg } 48401e04c3fSmrg 48501e04c3fSmrg *min = binding->Offset + (GLsizeiptr)min_offset; 48601e04c3fSmrg *max = binding->Offset + (GLsizeiptr)max_offset; 4877117f1b4Smrg} 4887117f1b4Smrg 4897117f1b4Smrg 4907117f1b4Smrg/** 49101e04c3fSmrg * Update the unique binding and pos/generic0 map tracking in the vao. 49201e04c3fSmrg * 49301e04c3fSmrg * The idea is to build up information in the vao so that a consuming 49401e04c3fSmrg * backend can execute the following to set up buffer and vertex element 49501e04c3fSmrg * information: 49601e04c3fSmrg * 49701e04c3fSmrg * const GLbitfield inputs_read = VERT_BIT_ALL; // backend vp inputs 49801e04c3fSmrg * 49901e04c3fSmrg * // Attribute data is in a VBO. 50001e04c3fSmrg * GLbitfield vbomask = inputs_read & _mesa_draw_vbo_array_bits(ctx); 50101e04c3fSmrg * while (vbomask) { 50201e04c3fSmrg * // The attribute index to start pulling a binding 50301e04c3fSmrg * const gl_vert_attrib i = ffs(vbomask) - 1; 50401e04c3fSmrg * const struct gl_vertex_buffer_binding *const binding 50501e04c3fSmrg * = _mesa_draw_buffer_binding(vao, i); 50601e04c3fSmrg * 50701e04c3fSmrg * <insert code to handle the vertex buffer object at binding> 50801e04c3fSmrg * 50901e04c3fSmrg * const GLbitfield boundmask = _mesa_draw_bound_attrib_bits(binding); 51001e04c3fSmrg * GLbitfield attrmask = vbomask & boundmask; 51101e04c3fSmrg * assert(attrmask); 51201e04c3fSmrg * // Walk attributes belonging to the binding 51301e04c3fSmrg * while (attrmask) { 51401e04c3fSmrg * const gl_vert_attrib attr = u_bit_scan(&attrmask); 51501e04c3fSmrg * const struct gl_array_attributes *const attrib 51601e04c3fSmrg * = _mesa_draw_array_attrib(vao, attr); 51701e04c3fSmrg * 51801e04c3fSmrg * <insert code to handle the vertex element refering to the binding> 51901e04c3fSmrg * } 52001e04c3fSmrg * vbomask &= ~boundmask; 52101e04c3fSmrg * } 52201e04c3fSmrg * 52301e04c3fSmrg * // Process user space buffers 52401e04c3fSmrg * GLbitfield usermask = inputs_read & _mesa_draw_user_array_bits(ctx); 52501e04c3fSmrg * while (usermask) { 52601e04c3fSmrg * // The attribute index to start pulling a binding 52701e04c3fSmrg * const gl_vert_attrib i = ffs(usermask) - 1; 52801e04c3fSmrg * const struct gl_vertex_buffer_binding *const binding 52901e04c3fSmrg * = _mesa_draw_buffer_binding(vao, i); 53001e04c3fSmrg * 53101e04c3fSmrg * <insert code to handle a set of interleaved user space arrays at binding> 53201e04c3fSmrg * 53301e04c3fSmrg * const GLbitfield boundmask = _mesa_draw_bound_attrib_bits(binding); 53401e04c3fSmrg * GLbitfield attrmask = usermask & boundmask; 53501e04c3fSmrg * assert(attrmask); 53601e04c3fSmrg * // Walk interleaved attributes with a common stride and instance divisor 53701e04c3fSmrg * while (attrmask) { 53801e04c3fSmrg * const gl_vert_attrib attr = u_bit_scan(&attrmask); 53901e04c3fSmrg * const struct gl_array_attributes *const attrib 54001e04c3fSmrg * = _mesa_draw_array_attrib(vao, attr); 54101e04c3fSmrg * 54201e04c3fSmrg * <insert code to handle non vbo vertex arrays> 54301e04c3fSmrg * } 54401e04c3fSmrg * usermask &= ~boundmask; 54501e04c3fSmrg * } 54601e04c3fSmrg * 54701e04c3fSmrg * // Process values that should have better been uniforms in the application 54801e04c3fSmrg * GLbitfield curmask = inputs_read & _mesa_draw_current_bits(ctx); 54901e04c3fSmrg * while (curmask) { 55001e04c3fSmrg * const gl_vert_attrib attr = u_bit_scan(&curmask); 55101e04c3fSmrg * const struct gl_array_attributes *const attrib 55201e04c3fSmrg * = _mesa_draw_current_attrib(ctx, attr); 55301e04c3fSmrg * 55401e04c3fSmrg * <insert code to handle current values> 55501e04c3fSmrg * } 55601e04c3fSmrg * 55701e04c3fSmrg * 55801e04c3fSmrg * Note that the scan below must not incoporate any context state. 55901e04c3fSmrg * The rationale is that once a VAO is finalized it should not 56001e04c3fSmrg * be touched anymore. That means, do not incorporate the 56101e04c3fSmrg * gl_context::Array._DrawVAOEnabledAttribs bitmask into this scan. 56201e04c3fSmrg * A backend driver may further reduce the handled vertex processing 56301e04c3fSmrg * inputs based on their vertex shader inputs. But scanning for 56401e04c3fSmrg * collapsable binding points to reduce relocs is done based on the 56501e04c3fSmrg * enabled arrays. 56601e04c3fSmrg * Also VAOs may be shared between contexts due to their use in dlists 56701e04c3fSmrg * thus no context state should bleed into the VAO. 5687117f1b4Smrg */ 56901e04c3fSmrgvoid 57001e04c3fSmrg_mesa_update_vao_derived_arrays(struct gl_context *ctx, 57101e04c3fSmrg struct gl_vertex_array_object *vao) 5727117f1b4Smrg{ 57301e04c3fSmrg /* Make sure we do not run into problems with shared objects */ 57401e04c3fSmrg assert(!vao->SharedAndImmutable || vao->NewArrays == 0); 57501e04c3fSmrg 57601e04c3fSmrg /* Limit used for common binding scanning below. */ 57701e04c3fSmrg const GLsizeiptr MaxRelativeOffset = 57801e04c3fSmrg ctx->Const.MaxVertexAttribRelativeOffset; 57901e04c3fSmrg 58001e04c3fSmrg /* The gl_vertex_array_object::_AttributeMapMode denotes the way 58101e04c3fSmrg * VERT_ATTRIB_{POS,GENERIC0} mapping is done. 58201e04c3fSmrg * 58301e04c3fSmrg * This mapping is used to map between the OpenGL api visible 58401e04c3fSmrg * VERT_ATTRIB_* arrays to mesa driver arrayinputs or shader inputs. 58501e04c3fSmrg * The mapping only depends on the enabled bits of the 58601e04c3fSmrg * VERT_ATTRIB_{POS,GENERIC0} arrays and is tracked in the VAO. 58701e04c3fSmrg * 58801e04c3fSmrg * This map needs to be applied when finally translating to the bitmasks 58901e04c3fSmrg * as consumed by the driver backends. The duplicate scanning is here 59001e04c3fSmrg * can as well be done in the OpenGL API numbering without this map. 59101e04c3fSmrg */ 59201e04c3fSmrg const gl_attribute_map_mode mode = vao->_AttributeMapMode; 59301e04c3fSmrg /* Enabled array bits. */ 594a8bb7a65Smaya const GLbitfield enabled = vao->Enabled; 59501e04c3fSmrg /* VBO array bits. */ 59601e04c3fSmrg const GLbitfield vbos = vao->VertexAttribBufferMask; 59701e04c3fSmrg 59801e04c3fSmrg /* Compute and store effectively enabled and mapped vbo arrays */ 59901e04c3fSmrg vao->_EffEnabledVBO = _mesa_vao_enable_to_vp_inputs(mode, enabled & vbos); 60001e04c3fSmrg /* Walk those enabled arrays that have a real vbo attached */ 60101e04c3fSmrg GLbitfield mask = enabled; 60201e04c3fSmrg while (mask) { 60301e04c3fSmrg /* Do not use u_bit_scan as we can walk multiple attrib arrays at once */ 60401e04c3fSmrg const int i = ffs(mask) - 1; 60501e04c3fSmrg /* The binding from the first to be processed attribute. */ 60601e04c3fSmrg const GLuint bindex = vao->VertexAttrib[i].BufferBindingIndex; 60701e04c3fSmrg struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[bindex]; 60801e04c3fSmrg 60901e04c3fSmrg /* The scan goes different for user space arrays than vbos */ 61001e04c3fSmrg if (_mesa_is_bufferobj(binding->BufferObj)) { 61101e04c3fSmrg /* The bound arrays. */ 61201e04c3fSmrg const GLbitfield bound = enabled & binding->_BoundArrays; 61301e04c3fSmrg 61401e04c3fSmrg /* Start this current effective binding with the actual bound arrays */ 61501e04c3fSmrg GLbitfield eff_bound_arrays = bound; 61601e04c3fSmrg 61701e04c3fSmrg /* 61801e04c3fSmrg * If there is nothing left to scan just update the effective binding 61901e04c3fSmrg * information. If the VAO is already only using a single binding point 62001e04c3fSmrg * we end up here. So the overhead of this scan for an application 62101e04c3fSmrg * carefully preparing the VAO for draw is low. 62201e04c3fSmrg */ 6237117f1b4Smrg 62401e04c3fSmrg GLbitfield scanmask = mask & vbos & ~bound; 62501e04c3fSmrg /* Is there something left to scan? */ 62601e04c3fSmrg if (scanmask == 0) { 62701e04c3fSmrg /* Just update the back reference from the attrib to the binding and 62801e04c3fSmrg * the effective offset. 62901e04c3fSmrg */ 63001e04c3fSmrg GLbitfield attrmask = eff_bound_arrays; 63101e04c3fSmrg while (attrmask) { 63201e04c3fSmrg const int j = u_bit_scan(&attrmask); 63301e04c3fSmrg struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j]; 63401e04c3fSmrg 63501e04c3fSmrg /* Update the index into the common binding point and offset */ 63601e04c3fSmrg attrib2->_EffBufferBindingIndex = bindex; 63701e04c3fSmrg attrib2->_EffRelativeOffset = attrib2->RelativeOffset; 63801e04c3fSmrg assert(attrib2->_EffRelativeOffset <= MaxRelativeOffset); 63901e04c3fSmrg } 64001e04c3fSmrg /* Finally this is the set of effectively bound arrays with the 64101e04c3fSmrg * original binding offset. 64201e04c3fSmrg */ 64301e04c3fSmrg binding->_EffOffset = binding->Offset; 64401e04c3fSmrg /* The bound arrays past the VERT_ATTRIB_{POS,GENERIC0} mapping. */ 64501e04c3fSmrg binding->_EffBoundArrays = 64601e04c3fSmrg _mesa_vao_enable_to_vp_inputs(mode, eff_bound_arrays); 64701e04c3fSmrg 64801e04c3fSmrg } else { 64901e04c3fSmrg /* In the VBO case, scan for attribute/binding 65001e04c3fSmrg * combinations with relative bindings in the range of 65101e04c3fSmrg * [0, ctx->Const.MaxVertexAttribRelativeOffset]. 65201e04c3fSmrg * Note that this does also go beyond just interleaved arrays 65301e04c3fSmrg * as long as they use the same VBO, binding parameters and the 65401e04c3fSmrg * offsets stay within bounds that the backend still can handle. 65501e04c3fSmrg */ 65601e04c3fSmrg 65701e04c3fSmrg GLsizeiptr min_offset, max_offset; 65801e04c3fSmrg compute_vbo_offset_range(vao, binding, &min_offset, &max_offset); 65901e04c3fSmrg assert(max_offset <= min_offset + MaxRelativeOffset); 66001e04c3fSmrg 66101e04c3fSmrg /* Now scan. */ 66201e04c3fSmrg while (scanmask) { 66301e04c3fSmrg /* Do not use u_bit_scan as we can walk multiple 66401e04c3fSmrg * attrib arrays at once 66501e04c3fSmrg */ 66601e04c3fSmrg const int j = ffs(scanmask) - 1; 66701e04c3fSmrg const struct gl_array_attributes *attrib2 = 66801e04c3fSmrg &vao->VertexAttrib[j]; 66901e04c3fSmrg const struct gl_vertex_buffer_binding *binding2 = 67001e04c3fSmrg &vao->BufferBinding[attrib2->BufferBindingIndex]; 67101e04c3fSmrg 67201e04c3fSmrg /* Remove those attrib bits from the mask that are bound to the 67301e04c3fSmrg * same effective binding point. 67401e04c3fSmrg */ 67501e04c3fSmrg const GLbitfield bound2 = enabled & binding2->_BoundArrays; 67601e04c3fSmrg scanmask &= ~bound2; 67701e04c3fSmrg 67801e04c3fSmrg /* Check if we have an identical binding */ 67901e04c3fSmrg if (binding->Stride != binding2->Stride) 68001e04c3fSmrg continue; 68101e04c3fSmrg if (binding->InstanceDivisor != binding2->InstanceDivisor) 68201e04c3fSmrg continue; 68301e04c3fSmrg if (binding->BufferObj != binding2->BufferObj) 68401e04c3fSmrg continue; 68501e04c3fSmrg /* Check if we can fold both bindings into a common binding */ 68601e04c3fSmrg GLsizeiptr min_offset2, max_offset2; 68701e04c3fSmrg compute_vbo_offset_range(vao, binding2, 68801e04c3fSmrg &min_offset2, &max_offset2); 68901e04c3fSmrg /* If the relative offset is within the limits ... */ 69001e04c3fSmrg if (min_offset + MaxRelativeOffset < max_offset2) 69101e04c3fSmrg continue; 69201e04c3fSmrg if (min_offset2 + MaxRelativeOffset < max_offset) 69301e04c3fSmrg continue; 69401e04c3fSmrg /* ... add this array to the effective binding */ 69501e04c3fSmrg eff_bound_arrays |= bound2; 69601e04c3fSmrg min_offset = MIN2(min_offset, min_offset2); 69701e04c3fSmrg max_offset = MAX2(max_offset, max_offset2); 69801e04c3fSmrg assert(max_offset <= min_offset + MaxRelativeOffset); 69901e04c3fSmrg } 70001e04c3fSmrg 70101e04c3fSmrg /* Update the back reference from the attrib to the binding */ 70201e04c3fSmrg GLbitfield attrmask = eff_bound_arrays; 70301e04c3fSmrg while (attrmask) { 70401e04c3fSmrg const int j = u_bit_scan(&attrmask); 70501e04c3fSmrg struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j]; 70601e04c3fSmrg const struct gl_vertex_buffer_binding *binding2 = 70701e04c3fSmrg &vao->BufferBinding[attrib2->BufferBindingIndex]; 70801e04c3fSmrg 70901e04c3fSmrg /* Update the index into the common binding point and offset */ 71001e04c3fSmrg attrib2->_EffBufferBindingIndex = bindex; 71101e04c3fSmrg attrib2->_EffRelativeOffset = 71201e04c3fSmrg binding2->Offset + attrib2->RelativeOffset - min_offset; 71301e04c3fSmrg assert(attrib2->_EffRelativeOffset <= MaxRelativeOffset); 71401e04c3fSmrg } 71501e04c3fSmrg /* Finally this is the set of effectively bound arrays */ 71601e04c3fSmrg binding->_EffOffset = min_offset; 71701e04c3fSmrg /* The bound arrays past the VERT_ATTRIB_{POS,GENERIC0} mapping. */ 71801e04c3fSmrg binding->_EffBoundArrays = 71901e04c3fSmrg _mesa_vao_enable_to_vp_inputs(mode, eff_bound_arrays); 72001e04c3fSmrg } 7217117f1b4Smrg 72201e04c3fSmrg /* Mark all the effective bound arrays as processed. */ 72301e04c3fSmrg mask &= ~eff_bound_arrays; 7244a49301eSmrg 72501e04c3fSmrg } else { 72601e04c3fSmrg /* Scanning of common bindings for user space arrays. 72701e04c3fSmrg */ 728af69d88dSmrg 72901e04c3fSmrg const struct gl_array_attributes *attrib = &vao->VertexAttrib[i]; 73001e04c3fSmrg const GLbitfield bound = VERT_BIT(i); 731af69d88dSmrg 73201e04c3fSmrg /* Note that user space array pointers can only happen using a one 73301e04c3fSmrg * to one binding point to array mapping. 73401e04c3fSmrg * The OpenGL 4.x/ARB_vertex_attrib_binding api does not support 73501e04c3fSmrg * user space arrays collected at multiple binding points. 73601e04c3fSmrg * The only provider of user space interleaved arrays with a single 73701e04c3fSmrg * binding point is the mesa internal vbo module. But that one 73801e04c3fSmrg * provides a perfect interleaved set of arrays. 73901e04c3fSmrg * 74001e04c3fSmrg * If this would not be true we would potentially get attribute arrays 74101e04c3fSmrg * with user space pointers that may not lie within the 74201e04c3fSmrg * MaxRelativeOffset range but still attached to a single binding. 74301e04c3fSmrg * Then we would need to store the effective attribute and binding 74401e04c3fSmrg * grouping information in a seperate array beside 74501e04c3fSmrg * gl_array_attributes/gl_vertex_buffer_binding. 74601e04c3fSmrg */ 747a8bb7a65Smaya assert(util_bitcount(binding->_BoundArrays & vao->Enabled) == 1 748a8bb7a65Smaya || (vao->Enabled & ~binding->_BoundArrays) == 0); 749af69d88dSmrg 75001e04c3fSmrg /* Start this current effective binding with the array */ 75101e04c3fSmrg GLbitfield eff_bound_arrays = bound; 7524a49301eSmrg 75301e04c3fSmrg const GLubyte *ptr = attrib->Ptr; 754a8bb7a65Smaya unsigned vertex_end = attrib->Format._ElementSize; 7554a49301eSmrg 75601e04c3fSmrg /* Walk other user space arrays and see which are interleaved 75701e04c3fSmrg * using the same binding parameters. 75801e04c3fSmrg */ 75901e04c3fSmrg GLbitfield scanmask = mask & ~vbos & ~bound; 76001e04c3fSmrg while (scanmask) { 76101e04c3fSmrg const int j = u_bit_scan(&scanmask); 76201e04c3fSmrg const struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j]; 76301e04c3fSmrg const struct gl_vertex_buffer_binding *binding2 = 76401e04c3fSmrg &vao->BufferBinding[attrib2->BufferBindingIndex]; 76501e04c3fSmrg 76601e04c3fSmrg /* See the comment at the same assert above. */ 767a8bb7a65Smaya assert(util_bitcount(binding2->_BoundArrays & vao->Enabled) == 1 768a8bb7a65Smaya || (vao->Enabled & ~binding->_BoundArrays) == 0); 76901e04c3fSmrg 77001e04c3fSmrg /* Check if we have an identical binding */ 77101e04c3fSmrg if (binding->Stride != binding2->Stride) 77201e04c3fSmrg continue; 77301e04c3fSmrg if (binding->InstanceDivisor != binding2->InstanceDivisor) 77401e04c3fSmrg continue; 77501e04c3fSmrg if (ptr <= attrib2->Ptr) { 776a8bb7a65Smaya if (ptr + binding->Stride < attrib2->Ptr + 777a8bb7a65Smaya attrib2->Format._ElementSize) 77801e04c3fSmrg continue; 779a8bb7a65Smaya unsigned end = attrib2->Ptr + attrib2->Format._ElementSize - ptr; 78001e04c3fSmrg vertex_end = MAX2(vertex_end, end); 78101e04c3fSmrg } else { 78201e04c3fSmrg if (attrib2->Ptr + binding->Stride < ptr + vertex_end) 78301e04c3fSmrg continue; 78401e04c3fSmrg vertex_end += (GLsizei)(ptr - attrib2->Ptr); 78501e04c3fSmrg ptr = attrib2->Ptr; 78601e04c3fSmrg } 78701e04c3fSmrg 78801e04c3fSmrg /* User space buffer object */ 78901e04c3fSmrg assert(!_mesa_is_bufferobj(binding2->BufferObj)); 79001e04c3fSmrg 79101e04c3fSmrg eff_bound_arrays |= VERT_BIT(j); 79201e04c3fSmrg } 793af69d88dSmrg 79401e04c3fSmrg /* Update the back reference from the attrib to the binding */ 79501e04c3fSmrg GLbitfield attrmask = eff_bound_arrays; 79601e04c3fSmrg while (attrmask) { 79701e04c3fSmrg const int j = u_bit_scan(&attrmask); 79801e04c3fSmrg struct gl_array_attributes *attrib2 = &vao->VertexAttrib[j]; 79901e04c3fSmrg 80001e04c3fSmrg /* Update the index into the common binding point and the offset */ 80101e04c3fSmrg attrib2->_EffBufferBindingIndex = bindex; 80201e04c3fSmrg attrib2->_EffRelativeOffset = attrib2->Ptr - ptr; 80301e04c3fSmrg assert(attrib2->_EffRelativeOffset <= binding->Stride); 80401e04c3fSmrg } 80501e04c3fSmrg /* Finally this is the set of effectively bound arrays */ 80601e04c3fSmrg binding->_EffOffset = (GLintptr)ptr; 80701e04c3fSmrg /* The bound arrays past the VERT_ATTRIB_{POS,GENERIC0} mapping. */ 80801e04c3fSmrg binding->_EffBoundArrays = 80901e04c3fSmrg _mesa_vao_enable_to_vp_inputs(mode, eff_bound_arrays); 81001e04c3fSmrg 81101e04c3fSmrg /* Mark all the effective bound arrays as processed. */ 81201e04c3fSmrg mask &= ~eff_bound_arrays; 81301e04c3fSmrg } 814af69d88dSmrg } 8154a49301eSmrg 81601e04c3fSmrg#ifndef NDEBUG 81701e04c3fSmrg /* Make sure the above code works as expected. */ 81801e04c3fSmrg for (gl_vert_attrib attr = 0; attr < VERT_ATTRIB_MAX; ++attr) { 81901e04c3fSmrg /* Query the original api defined attrib/binding information ... */ 82001e04c3fSmrg const unsigned char *const map =_mesa_vao_attribute_map[mode]; 821a8bb7a65Smaya if (vao->Enabled & VERT_BIT(map[attr])) { 822a8bb7a65Smaya const struct gl_array_attributes *attrib = 823a8bb7a65Smaya &vao->VertexAttrib[map[attr]]; 82401e04c3fSmrg const struct gl_vertex_buffer_binding *binding = 82501e04c3fSmrg &vao->BufferBinding[attrib->BufferBindingIndex]; 82601e04c3fSmrg /* ... and compare that with the computed attrib/binding */ 82701e04c3fSmrg const struct gl_vertex_buffer_binding *binding2 = 82801e04c3fSmrg &vao->BufferBinding[attrib->_EffBufferBindingIndex]; 82901e04c3fSmrg assert(binding->Stride == binding2->Stride); 83001e04c3fSmrg assert(binding->InstanceDivisor == binding2->InstanceDivisor); 83101e04c3fSmrg assert(binding->BufferObj == binding2->BufferObj); 83201e04c3fSmrg if (_mesa_is_bufferobj(binding->BufferObj)) { 83301e04c3fSmrg assert(attrib->_EffRelativeOffset <= MaxRelativeOffset); 83401e04c3fSmrg assert(binding->Offset + attrib->RelativeOffset == 83501e04c3fSmrg binding2->_EffOffset + attrib->_EffRelativeOffset); 83601e04c3fSmrg } else { 83701e04c3fSmrg assert(attrib->_EffRelativeOffset < binding->Stride); 83801e04c3fSmrg assert((GLintptr)attrib->Ptr == 83901e04c3fSmrg binding2->_EffOffset + attrib->_EffRelativeOffset); 84001e04c3fSmrg } 84101e04c3fSmrg } 84201e04c3fSmrg } 84301e04c3fSmrg#endif 844af69d88dSmrg} 845af69d88dSmrg 846af69d88dSmrg 847af69d88dSmrgvoid 84801e04c3fSmrg_mesa_set_vao_immutable(struct gl_context *ctx, 84901e04c3fSmrg struct gl_vertex_array_object *vao) 850af69d88dSmrg{ 85101e04c3fSmrg _mesa_update_vao_derived_arrays(ctx, vao); 85201e04c3fSmrg vao->NewArrays = 0; 85301e04c3fSmrg vao->SharedAndImmutable = true; 85401e04c3fSmrg} 855af69d88dSmrg 856af69d88dSmrg 85701e04c3fSmrgbool 85801e04c3fSmrg_mesa_all_varyings_in_vbos(const struct gl_vertex_array_object *vao) 85901e04c3fSmrg{ 86001e04c3fSmrg /* Walk those enabled arrays that have the default vbo attached */ 861a8bb7a65Smaya GLbitfield mask = vao->Enabled & ~vao->VertexAttribBufferMask; 862af69d88dSmrg 86301e04c3fSmrg while (mask) { 86401e04c3fSmrg /* Do not use u_bit_scan64 as we can walk multiple 86501e04c3fSmrg * attrib arrays at once 86601e04c3fSmrg */ 86701e04c3fSmrg const int i = ffs(mask) - 1; 86801e04c3fSmrg const struct gl_array_attributes *attrib_array = 86901e04c3fSmrg &vao->VertexAttrib[i]; 87001e04c3fSmrg const struct gl_vertex_buffer_binding *buffer_binding = 87101e04c3fSmrg &vao->BufferBinding[attrib_array->BufferBindingIndex]; 87201e04c3fSmrg 87301e04c3fSmrg /* We have already masked out vao->VertexAttribBufferMask */ 87401e04c3fSmrg assert(!_mesa_is_bufferobj(buffer_binding->BufferObj)); 87501e04c3fSmrg 87601e04c3fSmrg /* Bail out once we find the first non vbo with a non zero stride */ 87701e04c3fSmrg if (buffer_binding->Stride != 0) 87801e04c3fSmrg return false; 87901e04c3fSmrg 88001e04c3fSmrg /* Note that we cannot use the xor variant since the _BoundArray mask 88101e04c3fSmrg * may contain array attributes that are bound but not enabled. 88201e04c3fSmrg */ 88301e04c3fSmrg mask &= ~buffer_binding->_BoundArrays; 884af69d88dSmrg } 88501e04c3fSmrg 88601e04c3fSmrg return true; 887c1f859d4Smrg} 888c1f859d4Smrg 88901e04c3fSmrgbool 89001e04c3fSmrg_mesa_all_buffers_are_unmapped(const struct gl_vertex_array_object *vao) 89101e04c3fSmrg{ 89201e04c3fSmrg /* Walk the enabled arrays that have a vbo attached */ 893a8bb7a65Smaya GLbitfield mask = vao->Enabled & vao->VertexAttribBufferMask; 89401e04c3fSmrg 89501e04c3fSmrg while (mask) { 89601e04c3fSmrg const int i = ffs(mask) - 1; 89701e04c3fSmrg const struct gl_array_attributes *attrib_array = 89801e04c3fSmrg &vao->VertexAttrib[i]; 89901e04c3fSmrg const struct gl_vertex_buffer_binding *buffer_binding = 90001e04c3fSmrg &vao->BufferBinding[attrib_array->BufferBindingIndex]; 90101e04c3fSmrg 90201e04c3fSmrg /* We have already masked with vao->VertexAttribBufferMask */ 90301e04c3fSmrg assert(_mesa_is_bufferobj(buffer_binding->BufferObj)); 90401e04c3fSmrg 90501e04c3fSmrg /* Bail out once we find the first disallowed mapping */ 90601e04c3fSmrg if (_mesa_check_disallowed_mapping(buffer_binding->BufferObj)) 90701e04c3fSmrg return false; 90801e04c3fSmrg 90901e04c3fSmrg /* We have handled everything that is bound to this buffer_binding. */ 91001e04c3fSmrg mask &= ~buffer_binding->_BoundArrays; 91101e04c3fSmrg } 91201e04c3fSmrg 91301e04c3fSmrg return true; 91401e04c3fSmrg} 915c1f859d4Smrg 916a8bb7a65Smaya 917a8bb7a65Smaya/** 918a8bb7a65Smaya * Map buffer objects used in attribute arrays. 919a8bb7a65Smaya */ 920a8bb7a65Smayavoid 921a8bb7a65Smaya_mesa_vao_map_arrays(struct gl_context *ctx, struct gl_vertex_array_object *vao, 922a8bb7a65Smaya GLbitfield access) 923a8bb7a65Smaya{ 924a8bb7a65Smaya GLbitfield mask = vao->Enabled & vao->VertexAttribBufferMask; 925a8bb7a65Smaya while (mask) { 926a8bb7a65Smaya /* Do not use u_bit_scan as we can walk multiple attrib arrays at once */ 927a8bb7a65Smaya const gl_vert_attrib attr = ffs(mask) - 1; 928a8bb7a65Smaya const GLubyte bindex = vao->VertexAttrib[attr].BufferBindingIndex; 929a8bb7a65Smaya struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[bindex]; 930a8bb7a65Smaya mask &= ~binding->_BoundArrays; 931a8bb7a65Smaya 932a8bb7a65Smaya struct gl_buffer_object *bo = binding->BufferObj; 933a8bb7a65Smaya assert(_mesa_is_bufferobj(bo)); 934a8bb7a65Smaya if (_mesa_bufferobj_mapped(bo, MAP_INTERNAL)) 935a8bb7a65Smaya continue; 936a8bb7a65Smaya 937a8bb7a65Smaya ctx->Driver.MapBufferRange(ctx, 0, bo->Size, access, bo, MAP_INTERNAL); 938a8bb7a65Smaya } 939a8bb7a65Smaya} 940a8bb7a65Smaya 941a8bb7a65Smaya 942a8bb7a65Smaya/** 943a8bb7a65Smaya * Map buffer objects used in the vao, attribute arrays and index buffer. 944a8bb7a65Smaya */ 945a8bb7a65Smayavoid 946a8bb7a65Smaya_mesa_vao_map(struct gl_context *ctx, struct gl_vertex_array_object *vao, 947a8bb7a65Smaya GLbitfield access) 948a8bb7a65Smaya{ 949a8bb7a65Smaya struct gl_buffer_object *bo = vao->IndexBufferObj; 950a8bb7a65Smaya 951a8bb7a65Smaya /* map the index buffer, if there is one, and not already mapped */ 952a8bb7a65Smaya if (_mesa_is_bufferobj(bo) && !_mesa_bufferobj_mapped(bo, MAP_INTERNAL)) 953a8bb7a65Smaya ctx->Driver.MapBufferRange(ctx, 0, bo->Size, access, bo, MAP_INTERNAL); 954a8bb7a65Smaya 955a8bb7a65Smaya _mesa_vao_map_arrays(ctx, vao, access); 956a8bb7a65Smaya} 957a8bb7a65Smaya 958a8bb7a65Smaya 959a8bb7a65Smaya/** 960a8bb7a65Smaya * Unmap buffer objects used in attribute arrays. 961a8bb7a65Smaya */ 962a8bb7a65Smayavoid 963a8bb7a65Smaya_mesa_vao_unmap_arrays(struct gl_context *ctx, 964a8bb7a65Smaya struct gl_vertex_array_object *vao) 965a8bb7a65Smaya{ 966a8bb7a65Smaya GLbitfield mask = vao->Enabled & vao->VertexAttribBufferMask; 967a8bb7a65Smaya while (mask) { 968a8bb7a65Smaya /* Do not use u_bit_scan as we can walk multiple attrib arrays at once */ 969a8bb7a65Smaya const gl_vert_attrib attr = ffs(mask) - 1; 970a8bb7a65Smaya const GLubyte bindex = vao->VertexAttrib[attr].BufferBindingIndex; 971a8bb7a65Smaya struct gl_vertex_buffer_binding *binding = &vao->BufferBinding[bindex]; 972a8bb7a65Smaya mask &= ~binding->_BoundArrays; 973a8bb7a65Smaya 974a8bb7a65Smaya struct gl_buffer_object *bo = binding->BufferObj; 975a8bb7a65Smaya assert(_mesa_is_bufferobj(bo)); 976a8bb7a65Smaya if (!_mesa_bufferobj_mapped(bo, MAP_INTERNAL)) 977a8bb7a65Smaya continue; 978a8bb7a65Smaya 979a8bb7a65Smaya ctx->Driver.UnmapBuffer(ctx, bo, MAP_INTERNAL); 980a8bb7a65Smaya } 981a8bb7a65Smaya} 982a8bb7a65Smaya 983a8bb7a65Smaya 984a8bb7a65Smaya/** 985a8bb7a65Smaya * Unmap buffer objects used in the vao, attribute arrays and index buffer. 986a8bb7a65Smaya */ 987a8bb7a65Smayavoid 988a8bb7a65Smaya_mesa_vao_unmap(struct gl_context *ctx, struct gl_vertex_array_object *vao) 989a8bb7a65Smaya{ 990a8bb7a65Smaya struct gl_buffer_object *bo = vao->IndexBufferObj; 991a8bb7a65Smaya 992a8bb7a65Smaya /* unmap the index buffer, if there is one, and still mapped */ 993a8bb7a65Smaya if (_mesa_is_bufferobj(bo) && _mesa_bufferobj_mapped(bo, MAP_INTERNAL)) 994a8bb7a65Smaya ctx->Driver.UnmapBuffer(ctx, bo, MAP_INTERNAL); 995a8bb7a65Smaya 996a8bb7a65Smaya _mesa_vao_unmap_arrays(ctx, vao); 997a8bb7a65Smaya} 998a8bb7a65Smaya 999a8bb7a65Smaya 10007117f1b4Smrg/**********************************************************************/ 10017117f1b4Smrg/* API Functions */ 10027117f1b4Smrg/**********************************************************************/ 10037117f1b4Smrg 10044a49301eSmrg 10057117f1b4Smrg/** 100601e04c3fSmrg * ARB version of glBindVertexArray() 10077117f1b4Smrg */ 100801e04c3fSmrgstatic ALWAYS_INLINE void 100901e04c3fSmrgbind_vertex_array(struct gl_context *ctx, GLuint id, bool no_error) 10107117f1b4Smrg{ 101101e04c3fSmrg struct gl_vertex_array_object *const oldObj = ctx->Array.VAO; 1012af69d88dSmrg struct gl_vertex_array_object *newObj = NULL; 10137117f1b4Smrg 101401e04c3fSmrg assert(oldObj != NULL); 10157117f1b4Smrg 101601e04c3fSmrg if (oldObj->Name == id) 10177117f1b4Smrg return; /* rebinding the same array object- no change */ 10187117f1b4Smrg 10197117f1b4Smrg /* 10204a49301eSmrg * Get pointer to new array object (newObj) 10217117f1b4Smrg */ 10227117f1b4Smrg if (id == 0) { 10237117f1b4Smrg /* The spec says there is no array object named 0, but we use 10247117f1b4Smrg * one internally because it simplifies things. 10257117f1b4Smrg */ 1026af69d88dSmrg newObj = ctx->Array.DefaultVAO; 10277117f1b4Smrg } 10287117f1b4Smrg else { 10297117f1b4Smrg /* non-default array object */ 1030af69d88dSmrg newObj = _mesa_lookup_vao(ctx, id); 103101e04c3fSmrg if (!no_error && !newObj) { 103201e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 103301e04c3fSmrg "glBindVertexArray(non-gen name)"); 103401e04c3fSmrg return; 10357117f1b4Smrg } 1036af69d88dSmrg 103701e04c3fSmrg newObj->EverBound = GL_TRUE; 1038af69d88dSmrg } 1039af69d88dSmrg 104001e04c3fSmrg /* The _DrawArrays pointer is pointing at the VAO being unbound and 104101e04c3fSmrg * that VAO may be in the process of being deleted. If it's not going 104201e04c3fSmrg * to be deleted, this will have no effect, because the pointer needs 104301e04c3fSmrg * to be updated by the VBO module anyway. 104401e04c3fSmrg * 104501e04c3fSmrg * Before the VBO module can update the pointer, we have to set it 104601e04c3fSmrg * to NULL for drivers not to set up arrays which are not bound, 104701e04c3fSmrg * or to prevent a crash if the VAO being unbound is going to be 104801e04c3fSmrg * deleted. 104901e04c3fSmrg */ 105001e04c3fSmrg _mesa_set_draw_vao(ctx, ctx->Array._EmptyVAO, 0); 10517117f1b4Smrg 1052af69d88dSmrg _mesa_reference_vao(ctx, &ctx->Array.VAO, newObj); 10534a49301eSmrg} 10544a49301eSmrg 10554a49301eSmrg 10564a49301eSmrgvoid GLAPIENTRY 105701e04c3fSmrg_mesa_BindVertexArray_no_error(GLuint id) 10584a49301eSmrg{ 10594a49301eSmrg GET_CURRENT_CONTEXT(ctx); 106001e04c3fSmrg bind_vertex_array(ctx, id, true); 10614a49301eSmrg} 10624a49301eSmrg 10634a49301eSmrg 10644a49301eSmrgvoid GLAPIENTRY 106501e04c3fSmrg_mesa_BindVertexArray(GLuint id) 10664a49301eSmrg{ 10674a49301eSmrg GET_CURRENT_CONTEXT(ctx); 106801e04c3fSmrg bind_vertex_array(ctx, id, false); 10697117f1b4Smrg} 10707117f1b4Smrg 10717117f1b4Smrg 10727117f1b4Smrg/** 10737117f1b4Smrg * Delete a set of array objects. 1074af69d88dSmrg * 10757117f1b4Smrg * \param n Number of array objects to delete. 10767117f1b4Smrg * \param ids Array of \c n array object IDs. 10777117f1b4Smrg */ 107801e04c3fSmrgstatic void 107901e04c3fSmrgdelete_vertex_arrays(struct gl_context *ctx, GLsizei n, const GLuint *ids) 10807117f1b4Smrg{ 10817117f1b4Smrg GLsizei i; 10827117f1b4Smrg 10837117f1b4Smrg for (i = 0; i < n; i++) { 108401e04c3fSmrg /* IDs equal to 0 should be silently ignored. */ 108501e04c3fSmrg if (!ids[i]) 108601e04c3fSmrg continue; 108701e04c3fSmrg 1088af69d88dSmrg struct gl_vertex_array_object *obj = _mesa_lookup_vao(ctx, ids[i]); 10897117f1b4Smrg 109001e04c3fSmrg if (obj) { 109101e04c3fSmrg assert(obj->Name == ids[i]); 10927117f1b4Smrg 109301e04c3fSmrg /* If the array object is currently bound, the spec says "the binding 109401e04c3fSmrg * for that object reverts to zero and the default vertex array 109501e04c3fSmrg * becomes current." 109601e04c3fSmrg */ 109701e04c3fSmrg if (obj == ctx->Array.VAO) 109801e04c3fSmrg _mesa_BindVertexArray_no_error(0); 10997117f1b4Smrg 110001e04c3fSmrg /* The ID is immediately freed for re-use */ 110101e04c3fSmrg _mesa_HashRemoveLocked(ctx->Array.Objects, obj->Name); 110201e04c3fSmrg 110301e04c3fSmrg if (ctx->Array.LastLookedUpVAO == obj) 110401e04c3fSmrg _mesa_reference_vao(ctx, &ctx->Array.LastLookedUpVAO, NULL); 110501e04c3fSmrg if (ctx->Array._DrawVAO == obj) 110601e04c3fSmrg _mesa_set_draw_vao(ctx, ctx->Array._EmptyVAO, 0); 11074a49301eSmrg 11084a49301eSmrg /* Unreference the array object. 11094a49301eSmrg * If refcount hits zero, the object will be deleted. 11104a49301eSmrg */ 1111af69d88dSmrg _mesa_reference_vao(ctx, &obj, NULL); 11127117f1b4Smrg } 11137117f1b4Smrg } 11147117f1b4Smrg} 11157117f1b4Smrg 11167117f1b4Smrg 111701e04c3fSmrgvoid GLAPIENTRY 111801e04c3fSmrg_mesa_DeleteVertexArrays_no_error(GLsizei n, const GLuint *ids) 111901e04c3fSmrg{ 112001e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 112101e04c3fSmrg delete_vertex_arrays(ctx, n, ids); 112201e04c3fSmrg} 112301e04c3fSmrg 112401e04c3fSmrg 112501e04c3fSmrgvoid GLAPIENTRY 112601e04c3fSmrg_mesa_DeleteVertexArrays(GLsizei n, const GLuint *ids) 112701e04c3fSmrg{ 112801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 112901e04c3fSmrg 113001e04c3fSmrg if (n < 0) { 113101e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteVertexArray(n)"); 113201e04c3fSmrg return; 113301e04c3fSmrg } 113401e04c3fSmrg 113501e04c3fSmrg delete_vertex_arrays(ctx, n, ids); 113601e04c3fSmrg} 113701e04c3fSmrg 113801e04c3fSmrg 11397117f1b4Smrg/** 11407117f1b4Smrg * Generate a set of unique array object IDs and store them in \c arrays. 114101e04c3fSmrg * Helper for _mesa_GenVertexArrays() and _mesa_CreateVertexArrays() 114201e04c3fSmrg * below. 114301e04c3fSmrg * 11447117f1b4Smrg * \param n Number of IDs to generate. 11457117f1b4Smrg * \param arrays Array of \c n locations to store the IDs. 114601e04c3fSmrg * \param create Indicates that the objects should also be created. 114701e04c3fSmrg * \param func The name of the GL entry point. 11487117f1b4Smrg */ 1149af69d88dSmrgstatic void 115001e04c3fSmrggen_vertex_arrays(struct gl_context *ctx, GLsizei n, GLuint *arrays, 115101e04c3fSmrg bool create, const char *func) 11527117f1b4Smrg{ 11537117f1b4Smrg GLuint first; 11547117f1b4Smrg GLint i; 11557117f1b4Smrg 115601e04c3fSmrg if (!arrays) 11577117f1b4Smrg return; 11587117f1b4Smrg 11594a49301eSmrg first = _mesa_HashFindFreeKeyBlock(ctx->Array.Objects, n); 11607117f1b4Smrg 116101e04c3fSmrg /* For the sake of simplicity we create the array objects in both 116201e04c3fSmrg * the Gen* and Create* cases. The only difference is the value of 116301e04c3fSmrg * EverBound, which is set to true in the Create* case. 116401e04c3fSmrg */ 11657117f1b4Smrg for (i = 0; i < n; i++) { 1166af69d88dSmrg struct gl_vertex_array_object *obj; 11677117f1b4Smrg GLuint name = first + i; 11687117f1b4Smrg 116901e04c3fSmrg obj = _mesa_new_vao(ctx, name); 11707117f1b4Smrg if (!obj) { 117101e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); 11727117f1b4Smrg return; 11737117f1b4Smrg } 117401e04c3fSmrg obj->EverBound = create; 117501e04c3fSmrg _mesa_HashInsertLocked(ctx->Array.Objects, obj->Name, obj); 11767117f1b4Smrg arrays[i] = first + i; 11777117f1b4Smrg } 11784a49301eSmrg} 11794a49301eSmrg 11804a49301eSmrg 118101e04c3fSmrgstatic void 118201e04c3fSmrggen_vertex_arrays_err(struct gl_context *ctx, GLsizei n, GLuint *arrays, 118301e04c3fSmrg bool create, const char *func) 118401e04c3fSmrg{ 118501e04c3fSmrg if (n < 0) { 118601e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func); 118701e04c3fSmrg return; 118801e04c3fSmrg } 118901e04c3fSmrg 119001e04c3fSmrg gen_vertex_arrays(ctx, n, arrays, create, func); 119101e04c3fSmrg} 119201e04c3fSmrg 119301e04c3fSmrg 11944a49301eSmrg/** 11954a49301eSmrg * ARB version of glGenVertexArrays() 11964a49301eSmrg * All arrays will be required to live in VBOs. 11974a49301eSmrg */ 119801e04c3fSmrgvoid GLAPIENTRY 119901e04c3fSmrg_mesa_GenVertexArrays_no_error(GLsizei n, GLuint *arrays) 120001e04c3fSmrg{ 120101e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 120201e04c3fSmrg gen_vertex_arrays(ctx, n, arrays, false, "glGenVertexArrays"); 120301e04c3fSmrg} 120401e04c3fSmrg 120501e04c3fSmrg 12064a49301eSmrgvoid GLAPIENTRY 12074a49301eSmrg_mesa_GenVertexArrays(GLsizei n, GLuint *arrays) 12084a49301eSmrg{ 12094a49301eSmrg GET_CURRENT_CONTEXT(ctx); 121001e04c3fSmrg gen_vertex_arrays_err(ctx, n, arrays, false, "glGenVertexArrays"); 12114a49301eSmrg} 12124a49301eSmrg 12137117f1b4Smrg 12144a49301eSmrg/** 121501e04c3fSmrg * ARB_direct_state_access 121601e04c3fSmrg * Generates ID's and creates the array objects. 12174a49301eSmrg */ 12184a49301eSmrgvoid GLAPIENTRY 121901e04c3fSmrg_mesa_CreateVertexArrays_no_error(GLsizei n, GLuint *arrays) 12204a49301eSmrg{ 12214a49301eSmrg GET_CURRENT_CONTEXT(ctx); 122201e04c3fSmrg gen_vertex_arrays(ctx, n, arrays, true, "glCreateVertexArrays"); 122301e04c3fSmrg} 122401e04c3fSmrg 122501e04c3fSmrg 122601e04c3fSmrgvoid GLAPIENTRY 122701e04c3fSmrg_mesa_CreateVertexArrays(GLsizei n, GLuint *arrays) 122801e04c3fSmrg{ 122901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 123001e04c3fSmrg gen_vertex_arrays_err(ctx, n, arrays, true, "glCreateVertexArrays"); 12317117f1b4Smrg} 12327117f1b4Smrg 12337117f1b4Smrg 12347117f1b4Smrg/** 12357117f1b4Smrg * Determine if ID is the name of an array object. 1236af69d88dSmrg * 12377117f1b4Smrg * \param id ID of the potential array object. 1238af69d88dSmrg * \return \c GL_TRUE if \c id is the name of a array object, 12397117f1b4Smrg * \c GL_FALSE otherwise. 12407117f1b4Smrg */ 12417117f1b4SmrgGLboolean GLAPIENTRY 1242af69d88dSmrg_mesa_IsVertexArray( GLuint id ) 12437117f1b4Smrg{ 1244af69d88dSmrg struct gl_vertex_array_object * obj; 12457117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 12467117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 12477117f1b4Smrg 1248af69d88dSmrg obj = _mesa_lookup_vao(ctx, id); 12497117f1b4Smrg 125001e04c3fSmrg return obj != NULL && obj->EverBound; 125101e04c3fSmrg} 125201e04c3fSmrg 125301e04c3fSmrg 125401e04c3fSmrg/** 125501e04c3fSmrg * Sets the element array buffer binding of a vertex array object. 125601e04c3fSmrg * 125701e04c3fSmrg * This is the ARB_direct_state_access equivalent of 125801e04c3fSmrg * glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer). 125901e04c3fSmrg */ 126001e04c3fSmrgstatic ALWAYS_INLINE void 126101e04c3fSmrgvertex_array_element_buffer(struct gl_context *ctx, GLuint vaobj, GLuint buffer, 126201e04c3fSmrg bool no_error) 126301e04c3fSmrg{ 126401e04c3fSmrg struct gl_vertex_array_object *vao; 126501e04c3fSmrg struct gl_buffer_object *bufObj; 126601e04c3fSmrg 126701e04c3fSmrg ASSERT_OUTSIDE_BEGIN_END(ctx); 126801e04c3fSmrg 126901e04c3fSmrg if (!no_error) { 127001e04c3fSmrg /* The GL_ARB_direct_state_access specification says: 127101e04c3fSmrg * 127201e04c3fSmrg * "An INVALID_OPERATION error is generated by 127301e04c3fSmrg * VertexArrayElementBuffer if <vaobj> is not [compatibility profile: 127401e04c3fSmrg * zero or] the name of an existing vertex array object." 127501e04c3fSmrg */ 127601e04c3fSmrg vao =_mesa_lookup_vao_err(ctx, vaobj, "glVertexArrayElementBuffer"); 127701e04c3fSmrg if (!vao) 127801e04c3fSmrg return; 127901e04c3fSmrg } else { 128001e04c3fSmrg vao = _mesa_lookup_vao(ctx, vaobj); 128101e04c3fSmrg } 128201e04c3fSmrg 128301e04c3fSmrg if (buffer != 0) { 128401e04c3fSmrg if (!no_error) { 128501e04c3fSmrg /* The GL_ARB_direct_state_access specification says: 128601e04c3fSmrg * 128701e04c3fSmrg * "An INVALID_OPERATION error is generated if <buffer> is not zero 128801e04c3fSmrg * or the name of an existing buffer object." 128901e04c3fSmrg */ 129001e04c3fSmrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, 129101e04c3fSmrg "glVertexArrayElementBuffer"); 129201e04c3fSmrg } else { 129301e04c3fSmrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 129401e04c3fSmrg } 129501e04c3fSmrg } else { 129601e04c3fSmrg bufObj = ctx->Shared->NullBufferObj; 129701e04c3fSmrg } 129801e04c3fSmrg 1299a8bb7a65Smaya if (bufObj) { 1300a8bb7a65Smaya bufObj->UsageHistory |= USAGE_ELEMENT_ARRAY_BUFFER; 130101e04c3fSmrg _mesa_reference_buffer_object(ctx, &vao->IndexBufferObj, bufObj); 1302a8bb7a65Smaya } 130301e04c3fSmrg} 130401e04c3fSmrg 130501e04c3fSmrg 130601e04c3fSmrgvoid GLAPIENTRY 130701e04c3fSmrg_mesa_VertexArrayElementBuffer_no_error(GLuint vaobj, GLuint buffer) 130801e04c3fSmrg{ 130901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 131001e04c3fSmrg vertex_array_element_buffer(ctx, vaobj, buffer, true); 131101e04c3fSmrg} 131201e04c3fSmrg 131301e04c3fSmrg 131401e04c3fSmrgvoid GLAPIENTRY 131501e04c3fSmrg_mesa_VertexArrayElementBuffer(GLuint vaobj, GLuint buffer) 131601e04c3fSmrg{ 131701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 131801e04c3fSmrg vertex_array_element_buffer(ctx, vaobj, buffer, false); 131901e04c3fSmrg} 132001e04c3fSmrg 132101e04c3fSmrg 132201e04c3fSmrgvoid GLAPIENTRY 132301e04c3fSmrg_mesa_GetVertexArrayiv(GLuint vaobj, GLenum pname, GLint *param) 132401e04c3fSmrg{ 132501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 132601e04c3fSmrg struct gl_vertex_array_object *vao; 132701e04c3fSmrg 132801e04c3fSmrg ASSERT_OUTSIDE_BEGIN_END(ctx); 132901e04c3fSmrg 133001e04c3fSmrg /* The GL_ARB_direct_state_access specification says: 133101e04c3fSmrg * 133201e04c3fSmrg * "An INVALID_OPERATION error is generated if <vaobj> is not 133301e04c3fSmrg * [compatibility profile: zero or] the name of an existing 133401e04c3fSmrg * vertex array object." 133501e04c3fSmrg */ 133601e04c3fSmrg vao =_mesa_lookup_vao_err(ctx, vaobj, "glGetVertexArrayiv"); 133701e04c3fSmrg if (!vao) 133801e04c3fSmrg return; 133901e04c3fSmrg 134001e04c3fSmrg /* The GL_ARB_direct_state_access specification says: 134101e04c3fSmrg * 134201e04c3fSmrg * "An INVALID_ENUM error is generated if <pname> is not 134301e04c3fSmrg * ELEMENT_ARRAY_BUFFER_BINDING." 134401e04c3fSmrg */ 134501e04c3fSmrg if (pname != GL_ELEMENT_ARRAY_BUFFER_BINDING) { 134601e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 134701e04c3fSmrg "glGetVertexArrayiv(pname != " 134801e04c3fSmrg "GL_ELEMENT_ARRAY_BUFFER_BINDING)"); 134901e04c3fSmrg return; 135001e04c3fSmrg } 135101e04c3fSmrg 135201e04c3fSmrg param[0] = vao->IndexBufferObj->Name; 13537117f1b4Smrg} 1354