1 /* 2 * Mesa 3-D graphics library 3 * Version: 7.6 4 * 5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 6 * (C) Copyright IBM Corporation 2006 7 * Copyright (C) 2009 VMware, Inc. All Rights Reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * BRIAN PAUL OR IBM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 * SOFTWARE. 26 */ 27 28 29 /** 30 * \file arrayobj.c 31 * Functions for the GL_APPLE_vertex_array_object extension. 32 * 33 * \todo 34 * The code in this file borrows a lot from bufferobj.c. There's a certain 35 * amount of cruft left over from that origin that may be unnecessary. 36 * 37 * \author Ian Romanick <idr (at) us.ibm.com> 38 * \author Brian Paul 39 */ 40 41 42 #include "glheader.h" 43 #include "hash.h" 44 #include "image.h" 45 #include "imports.h" 46 #include "context.h" 47 #include "mfeatures.h" 48 #include "bufferobj.h" 49 #include "arrayobj.h" 50 #include "macros.h" 51 #include "mtypes.h" 52 #include "varray.h" 53 #include "main/dispatch.h" 54 55 56 /** 57 * Look up the array object for the given ID. 58 * 59 * \returns 60 * Either a pointer to the array object with the specified ID or \c NULL for 61 * a non-existent ID. The spec defines ID 0 as being technically 62 * non-existent. 63 */ 64 65 static inline struct gl_array_object * 66 lookup_arrayobj(struct gl_context *ctx, GLuint id) 67 { 68 if (id == 0) 69 return NULL; 70 else 71 return (struct gl_array_object *) 72 _mesa_HashLookup(ctx->Array.Objects, id); 73 } 74 75 76 /** 77 * For all the vertex arrays in the array object, unbind any pointers 78 * to any buffer objects (VBOs). 79 * This is done just prior to array object destruction. 80 */ 81 static void 82 unbind_array_object_vbos(struct gl_context *ctx, struct gl_array_object *obj) 83 { 84 GLuint i; 85 86 for (i = 0; i < Elements(obj->VertexAttrib); i++) 87 _mesa_reference_buffer_object(ctx, &obj->VertexAttrib[i].BufferObj, NULL); 88 } 89 90 91 /** 92 * Allocate and initialize a new vertex array object. 93 * 94 * This function is intended to be called via 95 * \c dd_function_table::NewArrayObject. 96 */ 97 struct gl_array_object * 98 _mesa_new_array_object( struct gl_context *ctx, GLuint name ) 99 { 100 struct gl_array_object *obj = CALLOC_STRUCT(gl_array_object); 101 if (obj) 102 _mesa_initialize_array_object(ctx, obj, name); 103 return obj; 104 } 105 106 107 /** 108 * Delete an array object. 109 * 110 * This function is intended to be called via 111 * \c dd_function_table::DeleteArrayObject. 112 */ 113 void 114 _mesa_delete_array_object( struct gl_context *ctx, struct gl_array_object *obj ) 115 { 116 (void) ctx; 117 unbind_array_object_vbos(ctx, obj); 118 _mesa_reference_buffer_object(ctx, &obj->ElementArrayBufferObj, NULL); 119 _glthread_DESTROY_MUTEX(obj->Mutex); 120 free(obj); 121 } 122 123 124 /** 125 * Set ptr to arrayObj w/ reference counting. 126 * Note: this should only be called from the _mesa_reference_array_object() 127 * inline function. 128 */ 129 void 130 _mesa_reference_array_object_(struct gl_context *ctx, 131 struct gl_array_object **ptr, 132 struct gl_array_object *arrayObj) 133 { 134 assert(*ptr != arrayObj); 135 136 if (*ptr) { 137 /* Unreference the old array object */ 138 GLboolean deleteFlag = GL_FALSE; 139 struct gl_array_object *oldObj = *ptr; 140 141 _glthread_LOCK_MUTEX(oldObj->Mutex); 142 ASSERT(oldObj->RefCount > 0); 143 oldObj->RefCount--; 144 #if 0 145 printf("ArrayObj %p %d DECR to %d\n", 146 (void *) oldObj, oldObj->Name, oldObj->RefCount); 147 #endif 148 deleteFlag = (oldObj->RefCount == 0); 149 _glthread_UNLOCK_MUTEX(oldObj->Mutex); 150 151 if (deleteFlag) { 152 ASSERT(ctx->Driver.DeleteArrayObject); 153 ctx->Driver.DeleteArrayObject(ctx, oldObj); 154 } 155 156 *ptr = NULL; 157 } 158 ASSERT(!*ptr); 159 160 if (arrayObj) { 161 /* reference new array object */ 162 _glthread_LOCK_MUTEX(arrayObj->Mutex); 163 if (arrayObj->RefCount == 0) { 164 /* this array's being deleted (look just above) */ 165 /* Not sure this can every really happen. Warn if it does. */ 166 _mesa_problem(NULL, "referencing deleted array object"); 167 *ptr = NULL; 168 } 169 else { 170 arrayObj->RefCount++; 171 #if 0 172 printf("ArrayObj %p %d INCR to %d\n", 173 (void *) arrayObj, arrayObj->Name, arrayObj->RefCount); 174 #endif 175 *ptr = arrayObj; 176 } 177 _glthread_UNLOCK_MUTEX(arrayObj->Mutex); 178 } 179 } 180 181 182 183 static void 184 init_array(struct gl_context *ctx, 185 struct gl_client_array *array, GLint size, GLint type) 186 { 187 array->Size = size; 188 array->Type = type; 189 array->Format = GL_RGBA; /* only significant for GL_EXT_vertex_array_bgra */ 190 array->Stride = 0; 191 array->StrideB = 0; 192 array->Ptr = NULL; 193 array->Enabled = GL_FALSE; 194 array->Normalized = GL_FALSE; 195 array->Integer = GL_FALSE; 196 array->_ElementSize = size * _mesa_sizeof_type(type); 197 /* Vertex array buffers */ 198 _mesa_reference_buffer_object(ctx, &array->BufferObj, 199 ctx->Shared->NullBufferObj); 200 } 201 202 203 /** 204 * Initialize a gl_array_object's arrays. 205 */ 206 void 207 _mesa_initialize_array_object( struct gl_context *ctx, 208 struct gl_array_object *obj, 209 GLuint name ) 210 { 211 GLuint i; 212 213 obj->Name = name; 214 215 _glthread_INIT_MUTEX(obj->Mutex); 216 obj->RefCount = 1; 217 218 /* Init the individual arrays */ 219 for (i = 0; i < Elements(obj->VertexAttrib); i++) { 220 switch (i) { 221 case VERT_ATTRIB_WEIGHT: 222 init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_WEIGHT], 1, GL_FLOAT); 223 break; 224 case VERT_ATTRIB_NORMAL: 225 init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_NORMAL], 3, GL_FLOAT); 226 break; 227 case VERT_ATTRIB_COLOR1: 228 init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_COLOR1], 3, GL_FLOAT); 229 break; 230 case VERT_ATTRIB_FOG: 231 init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_FOG], 1, GL_FLOAT); 232 break; 233 case VERT_ATTRIB_COLOR_INDEX: 234 init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_COLOR_INDEX], 1, GL_FLOAT); 235 break; 236 case VERT_ATTRIB_EDGEFLAG: 237 init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_EDGEFLAG], 1, GL_BOOL); 238 break; 239 #if FEATURE_point_size_array 240 case VERT_ATTRIB_POINT_SIZE: 241 init_array(ctx, &obj->VertexAttrib[VERT_ATTRIB_POINT_SIZE], 1, GL_FLOAT); 242 break; 243 #endif 244 default: 245 init_array(ctx, &obj->VertexAttrib[i], 4, GL_FLOAT); 246 break; 247 } 248 } 249 250 _mesa_reference_buffer_object(ctx, &obj->ElementArrayBufferObj, 251 ctx->Shared->NullBufferObj); 252 } 253 254 255 /** 256 * Add the given array object to the array object pool. 257 */ 258 static void 259 save_array_object( struct gl_context *ctx, struct gl_array_object *obj ) 260 { 261 if (obj->Name > 0) { 262 /* insert into hash table */ 263 _mesa_HashInsert(ctx->Array.Objects, obj->Name, obj); 264 } 265 } 266 267 268 /** 269 * Remove the given array object from the array object pool. 270 * Do not deallocate the array object though. 271 */ 272 static void 273 remove_array_object( struct gl_context *ctx, struct gl_array_object *obj ) 274 { 275 if (obj->Name > 0) { 276 /* remove from hash table */ 277 _mesa_HashRemove(ctx->Array.Objects, obj->Name); 278 } 279 } 280 281 282 283 /** 284 * Helper for _mesa_update_array_object_max_element(). 285 * \return min(arrayObj->VertexAttrib[*]._MaxElement). 286 */ 287 static GLuint 288 compute_max_element(struct gl_array_object *arrayObj, GLbitfield64 enabled) 289 { 290 GLuint min = ~((GLuint)0); 291 292 while (enabled) { 293 struct gl_client_array *client_array; 294 GLint attrib = ffsll(enabled) - 1; 295 enabled ^= BITFIELD64_BIT(attrib); 296 297 client_array = &arrayObj->VertexAttrib[attrib]; 298 assert(client_array->Enabled); 299 _mesa_update_array_max_element(client_array); 300 min = MIN2(min, client_array->_MaxElement); 301 } 302 303 return min; 304 } 305 306 307 /** 308 * Examine vertex arrays to update the gl_array_object::_MaxElement field. 309 */ 310 void 311 _mesa_update_array_object_max_element(struct gl_context *ctx, 312 struct gl_array_object *arrayObj) 313 { 314 GLbitfield64 enabled; 315 316 if (!ctx->VertexProgram._Current || 317 ctx->VertexProgram._Current == ctx->VertexProgram._TnlProgram) { 318 enabled = _mesa_array_object_get_enabled_ff(arrayObj); 319 } else if (ctx->VertexProgram._Current->IsNVProgram) { 320 enabled = _mesa_array_object_get_enabled_nv(arrayObj); 321 } else { 322 enabled = _mesa_array_object_get_enabled_arb(arrayObj); 323 } 324 325 /* _MaxElement is one past the last legal array element */ 326 arrayObj->_MaxElement = compute_max_element(arrayObj, enabled); 327 } 328 329 330 /**********************************************************************/ 331 /* API Functions */ 332 /**********************************************************************/ 333 334 335 /** 336 * Helper for _mesa_BindVertexArray() and _mesa_BindVertexArrayAPPLE(). 337 * \param genRequired specifies behavour when id was not generated with 338 * glGenVertexArrays(). 339 */ 340 static void 341 bind_vertex_array(struct gl_context *ctx, GLuint id, GLboolean genRequired) 342 { 343 struct gl_array_object * const oldObj = ctx->Array.ArrayObj; 344 struct gl_array_object *newObj = NULL; 345 ASSERT_OUTSIDE_BEGIN_END(ctx); 346 347 ASSERT(oldObj != NULL); 348 349 if ( oldObj->Name == id ) 350 return; /* rebinding the same array object- no change */ 351 352 /* 353 * Get pointer to new array object (newObj) 354 */ 355 if (id == 0) { 356 /* The spec says there is no array object named 0, but we use 357 * one internally because it simplifies things. 358 */ 359 newObj = ctx->Array.DefaultArrayObj; 360 } 361 else { 362 /* non-default array object */ 363 newObj = lookup_arrayobj(ctx, id); 364 if (!newObj) { 365 if (genRequired) { 366 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindVertexArray(id)"); 367 return; 368 } 369 370 /* For APPLE version, generate a new array object now */ 371 newObj = (*ctx->Driver.NewArrayObject)(ctx, id); 372 if (!newObj) { 373 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindVertexArrayAPPLE"); 374 return; 375 } 376 377 save_array_object(ctx, newObj); 378 } 379 380 if (!newObj->_Used) { 381 /* The "Interactions with APPLE_vertex_array_object" section of the 382 * GL_ARB_vertex_array_object spec says: 383 * 384 * "The first bind call, either BindVertexArray or 385 * BindVertexArrayAPPLE, determines the semantic of the object." 386 */ 387 newObj->ARBsemantics = genRequired; 388 newObj->_Used = GL_TRUE; 389 } 390 } 391 392 ctx->NewState |= _NEW_ARRAY; 393 _mesa_reference_array_object(ctx, &ctx->Array.ArrayObj, newObj); 394 395 /* Pass BindVertexArray call to device driver */ 396 if (ctx->Driver.BindArrayObject && newObj) 397 ctx->Driver.BindArrayObject(ctx, newObj); 398 } 399 400 401 /** 402 * ARB version of glBindVertexArray() 403 * This function behaves differently from glBindVertexArrayAPPLE() in 404 * that this function requires all ids to have been previously generated 405 * by glGenVertexArrays[APPLE](). 406 */ 407 void GLAPIENTRY 408 _mesa_BindVertexArray( GLuint id ) 409 { 410 GET_CURRENT_CONTEXT(ctx); 411 bind_vertex_array(ctx, id, GL_TRUE); 412 } 413 414 415 /** 416 * Bind a new array. 417 * 418 * \todo 419 * The binding could be done more efficiently by comparing the non-NULL 420 * pointers in the old and new objects. The only arrays that are "dirty" are 421 * the ones that are non-NULL in either object. 422 */ 423 void GLAPIENTRY 424 _mesa_BindVertexArrayAPPLE( GLuint id ) 425 { 426 GET_CURRENT_CONTEXT(ctx); 427 bind_vertex_array(ctx, id, GL_FALSE); 428 } 429 430 431 /** 432 * Delete a set of array objects. 433 * 434 * \param n Number of array objects to delete. 435 * \param ids Array of \c n array object IDs. 436 */ 437 void GLAPIENTRY 438 _mesa_DeleteVertexArraysAPPLE(GLsizei n, const GLuint *ids) 439 { 440 GET_CURRENT_CONTEXT(ctx); 441 GLsizei i; 442 ASSERT_OUTSIDE_BEGIN_END(ctx); 443 444 if (n < 0) { 445 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteVertexArrayAPPLE(n)"); 446 return; 447 } 448 449 for (i = 0; i < n; i++) { 450 struct gl_array_object *obj = lookup_arrayobj(ctx, ids[i]); 451 452 if ( obj != NULL ) { 453 ASSERT( obj->Name == ids[i] ); 454 455 /* If the array object is currently bound, the spec says "the binding 456 * for that object reverts to zero and the default vertex array 457 * becomes current." 458 */ 459 if ( obj == ctx->Array.ArrayObj ) { 460 _mesa_BindVertexArray(0); 461 } 462 463 /* The ID is immediately freed for re-use */ 464 remove_array_object(ctx, obj); 465 466 /* Unreference the array object. 467 * If refcount hits zero, the object will be deleted. 468 */ 469 _mesa_reference_array_object(ctx, &obj, NULL); 470 } 471 } 472 } 473 474 475 /** 476 * Generate a set of unique array object IDs and store them in \c arrays. 477 * Helper for _mesa_GenVertexArrays[APPLE]() functions below. 478 * \param n Number of IDs to generate. 479 * \param arrays Array of \c n locations to store the IDs. 480 * \param vboOnly Will arrays have to reside in VBOs? 481 */ 482 static void 483 gen_vertex_arrays(struct gl_context *ctx, GLsizei n, GLuint *arrays) 484 { 485 GLuint first; 486 GLint i; 487 ASSERT_OUTSIDE_BEGIN_END(ctx); 488 489 if (n < 0) { 490 _mesa_error(ctx, GL_INVALID_VALUE, "glGenVertexArraysAPPLE"); 491 return; 492 } 493 494 if (!arrays) { 495 return; 496 } 497 498 first = _mesa_HashFindFreeKeyBlock(ctx->Array.Objects, n); 499 500 /* Allocate new, empty array objects and return identifiers */ 501 for (i = 0; i < n; i++) { 502 struct gl_array_object *obj; 503 GLuint name = first + i; 504 505 obj = (*ctx->Driver.NewArrayObject)( ctx, name ); 506 if (!obj) { 507 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenVertexArraysAPPLE"); 508 return; 509 } 510 save_array_object(ctx, obj); 511 arrays[i] = first + i; 512 } 513 } 514 515 516 /** 517 * ARB version of glGenVertexArrays() 518 * All arrays will be required to live in VBOs. 519 */ 520 void GLAPIENTRY 521 _mesa_GenVertexArrays(GLsizei n, GLuint *arrays) 522 { 523 GET_CURRENT_CONTEXT(ctx); 524 gen_vertex_arrays(ctx, n, arrays); 525 } 526 527 528 /** 529 * APPLE version of glGenVertexArraysAPPLE() 530 * Arrays may live in VBOs or ordinary memory. 531 */ 532 void GLAPIENTRY 533 _mesa_GenVertexArraysAPPLE(GLsizei n, GLuint *arrays) 534 { 535 GET_CURRENT_CONTEXT(ctx); 536 gen_vertex_arrays(ctx, n, arrays); 537 } 538 539 540 /** 541 * Determine if ID is the name of an array object. 542 * 543 * \param id ID of the potential array object. 544 * \return \c GL_TRUE if \c id is the name of a array object, 545 * \c GL_FALSE otherwise. 546 */ 547 GLboolean GLAPIENTRY 548 _mesa_IsVertexArrayAPPLE( GLuint id ) 549 { 550 struct gl_array_object * obj; 551 GET_CURRENT_CONTEXT(ctx); 552 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 553 554 if (id == 0) 555 return GL_FALSE; 556 557 obj = lookup_arrayobj(ctx, id); 558 559 return (obj != NULL) ? GL_TRUE : GL_FALSE; 560 } 561