bufferobj.c revision 7117f1b4
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5.1 4 * 5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 26/** 27 * \file bufferobj.c 28 * \brief Functions for the GL_ARB_vertex_buffer_object extension. 29 * \author Brian Paul, Ian Romanick 30 */ 31 32 33#include "glheader.h" 34#include "hash.h" 35#include "imports.h" 36#include "image.h" 37#include "context.h" 38#include "bufferobj.h" 39 40 41/** 42 * Get the buffer object bound to the specified target in a GL context. 43 * 44 * \param ctx GL context 45 * \param target Buffer object target to be retrieved. Currently this must 46 * be either \c GL_ARRAY_BUFFER or \c GL_ELEMENT_ARRAY_BUFFER. 47 * \return A pointer to the buffer object bound to \c target in the 48 * specified context or \c NULL if \c target is invalid. 49 */ 50static INLINE struct gl_buffer_object * 51get_buffer(GLcontext *ctx, GLenum target) 52{ 53 struct gl_buffer_object * bufObj = NULL; 54 55 switch (target) { 56 case GL_ARRAY_BUFFER_ARB: 57 bufObj = ctx->Array.ArrayBufferObj; 58 break; 59 case GL_ELEMENT_ARRAY_BUFFER_ARB: 60 bufObj = ctx->Array.ElementArrayBufferObj; 61 break; 62 case GL_PIXEL_PACK_BUFFER_EXT: 63 bufObj = ctx->Pack.BufferObj; 64 break; 65 case GL_PIXEL_UNPACK_BUFFER_EXT: 66 bufObj = ctx->Unpack.BufferObj; 67 break; 68 default: 69 /* error must be recorded by caller */ 70 return NULL; 71 } 72 73 /* bufObj should point to NullBufferObj or a user-created buffer object */ 74 ASSERT(bufObj); 75 76 return bufObj; 77} 78 79 80/** 81 * Tests the subdata range parameters and sets the GL error code for 82 * \c glBufferSubDataARB and \c glGetBufferSubDataARB. 83 * 84 * \param ctx GL context. 85 * \param target Buffer object target on which to operate. 86 * \param offset Offset of the first byte of the subdata range. 87 * \param size Size, in bytes, of the subdata range. 88 * \param caller Name of calling function for recording errors. 89 * \return A pointer to the buffer object bound to \c target in the 90 * specified context or \c NULL if any of the parameter or state 91 * conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB 92 * are invalid. 93 * 94 * \sa glBufferSubDataARB, glGetBufferSubDataARB 95 */ 96static struct gl_buffer_object * 97buffer_object_subdata_range_good( GLcontext * ctx, GLenum target, 98 GLintptrARB offset, GLsizeiptrARB size, 99 const char *caller ) 100{ 101 struct gl_buffer_object *bufObj; 102 103 if (size < 0) { 104 _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller); 105 return NULL; 106 } 107 108 if (offset < 0) { 109 _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller); 110 return NULL; 111 } 112 113 bufObj = get_buffer(ctx, target); 114 if (!bufObj) { 115 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", caller); 116 return NULL; 117 } 118 if (bufObj->Name == 0) { 119 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); 120 return NULL; 121 } 122 if (offset + size > bufObj->Size) { 123 _mesa_error(ctx, GL_INVALID_VALUE, 124 "%s(size + offset > buffer size)", caller); 125 return NULL; 126 } 127 if (bufObj->Pointer) { 128 /* Buffer is currently mapped */ 129 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); 130 return NULL; 131 } 132 133 return bufObj; 134} 135 136 137/** 138 * Allocate and initialize a new buffer object. 139 * 140 * This function is intended to be called via 141 * \c dd_function_table::NewBufferObject. 142 */ 143struct gl_buffer_object * 144_mesa_new_buffer_object( GLcontext *ctx, GLuint name, GLenum target ) 145{ 146 struct gl_buffer_object *obj; 147 148 (void) ctx; 149 150 obj = MALLOC_STRUCT(gl_buffer_object); 151 _mesa_initialize_buffer_object(obj, name, target); 152 return obj; 153} 154 155 156/** 157 * Delete a buffer object. 158 * 159 * This function is intended to be called via 160 * \c dd_function_table::DeleteBuffer. 161 */ 162void 163_mesa_delete_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj ) 164{ 165 (void) ctx; 166 167 if (bufObj->Data) 168 _mesa_free(bufObj->Data); 169 _mesa_free(bufObj); 170} 171 172 173void 174_mesa_unbind_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj ) 175{ 176 if (bufObj != ctx->Array.NullBufferObj) { 177 bufObj->RefCount--; 178 if (bufObj->RefCount <= 0) { 179 ASSERT(ctx->Array.ArrayBufferObj != bufObj); 180 ASSERT(ctx->Array.ElementArrayBufferObj != bufObj); 181 ASSERT(ctx->Array.ArrayObj->Vertex.BufferObj != bufObj); 182 ASSERT(ctx->Driver.DeleteBuffer); 183 ctx->Driver.DeleteBuffer(ctx, bufObj); 184 } 185 } 186} 187 188 189/** 190 * Initialize a buffer object to default values. 191 */ 192void 193_mesa_initialize_buffer_object( struct gl_buffer_object *obj, 194 GLuint name, GLenum target ) 195{ 196 (void) target; 197 198 _mesa_bzero(obj, sizeof(struct gl_buffer_object)); 199 obj->RefCount = 1; 200 obj->Name = name; 201 obj->Usage = GL_STATIC_DRAW_ARB; 202 obj->Access = GL_READ_WRITE_ARB; 203} 204 205 206/** 207 * Add the given buffer object to the buffer object pool. 208 */ 209void 210_mesa_save_buffer_object( GLcontext *ctx, struct gl_buffer_object *obj ) 211{ 212 if (obj->Name > 0) { 213 /* insert into hash table */ 214 _mesa_HashInsert(ctx->Shared->BufferObjects, obj->Name, obj); 215 } 216} 217 218 219/** 220 * Remove the given buffer object from the buffer object pool. 221 * Do not deallocate the buffer object though. 222 */ 223void 224_mesa_remove_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj ) 225{ 226 if (bufObj->Name > 0) { 227 /* remove from hash table */ 228 _mesa_HashRemove(ctx->Shared->BufferObjects, bufObj->Name); 229 } 230} 231 232 233/** 234 * Allocate space for and store data in a buffer object. Any data that was 235 * previously stored in the buffer object is lost. If \c data is \c NULL, 236 * memory will be allocated, but no copy will occur. 237 * 238 * This function is intended to be called via 239 * \c dd_function_table::BufferData. This function need not set GL error 240 * codes. The input parameters will have been tested before calling. 241 * 242 * \param ctx GL context. 243 * \param target Buffer object target on which to operate. 244 * \param size Size, in bytes, of the new data store. 245 * \param data Pointer to the data to store in the buffer object. This 246 * pointer may be \c NULL. 247 * \param usage Hints about how the data will be used. 248 * \param bufObj Object to be used. 249 * 250 * \sa glBufferDataARB, dd_function_table::BufferData. 251 */ 252void 253_mesa_buffer_data( GLcontext *ctx, GLenum target, GLsizeiptrARB size, 254 const GLvoid * data, GLenum usage, 255 struct gl_buffer_object * bufObj ) 256{ 257 void * new_data; 258 259 (void) ctx; (void) target; 260 261 new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size ); 262 if (new_data) { 263 bufObj->Data = (GLubyte *) new_data; 264 bufObj->Size = size; 265 bufObj->Usage = usage; 266 267 if (data) { 268 _mesa_memcpy( bufObj->Data, data, size ); 269 } 270 } 271} 272 273 274/** 275 * Replace data in a subrange of buffer object. If the data range 276 * specified by \c size + \c offset extends beyond the end of the buffer or 277 * if \c data is \c NULL, no copy is performed. 278 * 279 * This function is intended to be called by 280 * \c dd_function_table::BufferSubData. This function need not set GL error 281 * codes. The input parameters will have been tested before calling. 282 * 283 * \param ctx GL context. 284 * \param target Buffer object target on which to operate. 285 * \param offset Offset of the first byte to be modified. 286 * \param size Size, in bytes, of the data range. 287 * \param data Pointer to the data to store in the buffer object. 288 * \param bufObj Object to be used. 289 * 290 * \sa glBufferSubDataARB, dd_function_table::BufferSubData. 291 */ 292void 293_mesa_buffer_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset, 294 GLsizeiptrARB size, const GLvoid * data, 295 struct gl_buffer_object * bufObj ) 296{ 297 (void) ctx; (void) target; 298 299 /* this should have been caught in _mesa_BufferSubData() */ 300 ASSERT(size + offset <= bufObj->Size); 301 302 if (bufObj->Data) { 303 _mesa_memcpy( (GLubyte *) bufObj->Data + offset, data, size ); 304 } 305} 306 307 308/** 309 * Retrieve data from a subrange of buffer object. If the data range 310 * specified by \c size + \c offset extends beyond the end of the buffer or 311 * if \c data is \c NULL, no copy is performed. 312 * 313 * This function is intended to be called by 314 * \c dd_function_table::BufferGetSubData. This function need not set GL error 315 * codes. The input parameters will have been tested before calling. 316 * 317 * \param ctx GL context. 318 * \param target Buffer object target on which to operate. 319 * \param offset Offset of the first byte to be modified. 320 * \param size Size, in bytes, of the data range. 321 * \param data Pointer to the data to store in the buffer object. 322 * \param bufObj Object to be used. 323 * 324 * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData. 325 */ 326void 327_mesa_buffer_get_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset, 328 GLsizeiptrARB size, GLvoid * data, 329 struct gl_buffer_object * bufObj ) 330{ 331 (void) ctx; (void) target; 332 333 if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) { 334 _mesa_memcpy( data, (GLubyte *) bufObj->Data + offset, size ); 335 } 336} 337 338 339/** 340 * Fallback function called via ctx->Driver.MapBuffer(). 341 * Hardware drivers that really implement buffer objects should never use 342 * this function. 343 * 344 * The function parameters will have been already tested for errors. 345 * 346 * \param ctx GL context. 347 * \param target Buffer object target on which to operate. 348 * \param access Information about how the buffer will be accessed. 349 * \param bufObj Object to be mapped. 350 * \return A pointer to the object's internal data store that can be accessed 351 * by the processor 352 * 353 * \sa glMapBufferARB, dd_function_table::MapBuffer 354 */ 355void * 356_mesa_buffer_map( GLcontext *ctx, GLenum target, GLenum access, 357 struct gl_buffer_object *bufObj ) 358{ 359 (void) ctx; 360 (void) target; 361 (void) access; 362 ASSERT(!bufObj->OnCard); 363 /* Just return a direct pointer to the data */ 364 if (bufObj->Pointer) { 365 /* already mapped! */ 366 return NULL; 367 } 368 bufObj->Pointer = bufObj->Data; 369 return bufObj->Pointer; 370} 371 372 373/** 374 * Fallback function called via ctx->Driver.MapBuffer(). 375 * Hardware drivers that really implement buffer objects should never use 376 * function. 377 * 378 * The input parameters will have been already tested for errors. 379 * 380 * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer 381 */ 382GLboolean 383_mesa_buffer_unmap( GLcontext *ctx, GLenum target, 384 struct gl_buffer_object *bufObj ) 385{ 386 (void) ctx; 387 (void) target; 388 ASSERT(!bufObj->OnCard); 389 /* XXX we might assert here that bufObj->Pointer is non-null */ 390 bufObj->Pointer = NULL; 391 return GL_TRUE; 392} 393 394 395/** 396 * Initialize the state associated with buffer objects 397 */ 398void 399_mesa_init_buffer_objects( GLcontext *ctx ) 400{ 401 /* Allocate the default buffer object and set refcount so high that 402 * it never gets deleted. 403 */ 404 ctx->Array.NullBufferObj = _mesa_new_buffer_object(ctx, 0, 0); 405 if (ctx->Array.NullBufferObj) 406 ctx->Array.NullBufferObj->RefCount = 1000; 407 408 ctx->Array.ArrayBufferObj = ctx->Array.NullBufferObj; 409 ctx->Array.ElementArrayBufferObj = ctx->Array.NullBufferObj; 410} 411 412 413/** 414 * When we're about to read pixel data out of a PBO (via glDrawPixels, 415 * glTexImage, etc) or write data into a PBO (via glReadPixels, 416 * glGetTexImage, etc) we call this function to check that we're not 417 * going to read out of bounds. 418 * 419 * XXX This would also be a convenient time to check that the PBO isn't 420 * currently mapped. Whoever calls this function should check for that. 421 * Remember, we can't use a PBO when it's mapped! 422 * 423 * \param width width of image to read/write 424 * \param height height of image to read/write 425 * \param depth depth of image to read/write 426 * \param format format of image to read/write 427 * \param type datatype of image to read/write 428 * \param ptr the user-provided pointer/offset 429 * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would 430 * go out of bounds. 431 */ 432GLboolean 433_mesa_validate_pbo_access(GLuint dimensions, 434 const struct gl_pixelstore_attrib *pack, 435 GLsizei width, GLsizei height, GLsizei depth, 436 GLenum format, GLenum type, const GLvoid *ptr) 437{ 438 GLvoid *start, *end; 439 const GLubyte *sizeAddr; /* buffer size, cast to a pointer */ 440 441 ASSERT(pack->BufferObj->Name != 0); 442 443 if (pack->BufferObj->Size == 0) 444 /* no buffer! */ 445 return GL_FALSE; 446 447 /* get address of first pixel we'll read */ 448 start = _mesa_image_address(dimensions, pack, ptr, width, height, 449 format, type, 0, 0, 0); 450 451 /* get address just past the last pixel we'll read */ 452 end = _mesa_image_address(dimensions, pack, ptr, width, height, 453 format, type, depth-1, height-1, width); 454 455 456 sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size; 457 458 if ((const GLubyte *) start > sizeAddr) { 459 /* This will catch negative values / wrap-around */ 460 return GL_FALSE; 461 } 462 if ((const GLubyte *) end > sizeAddr) { 463 /* Image read goes beyond end of buffer */ 464 return GL_FALSE; 465 } 466 467 /* OK! */ 468 return GL_TRUE; 469} 470 471 472/** 473 * Return the gl_buffer_object for the given ID. 474 * Always return NULL for ID 0. 475 */ 476struct gl_buffer_object * 477_mesa_lookup_bufferobj(GLcontext *ctx, GLuint buffer) 478{ 479 if (buffer == 0) 480 return NULL; 481 else 482 return (struct gl_buffer_object *) 483 _mesa_HashLookup(ctx->Shared->BufferObjects, buffer); 484} 485 486 487 488/**********************************************************************/ 489/* API Functions */ 490/**********************************************************************/ 491 492void GLAPIENTRY 493_mesa_BindBufferARB(GLenum target, GLuint buffer) 494{ 495 GET_CURRENT_CONTEXT(ctx); 496 struct gl_buffer_object *oldBufObj; 497 struct gl_buffer_object *newBufObj = NULL; 498 struct gl_buffer_object **bindTarget = NULL; 499 ASSERT_OUTSIDE_BEGIN_END(ctx); 500 501 switch (target) { 502 case GL_ARRAY_BUFFER_ARB: 503 bindTarget = &ctx->Array.ArrayBufferObj; 504 break; 505 case GL_ELEMENT_ARRAY_BUFFER_ARB: 506 bindTarget = &ctx->Array.ElementArrayBufferObj; 507 break; 508 case GL_PIXEL_PACK_BUFFER_EXT: 509 bindTarget = &ctx->Pack.BufferObj; 510 break; 511 case GL_PIXEL_UNPACK_BUFFER_EXT: 512 bindTarget = &ctx->Unpack.BufferObj; 513 break; 514 default: 515 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target)"); 516 return; 517 } 518 519 /* Get pointer to old buffer object (to be unbound) */ 520 oldBufObj = get_buffer(ctx, target); 521 if (oldBufObj && oldBufObj->Name == buffer) 522 return; /* rebinding the same buffer object- no change */ 523 524 /* 525 * Get pointer to new buffer object (newBufObj) 526 */ 527 if (buffer == 0) { 528 /* The spec says there's not a buffer object named 0, but we use 529 * one internally because it simplifies things. 530 */ 531 newBufObj = ctx->Array.NullBufferObj; 532 } 533 else { 534 /* non-default buffer object */ 535 newBufObj = _mesa_lookup_bufferobj(ctx, buffer); 536 if (!newBufObj) { 537 /* if this is a new buffer object id, allocate a buffer object now */ 538 ASSERT(ctx->Driver.NewBufferObject); 539 newBufObj = ctx->Driver.NewBufferObject(ctx, buffer, target); 540 if (!newBufObj) { 541 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB"); 542 return; 543 } 544 _mesa_save_buffer_object(ctx, newBufObj); 545 } 546 } 547 548 /* Make new binding */ 549 *bindTarget = newBufObj; 550 newBufObj->RefCount++; 551 552 /* Pass BindBuffer call to device driver */ 553 if (ctx->Driver.BindBuffer && newBufObj) 554 ctx->Driver.BindBuffer( ctx, target, newBufObj ); 555 556 /* decr ref count on old buffer obj, delete if needed */ 557 if (oldBufObj) { 558 oldBufObj->RefCount--; 559 assert(oldBufObj->RefCount >= 0); 560 if (oldBufObj->RefCount == 0) { 561 assert(oldBufObj->Name != 0); 562 ASSERT(ctx->Driver.DeleteBuffer); 563 ctx->Driver.DeleteBuffer( ctx, oldBufObj ); 564 } 565 } 566} 567 568 569/** 570 * Delete a set of buffer objects. 571 * 572 * \param n Number of buffer objects to delete. 573 * \param ids Array of \c n buffer object IDs. 574 */ 575void GLAPIENTRY 576_mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids) 577{ 578 GET_CURRENT_CONTEXT(ctx); 579 GLsizei i; 580 ASSERT_OUTSIDE_BEGIN_END(ctx); 581 582 if (n < 0) { 583 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)"); 584 return; 585 } 586 587 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 588 589 for (i = 0; i < n; i++) { 590 struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]); 591 if (bufObj) { 592 /* unbind any vertex pointers bound to this buffer */ 593 GLuint j; 594 595 ASSERT(bufObj->Name == ids[i]); 596 597 if (ctx->Array.ArrayObj->Vertex.BufferObj == bufObj) { 598 bufObj->RefCount--; 599 ctx->Array.ArrayObj->Vertex.BufferObj = ctx->Array.NullBufferObj; 600 ctx->Array.NullBufferObj->RefCount++; 601 } 602 if (ctx->Array.ArrayObj->Normal.BufferObj == bufObj) { 603 bufObj->RefCount--; 604 ctx->Array.ArrayObj->Normal.BufferObj = ctx->Array.NullBufferObj; 605 ctx->Array.NullBufferObj->RefCount++; 606 } 607 if (ctx->Array.ArrayObj->Color.BufferObj == bufObj) { 608 bufObj->RefCount--; 609 ctx->Array.ArrayObj->Color.BufferObj = ctx->Array.NullBufferObj; 610 ctx->Array.NullBufferObj->RefCount++; 611 } 612 if (ctx->Array.ArrayObj->SecondaryColor.BufferObj == bufObj) { 613 bufObj->RefCount--; 614 ctx->Array.ArrayObj->SecondaryColor.BufferObj = ctx->Array.NullBufferObj; 615 ctx->Array.NullBufferObj->RefCount++; 616 } 617 if (ctx->Array.ArrayObj->FogCoord.BufferObj == bufObj) { 618 bufObj->RefCount--; 619 ctx->Array.ArrayObj->FogCoord.BufferObj = ctx->Array.NullBufferObj; 620 ctx->Array.NullBufferObj->RefCount++; 621 } 622 if (ctx->Array.ArrayObj->Index.BufferObj == bufObj) { 623 bufObj->RefCount--; 624 ctx->Array.ArrayObj->Index.BufferObj = ctx->Array.NullBufferObj; 625 ctx->Array.NullBufferObj->RefCount++; 626 } 627 if (ctx->Array.ArrayObj->EdgeFlag.BufferObj == bufObj) { 628 bufObj->RefCount--; 629 ctx->Array.ArrayObj->EdgeFlag.BufferObj = ctx->Array.NullBufferObj; 630 ctx->Array.NullBufferObj->RefCount++; 631 } 632 for (j = 0; j < MAX_TEXTURE_UNITS; j++) { 633 if (ctx->Array.ArrayObj->TexCoord[j].BufferObj == bufObj) { 634 bufObj->RefCount--; 635 ctx->Array.ArrayObj->TexCoord[j].BufferObj = ctx->Array.NullBufferObj; 636 ctx->Array.NullBufferObj->RefCount++; 637 } 638 } 639 for (j = 0; j < VERT_ATTRIB_MAX; j++) { 640 if (ctx->Array.ArrayObj->VertexAttrib[j].BufferObj == bufObj) { 641 bufObj->RefCount--; 642 ctx->Array.ArrayObj->VertexAttrib[j].BufferObj = ctx->Array.NullBufferObj; 643 ctx->Array.NullBufferObj->RefCount++; 644 } 645 } 646 647 if (ctx->Array.ArrayBufferObj == bufObj) { 648 _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 ); 649 } 650 if (ctx->Array.ElementArrayBufferObj == bufObj) { 651 _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 ); 652 } 653 654 if (ctx->Pack.BufferObj == bufObj) { 655 _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 ); 656 } 657 if (ctx->Unpack.BufferObj == bufObj) { 658 _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 ); 659 } 660 661 /* The ID is immediately freed for re-use */ 662 _mesa_remove_buffer_object(ctx, bufObj); 663 _mesa_unbind_buffer_object(ctx, bufObj); 664 } 665 } 666 667 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 668} 669 670 671/** 672 * Generate a set of unique buffer object IDs and store them in \c buffer. 673 * 674 * \param n Number of IDs to generate. 675 * \param buffer Array of \c n locations to store the IDs. 676 */ 677void GLAPIENTRY 678_mesa_GenBuffersARB(GLsizei n, GLuint *buffer) 679{ 680 GET_CURRENT_CONTEXT(ctx); 681 GLuint first; 682 GLint i; 683 ASSERT_OUTSIDE_BEGIN_END(ctx); 684 685 if (n < 0) { 686 _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB"); 687 return; 688 } 689 690 if (!buffer) { 691 return; 692 } 693 694 /* 695 * This must be atomic (generation and allocation of buffer object IDs) 696 */ 697 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 698 699 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n); 700 701 /* Allocate new, empty buffer objects and return identifiers */ 702 for (i = 0; i < n; i++) { 703 struct gl_buffer_object *bufObj; 704 GLuint name = first + i; 705 GLenum target = 0; 706 bufObj = ctx->Driver.NewBufferObject( ctx, name, target ); 707 if (!bufObj) { 708 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 709 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenBuffersARB"); 710 return; 711 } 712 _mesa_save_buffer_object(ctx, bufObj); 713 buffer[i] = first + i; 714 } 715 716 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 717} 718 719 720/** 721 * Determine if ID is the name of a buffer object. 722 * 723 * \param id ID of the potential buffer object. 724 * \return \c GL_TRUE if \c id is the name of a buffer object, 725 * \c GL_FALSE otherwise. 726 */ 727GLboolean GLAPIENTRY 728_mesa_IsBufferARB(GLuint id) 729{ 730 struct gl_buffer_object *bufObj; 731 GET_CURRENT_CONTEXT(ctx); 732 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 733 734 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 735 bufObj = _mesa_lookup_bufferobj(ctx, id); 736 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 737 738 return bufObj ? GL_TRUE : GL_FALSE; 739} 740 741 742void GLAPIENTRY 743_mesa_BufferDataARB(GLenum target, GLsizeiptrARB size, 744 const GLvoid * data, GLenum usage) 745{ 746 GET_CURRENT_CONTEXT(ctx); 747 struct gl_buffer_object *bufObj; 748 ASSERT_OUTSIDE_BEGIN_END(ctx); 749 750 if (size < 0) { 751 _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)"); 752 return; 753 } 754 755 switch (usage) { 756 case GL_STREAM_DRAW_ARB: 757 case GL_STREAM_READ_ARB: 758 case GL_STREAM_COPY_ARB: 759 case GL_STATIC_DRAW_ARB: 760 case GL_STATIC_READ_ARB: 761 case GL_STATIC_COPY_ARB: 762 case GL_DYNAMIC_DRAW_ARB: 763 case GL_DYNAMIC_READ_ARB: 764 case GL_DYNAMIC_COPY_ARB: 765 /* OK */ 766 break; 767 default: 768 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)"); 769 return; 770 } 771 772 bufObj = get_buffer(ctx, target); 773 if (!bufObj) { 774 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(target)" ); 775 return; 776 } 777 if (bufObj->Name == 0) { 778 _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB" ); 779 return; 780 } 781 782 if (bufObj->Pointer) { 783 _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB(buffer is mapped)" ); 784 return; 785 } 786 787 ASSERT(ctx->Driver.BufferData); 788 789 /* Give the buffer object to the driver! <data> may be null! */ 790 ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj ); 791} 792 793 794void GLAPIENTRY 795_mesa_BufferSubDataARB(GLenum target, GLintptrARB offset, 796 GLsizeiptrARB size, const GLvoid * data) 797{ 798 GET_CURRENT_CONTEXT(ctx); 799 struct gl_buffer_object *bufObj; 800 ASSERT_OUTSIDE_BEGIN_END(ctx); 801 802 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, 803 "glBufferSubDataARB" ); 804 if (!bufObj) { 805 /* error already recorded */ 806 return; 807 } 808 809 ASSERT(ctx->Driver.BufferSubData); 810 ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj ); 811} 812 813 814void GLAPIENTRY 815_mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset, 816 GLsizeiptrARB size, void * data) 817{ 818 GET_CURRENT_CONTEXT(ctx); 819 struct gl_buffer_object *bufObj; 820 ASSERT_OUTSIDE_BEGIN_END(ctx); 821 822 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, 823 "glGetBufferSubDataARB" ); 824 if (!bufObj) { 825 /* error already recorded */ 826 return; 827 } 828 829 ASSERT(ctx->Driver.GetBufferSubData); 830 ctx->Driver.GetBufferSubData( ctx, target, offset, size, data, bufObj ); 831} 832 833 834void * GLAPIENTRY 835_mesa_MapBufferARB(GLenum target, GLenum access) 836{ 837 GET_CURRENT_CONTEXT(ctx); 838 struct gl_buffer_object * bufObj; 839 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); 840 841 switch (access) { 842 case GL_READ_ONLY_ARB: 843 case GL_WRITE_ONLY_ARB: 844 case GL_READ_WRITE_ARB: 845 /* OK */ 846 break; 847 default: 848 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)"); 849 return NULL; 850 } 851 852 bufObj = get_buffer(ctx, target); 853 if (!bufObj) { 854 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(target)" ); 855 return NULL; 856 } 857 if (bufObj->Name == 0) { 858 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB" ); 859 return NULL; 860 } 861 if (bufObj->Pointer) { 862 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)"); 863 return NULL; 864 } 865 866 ASSERT(ctx->Driver.MapBuffer); 867 bufObj->Pointer = ctx->Driver.MapBuffer( ctx, target, access, bufObj ); 868 if (!bufObj->Pointer) { 869 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(access)"); 870 } 871 872 bufObj->Access = access; 873 874 return bufObj->Pointer; 875} 876 877 878GLboolean GLAPIENTRY 879_mesa_UnmapBufferARB(GLenum target) 880{ 881 GET_CURRENT_CONTEXT(ctx); 882 struct gl_buffer_object *bufObj; 883 GLboolean status = GL_TRUE; 884 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 885 886 bufObj = get_buffer(ctx, target); 887 if (!bufObj) { 888 _mesa_error(ctx, GL_INVALID_ENUM, "glUnmapBufferARB(target)" ); 889 return GL_FALSE; 890 } 891 if (bufObj->Name == 0) { 892 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" ); 893 return GL_FALSE; 894 } 895 if (!bufObj->Pointer) { 896 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB"); 897 return GL_FALSE; 898 } 899 900 if (ctx->Driver.UnmapBuffer) { 901 status = ctx->Driver.UnmapBuffer( ctx, target, bufObj ); 902 } 903 904 bufObj->Access = GL_READ_WRITE_ARB; /* initial value, OK? */ 905 bufObj->Pointer = NULL; 906 907 return status; 908} 909 910 911void GLAPIENTRY 912_mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params) 913{ 914 GET_CURRENT_CONTEXT(ctx); 915 struct gl_buffer_object *bufObj; 916 ASSERT_OUTSIDE_BEGIN_END(ctx); 917 918 bufObj = get_buffer(ctx, target); 919 if (!bufObj) { 920 _mesa_error(ctx, GL_INVALID_ENUM, "GetBufferParameterivARB(target)" ); 921 return; 922 } 923 if (bufObj->Name == 0) { 924 _mesa_error(ctx, GL_INVALID_OPERATION, "GetBufferParameterivARB" ); 925 return; 926 } 927 928 switch (pname) { 929 case GL_BUFFER_SIZE_ARB: 930 *params = (GLint) bufObj->Size; 931 break; 932 case GL_BUFFER_USAGE_ARB: 933 *params = bufObj->Usage; 934 break; 935 case GL_BUFFER_ACCESS_ARB: 936 *params = bufObj->Access; 937 break; 938 case GL_BUFFER_MAPPED_ARB: 939 *params = (bufObj->Pointer != NULL); 940 break; 941 default: 942 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname)"); 943 return; 944 } 945} 946 947 948void GLAPIENTRY 949_mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params) 950{ 951 GET_CURRENT_CONTEXT(ctx); 952 struct gl_buffer_object * bufObj; 953 ASSERT_OUTSIDE_BEGIN_END(ctx); 954 955 if (pname != GL_BUFFER_MAP_POINTER_ARB) { 956 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)"); 957 return; 958 } 959 960 bufObj = get_buffer(ctx, target); 961 if (!bufObj) { 962 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(target)" ); 963 return; 964 } 965 if (bufObj->Name == 0) { 966 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferPointervARB" ); 967 return; 968 } 969 970 *params = bufObj->Pointer; 971} 972