bufferobj.c revision c1f859d4
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.2 4 * 5 * Copyright (C) 1999-2008 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 170 /* assign strange values here to help w/ debugging */ 171 bufObj->RefCount = -1000; 172 bufObj->Name = ~0; 173 174 _mesa_free(bufObj); 175} 176 177 178 179/** 180 * Set ptr to bufObj w/ reference counting. 181 */ 182void 183_mesa_reference_buffer_object(GLcontext *ctx, 184 struct gl_buffer_object **ptr, 185 struct gl_buffer_object *bufObj) 186{ 187 if (*ptr == bufObj) 188 return; 189 190 if (*ptr) { 191 /* Unreference the old texture */ 192 GLboolean deleteFlag = GL_FALSE; 193 struct gl_buffer_object *oldObj = *ptr; 194 195 /*_glthread_LOCK_MUTEX(oldObj->Mutex);*/ 196 ASSERT(oldObj->RefCount > 0); 197 oldObj->RefCount--; 198#if 0 199 printf("BufferObj %p %d DECR to %d\n", 200 (void *) oldObj, oldObj->Name, oldObj->RefCount); 201#endif 202 deleteFlag = (oldObj->RefCount == 0); 203 /*_glthread_UNLOCK_MUTEX(oldObj->Mutex);*/ 204 205 if (deleteFlag) { 206 207 /* some sanity checking: don't delete a buffer still in use */ 208#if 0 209 /* unfortunately, these tests are invalid during context tear-down */ 210 ASSERT(ctx->Array.ArrayBufferObj != bufObj); 211 ASSERT(ctx->Array.ElementArrayBufferObj != bufObj); 212 ASSERT(ctx->Array.ArrayObj->Vertex.BufferObj != bufObj); 213#endif 214 215 ASSERT(ctx->Driver.DeleteBuffer); 216 ctx->Driver.DeleteBuffer(ctx, oldObj); 217 } 218 219 *ptr = NULL; 220 } 221 ASSERT(!*ptr); 222 223 if (bufObj) { 224 /* reference new texture */ 225 /*_glthread_LOCK_MUTEX(tex->Mutex);*/ 226 if (bufObj->RefCount == 0) { 227 /* this buffer's being deleted (look just above) */ 228 /* Not sure this can every really happen. Warn if it does. */ 229 _mesa_problem(NULL, "referencing deleted buffer object"); 230 *ptr = NULL; 231 } 232 else { 233 bufObj->RefCount++; 234#if 0 235 printf("BufferObj %p %d INCR to %d\n", 236 (void *) bufObj, bufObj->Name, bufObj->RefCount); 237#endif 238 *ptr = bufObj; 239 } 240 /*_glthread_UNLOCK_MUTEX(tex->Mutex);*/ 241 } 242} 243 244 245/** 246 * Initialize a buffer object to default values. 247 */ 248void 249_mesa_initialize_buffer_object( struct gl_buffer_object *obj, 250 GLuint name, GLenum target ) 251{ 252 (void) target; 253 254 _mesa_bzero(obj, sizeof(struct gl_buffer_object)); 255 obj->RefCount = 1; 256 obj->Name = name; 257 obj->Usage = GL_STATIC_DRAW_ARB; 258 obj->Access = GL_READ_WRITE_ARB; 259} 260 261 262/** 263 * Allocate space for and store data in a buffer object. Any data that was 264 * previously stored in the buffer object is lost. If \c data is \c NULL, 265 * memory will be allocated, but no copy will occur. 266 * 267 * This function is intended to be called via 268 * \c dd_function_table::BufferData. This function need not set GL error 269 * codes. The input parameters will have been tested before calling. 270 * 271 * \param ctx GL context. 272 * \param target Buffer object target on which to operate. 273 * \param size Size, in bytes, of the new data store. 274 * \param data Pointer to the data to store in the buffer object. This 275 * pointer may be \c NULL. 276 * \param usage Hints about how the data will be used. 277 * \param bufObj Object to be used. 278 * 279 * \sa glBufferDataARB, dd_function_table::BufferData. 280 */ 281void 282_mesa_buffer_data( GLcontext *ctx, GLenum target, GLsizeiptrARB size, 283 const GLvoid * data, GLenum usage, 284 struct gl_buffer_object * bufObj ) 285{ 286 void * new_data; 287 288 (void) ctx; (void) target; 289 290 new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size ); 291 if (new_data) { 292 bufObj->Data = (GLubyte *) new_data; 293 bufObj->Size = size; 294 bufObj->Usage = usage; 295 296 if (data) { 297 _mesa_memcpy( bufObj->Data, data, size ); 298 } 299 } 300} 301 302 303/** 304 * Replace data in a subrange of buffer object. If the data range 305 * specified by \c size + \c offset extends beyond the end of the buffer or 306 * if \c data is \c NULL, no copy is performed. 307 * 308 * This function is intended to be called by 309 * \c dd_function_table::BufferSubData. This function need not set GL error 310 * codes. The input parameters will have been tested before calling. 311 * 312 * \param ctx GL context. 313 * \param target Buffer object target on which to operate. 314 * \param offset Offset of the first byte to be modified. 315 * \param size Size, in bytes, of the data range. 316 * \param data Pointer to the data to store in the buffer object. 317 * \param bufObj Object to be used. 318 * 319 * \sa glBufferSubDataARB, dd_function_table::BufferSubData. 320 */ 321void 322_mesa_buffer_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset, 323 GLsizeiptrARB size, const GLvoid * data, 324 struct gl_buffer_object * bufObj ) 325{ 326 (void) ctx; (void) target; 327 328 /* this should have been caught in _mesa_BufferSubData() */ 329 ASSERT(size + offset <= bufObj->Size); 330 331 if (bufObj->Data) { 332 _mesa_memcpy( (GLubyte *) bufObj->Data + offset, data, size ); 333 } 334} 335 336 337/** 338 * Retrieve data from a subrange of buffer object. If the data range 339 * specified by \c size + \c offset extends beyond the end of the buffer or 340 * if \c data is \c NULL, no copy is performed. 341 * 342 * This function is intended to be called by 343 * \c dd_function_table::BufferGetSubData. This function need not set GL error 344 * codes. The input parameters will have been tested before calling. 345 * 346 * \param ctx GL context. 347 * \param target Buffer object target on which to operate. 348 * \param offset Offset of the first byte to be modified. 349 * \param size Size, in bytes, of the data range. 350 * \param data Pointer to the data to store in the buffer object. 351 * \param bufObj Object to be used. 352 * 353 * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData. 354 */ 355void 356_mesa_buffer_get_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset, 357 GLsizeiptrARB size, GLvoid * data, 358 struct gl_buffer_object * bufObj ) 359{ 360 (void) ctx; (void) target; 361 362 if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) { 363 _mesa_memcpy( data, (GLubyte *) bufObj->Data + offset, size ); 364 } 365} 366 367 368/** 369 * Fallback function called via ctx->Driver.MapBuffer(). 370 * Hardware drivers that really implement buffer objects should never use 371 * this function. 372 * 373 * The function parameters will have been already tested for errors. 374 * 375 * \param ctx GL context. 376 * \param target Buffer object target on which to operate. 377 * \param access Information about how the buffer will be accessed. 378 * \param bufObj Object to be mapped. 379 * \return A pointer to the object's internal data store that can be accessed 380 * by the processor 381 * 382 * \sa glMapBufferARB, dd_function_table::MapBuffer 383 */ 384void * 385_mesa_buffer_map( GLcontext *ctx, GLenum target, GLenum access, 386 struct gl_buffer_object *bufObj ) 387{ 388 (void) ctx; 389 (void) target; 390 (void) access; 391 ASSERT(!bufObj->OnCard); 392 /* Just return a direct pointer to the data */ 393 if (bufObj->Pointer) { 394 /* already mapped! */ 395 return NULL; 396 } 397 bufObj->Pointer = bufObj->Data; 398 return bufObj->Pointer; 399} 400 401 402/** 403 * Fallback function called via ctx->Driver.MapBuffer(). 404 * Hardware drivers that really implement buffer objects should never use 405 * function. 406 * 407 * The input parameters will have been already tested for errors. 408 * 409 * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer 410 */ 411GLboolean 412_mesa_buffer_unmap( GLcontext *ctx, GLenum target, 413 struct gl_buffer_object *bufObj ) 414{ 415 (void) ctx; 416 (void) target; 417 ASSERT(!bufObj->OnCard); 418 /* XXX we might assert here that bufObj->Pointer is non-null */ 419 bufObj->Pointer = NULL; 420 return GL_TRUE; 421} 422 423 424/** 425 * Initialize the state associated with buffer objects 426 */ 427void 428_mesa_init_buffer_objects( GLcontext *ctx ) 429{ 430 /* Allocate the default buffer object and set refcount so high that 431 * it never gets deleted. 432 * XXX with recent/improved refcounting this may not longer be needed. 433 */ 434 ctx->Array.NullBufferObj = _mesa_new_buffer_object(ctx, 0, 0); 435 if (ctx->Array.NullBufferObj) 436 ctx->Array.NullBufferObj->RefCount = 1000; 437 438 ctx->Array.ArrayBufferObj = ctx->Array.NullBufferObj; 439 ctx->Array.ElementArrayBufferObj = ctx->Array.NullBufferObj; 440} 441 442/** 443 * Bind the specified target to buffer for the specified context. 444 */ 445static void 446bind_buffer_object(GLcontext *ctx, GLenum target, GLuint buffer) 447{ 448 struct gl_buffer_object *oldBufObj; 449 struct gl_buffer_object *newBufObj = NULL; 450 struct gl_buffer_object **bindTarget = NULL; 451 452 switch (target) { 453 case GL_ARRAY_BUFFER_ARB: 454 bindTarget = &ctx->Array.ArrayBufferObj; 455 break; 456 case GL_ELEMENT_ARRAY_BUFFER_ARB: 457 bindTarget = &ctx->Array.ElementArrayBufferObj; 458 break; 459 case GL_PIXEL_PACK_BUFFER_EXT: 460 bindTarget = &ctx->Pack.BufferObj; 461 break; 462 case GL_PIXEL_UNPACK_BUFFER_EXT: 463 bindTarget = &ctx->Unpack.BufferObj; 464 break; 465 default: 466 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target)"); 467 return; 468 } 469 470 /* Get pointer to old buffer object (to be unbound) */ 471 oldBufObj = get_buffer(ctx, target); 472 if (oldBufObj && oldBufObj->Name == buffer) 473 return; /* rebinding the same buffer object- no change */ 474 475 /* 476 * Get pointer to new buffer object (newBufObj) 477 */ 478 if (buffer == 0) { 479 /* The spec says there's not a buffer object named 0, but we use 480 * one internally because it simplifies things. 481 */ 482 newBufObj = ctx->Array.NullBufferObj; 483 } 484 else { 485 /* non-default buffer object */ 486 newBufObj = _mesa_lookup_bufferobj(ctx, buffer); 487 if (!newBufObj) { 488 /* if this is a new buffer object id, allocate a buffer object now */ 489 ASSERT(ctx->Driver.NewBufferObject); 490 newBufObj = ctx->Driver.NewBufferObject(ctx, buffer, target); 491 if (!newBufObj) { 492 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB"); 493 return; 494 } 495 _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, newBufObj); 496 } 497 } 498 499 /* bind new buffer */ 500 _mesa_reference_buffer_object(ctx, bindTarget, newBufObj); 501 502 /* Pass BindBuffer call to device driver */ 503 if (ctx->Driver.BindBuffer && newBufObj) 504 ctx->Driver.BindBuffer( ctx, target, newBufObj ); 505} 506 507 508/** 509 * Update the default buffer objects in the given context to reference those 510 * specified in the shared state and release those referencing the old 511 * shared state. 512 */ 513void 514_mesa_update_default_objects_buffer_objects(GLcontext *ctx) 515{ 516 /* Bind the NullBufferObj to remove references to those 517 * in the shared context hash table. 518 */ 519 bind_buffer_object( ctx, GL_ARRAY_BUFFER_ARB, 0); 520 bind_buffer_object( ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, 0); 521 bind_buffer_object( ctx, GL_PIXEL_PACK_BUFFER_ARB, 0); 522 bind_buffer_object( ctx, GL_PIXEL_UNPACK_BUFFER_ARB, 0); 523} 524 525 526/** 527 * When we're about to read pixel data out of a PBO (via glDrawPixels, 528 * glTexImage, etc) or write data into a PBO (via glReadPixels, 529 * glGetTexImage, etc) we call this function to check that we're not 530 * going to read out of bounds. 531 * 532 * XXX This would also be a convenient time to check that the PBO isn't 533 * currently mapped. Whoever calls this function should check for that. 534 * Remember, we can't use a PBO when it's mapped! 535 * 536 * \param width width of image to read/write 537 * \param height height of image to read/write 538 * \param depth depth of image to read/write 539 * \param format format of image to read/write 540 * \param type datatype of image to read/write 541 * \param ptr the user-provided pointer/offset 542 * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would 543 * go out of bounds. 544 */ 545GLboolean 546_mesa_validate_pbo_access(GLuint dimensions, 547 const struct gl_pixelstore_attrib *pack, 548 GLsizei width, GLsizei height, GLsizei depth, 549 GLenum format, GLenum type, const GLvoid *ptr) 550{ 551 GLvoid *start, *end; 552 const GLubyte *sizeAddr; /* buffer size, cast to a pointer */ 553 554 ASSERT(pack->BufferObj->Name != 0); 555 556 if (pack->BufferObj->Size == 0) 557 /* no buffer! */ 558 return GL_FALSE; 559 560 /* get address of first pixel we'll read */ 561 start = _mesa_image_address(dimensions, pack, ptr, width, height, 562 format, type, 0, 0, 0); 563 564 /* get address just past the last pixel we'll read */ 565 end = _mesa_image_address(dimensions, pack, ptr, width, height, 566 format, type, depth-1, height-1, width); 567 568 569 sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size; 570 571 if ((const GLubyte *) start > sizeAddr) { 572 /* This will catch negative values / wrap-around */ 573 return GL_FALSE; 574 } 575 if ((const GLubyte *) end > sizeAddr) { 576 /* Image read goes beyond end of buffer */ 577 return GL_FALSE; 578 } 579 580 /* OK! */ 581 return GL_TRUE; 582} 583 584 585/** 586 * If the source of glBitmap data is a PBO, check that we won't read out 587 * of buffer bounds, then map the buffer. 588 * If not sourcing from a PBO, just return the bitmap pointer. 589 * This is a helper function for (some) drivers. 590 * Return NULL if error. 591 * If non-null return, must call _mesa_unmap_bitmap_pbo() when done. 592 */ 593const GLubyte * 594_mesa_map_bitmap_pbo(GLcontext *ctx, 595 const struct gl_pixelstore_attrib *unpack, 596 const GLubyte *bitmap) 597{ 598 const GLubyte *buf; 599 600 if (unpack->BufferObj->Name) { 601 /* unpack from PBO */ 602 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, 603 GL_READ_ONLY_ARB, 604 unpack->BufferObj); 605 if (!buf) 606 return NULL; 607 608 buf = ADD_POINTERS(buf, bitmap); 609 } 610 else { 611 /* unpack from normal memory */ 612 buf = bitmap; 613 } 614 615 return buf; 616} 617 618 619/** 620 * Counterpart to _mesa_map_bitmap_pbo() 621 * This is a helper function for (some) drivers. 622 */ 623void 624_mesa_unmap_bitmap_pbo(GLcontext *ctx, 625 const struct gl_pixelstore_attrib *unpack) 626{ 627 if (unpack->BufferObj->Name) { 628 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, 629 unpack->BufferObj); 630 } 631} 632 633 634/** 635 * \sa _mesa_map_bitmap_pbo 636 */ 637const GLvoid * 638_mesa_map_drawpix_pbo(GLcontext *ctx, 639 const struct gl_pixelstore_attrib *unpack, 640 const GLvoid *pixels) 641{ 642 const GLvoid *buf; 643 644 if (unpack->BufferObj->Name) { 645 /* unpack from PBO */ 646 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, 647 GL_READ_ONLY_ARB, 648 unpack->BufferObj); 649 if (!buf) 650 return NULL; 651 652 buf = ADD_POINTERS(buf, pixels); 653 } 654 else { 655 /* unpack from normal memory */ 656 buf = pixels; 657 } 658 659 return buf; 660} 661 662 663/** 664 * \sa _mesa_unmap_bitmap_pbo 665 */ 666void 667_mesa_unmap_drapix_pbo(GLcontext *ctx, 668 const struct gl_pixelstore_attrib *unpack) 669{ 670 if (unpack->BufferObj->Name) { 671 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, 672 unpack->BufferObj); 673 } 674} 675 676 677/** 678 * If PBO is bound, map the buffer, return dest pointer in mapped buffer. 679 * Call _mesa_unmap_readpix_pbo() when finished 680 * \return NULL if error 681 */ 682void * 683_mesa_map_readpix_pbo(GLcontext *ctx, 684 const struct gl_pixelstore_attrib *pack, 685 GLvoid *dest) 686{ 687 void *buf; 688 689 if (pack->BufferObj->Name) { 690 /* pack into PBO */ 691 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, 692 GL_WRITE_ONLY_ARB, 693 pack->BufferObj); 694 if (!buf) 695 return NULL; 696 697 buf = ADD_POINTERS(buf, dest); 698 } 699 else { 700 /* pack to normal memory */ 701 buf = dest; 702 } 703 704 return buf; 705} 706 707 708/** 709 * Counterpart to _mesa_map_readpix_pbo() 710 */ 711void 712_mesa_unmap_readpix_pbo(GLcontext *ctx, 713 const struct gl_pixelstore_attrib *pack) 714{ 715 if (pack->BufferObj->Name) { 716 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj); 717 } 718} 719 720 721 722/** 723 * Return the gl_buffer_object for the given ID. 724 * Always return NULL for ID 0. 725 */ 726struct gl_buffer_object * 727_mesa_lookup_bufferobj(GLcontext *ctx, GLuint buffer) 728{ 729 if (buffer == 0) 730 return NULL; 731 else 732 return (struct gl_buffer_object *) 733 _mesa_HashLookup(ctx->Shared->BufferObjects, buffer); 734} 735 736 737/** 738 * If *ptr points to obj, set ptr = the Null/default buffer object. 739 * This is a helper for buffer object deletion. 740 * The GL spec says that deleting a buffer object causes it to get 741 * unbound from all arrays in the current context. 742 */ 743static void 744unbind(GLcontext *ctx, 745 struct gl_buffer_object **ptr, 746 struct gl_buffer_object *obj) 747{ 748 if (*ptr == obj) { 749 _mesa_reference_buffer_object(ctx, ptr, ctx->Array.NullBufferObj); 750 } 751} 752 753 754 755/**********************************************************************/ 756/* API Functions */ 757/**********************************************************************/ 758 759void GLAPIENTRY 760_mesa_BindBufferARB(GLenum target, GLuint buffer) 761{ 762 GET_CURRENT_CONTEXT(ctx); 763 ASSERT_OUTSIDE_BEGIN_END(ctx); 764 765 bind_buffer_object(ctx, target, buffer); 766} 767 768 769/** 770 * Delete a set of buffer objects. 771 * 772 * \param n Number of buffer objects to delete. 773 * \param ids Array of \c n buffer object IDs. 774 */ 775void GLAPIENTRY 776_mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids) 777{ 778 GET_CURRENT_CONTEXT(ctx); 779 GLsizei i; 780 ASSERT_OUTSIDE_BEGIN_END(ctx); 781 782 if (n < 0) { 783 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)"); 784 return; 785 } 786 787 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 788 789 for (i = 0; i < n; i++) { 790 struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]); 791 if (bufObj) { 792 /* unbind any vertex pointers bound to this buffer */ 793 GLuint j; 794 795 ASSERT(bufObj->Name == ids[i]); 796 797 if (bufObj->Pointer) { 798 /* if mapped, unmap it now */ 799 ctx->Driver.UnmapBuffer(ctx, 0, bufObj); 800 bufObj->Access = GL_READ_WRITE_ARB; 801 bufObj->Pointer = NULL; 802 } 803 804 unbind(ctx, &ctx->Array.ArrayObj->Vertex.BufferObj, bufObj); 805 unbind(ctx, &ctx->Array.ArrayObj->Normal.BufferObj, bufObj); 806 unbind(ctx, &ctx->Array.ArrayObj->Color.BufferObj, bufObj); 807 unbind(ctx, &ctx->Array.ArrayObj->SecondaryColor.BufferObj, bufObj); 808 unbind(ctx, &ctx->Array.ArrayObj->FogCoord.BufferObj, bufObj); 809 unbind(ctx, &ctx->Array.ArrayObj->Index.BufferObj, bufObj); 810 unbind(ctx, &ctx->Array.ArrayObj->EdgeFlag.BufferObj, bufObj); 811 for (j = 0; j < MAX_TEXTURE_COORD_UNITS; j++) { 812 unbind(ctx, &ctx->Array.ArrayObj->TexCoord[j].BufferObj, bufObj); 813 } 814 for (j = 0; j < VERT_ATTRIB_MAX; j++) { 815 unbind(ctx, &ctx->Array.ArrayObj->VertexAttrib[j].BufferObj, bufObj); 816 } 817 818 if (ctx->Array.ArrayBufferObj == bufObj) { 819 _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 ); 820 } 821 if (ctx->Array.ElementArrayBufferObj == bufObj) { 822 _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 ); 823 } 824 825 if (ctx->Pack.BufferObj == bufObj) { 826 _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 ); 827 } 828 if (ctx->Unpack.BufferObj == bufObj) { 829 _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 ); 830 } 831 832 /* The ID is immediately freed for re-use */ 833 _mesa_HashRemove(ctx->Shared->BufferObjects, bufObj->Name); 834 _mesa_reference_buffer_object(ctx, &bufObj, NULL); 835 } 836 } 837 838 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 839} 840 841 842/** 843 * Generate a set of unique buffer object IDs and store them in \c buffer. 844 * 845 * \param n Number of IDs to generate. 846 * \param buffer Array of \c n locations to store the IDs. 847 */ 848void GLAPIENTRY 849_mesa_GenBuffersARB(GLsizei n, GLuint *buffer) 850{ 851 GET_CURRENT_CONTEXT(ctx); 852 GLuint first; 853 GLint i; 854 ASSERT_OUTSIDE_BEGIN_END(ctx); 855 856 if (n < 0) { 857 _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB"); 858 return; 859 } 860 861 if (!buffer) { 862 return; 863 } 864 865 /* 866 * This must be atomic (generation and allocation of buffer object IDs) 867 */ 868 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 869 870 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n); 871 872 /* Allocate new, empty buffer objects and return identifiers */ 873 for (i = 0; i < n; i++) { 874 struct gl_buffer_object *bufObj; 875 GLuint name = first + i; 876 GLenum target = 0; 877 bufObj = ctx->Driver.NewBufferObject( ctx, name, target ); 878 if (!bufObj) { 879 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 880 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenBuffersARB"); 881 return; 882 } 883 _mesa_HashInsert(ctx->Shared->BufferObjects, first + i, bufObj); 884 buffer[i] = first + i; 885 } 886 887 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 888} 889 890 891/** 892 * Determine if ID is the name of a buffer object. 893 * 894 * \param id ID of the potential buffer object. 895 * \return \c GL_TRUE if \c id is the name of a buffer object, 896 * \c GL_FALSE otherwise. 897 */ 898GLboolean GLAPIENTRY 899_mesa_IsBufferARB(GLuint id) 900{ 901 struct gl_buffer_object *bufObj; 902 GET_CURRENT_CONTEXT(ctx); 903 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 904 905 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 906 bufObj = _mesa_lookup_bufferobj(ctx, id); 907 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 908 909 return bufObj ? GL_TRUE : GL_FALSE; 910} 911 912 913void GLAPIENTRY 914_mesa_BufferDataARB(GLenum target, GLsizeiptrARB size, 915 const GLvoid * data, GLenum usage) 916{ 917 GET_CURRENT_CONTEXT(ctx); 918 struct gl_buffer_object *bufObj; 919 ASSERT_OUTSIDE_BEGIN_END(ctx); 920 921 if (size < 0) { 922 _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)"); 923 return; 924 } 925 926 switch (usage) { 927 case GL_STREAM_DRAW_ARB: 928 case GL_STREAM_READ_ARB: 929 case GL_STREAM_COPY_ARB: 930 case GL_STATIC_DRAW_ARB: 931 case GL_STATIC_READ_ARB: 932 case GL_STATIC_COPY_ARB: 933 case GL_DYNAMIC_DRAW_ARB: 934 case GL_DYNAMIC_READ_ARB: 935 case GL_DYNAMIC_COPY_ARB: 936 /* OK */ 937 break; 938 default: 939 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)"); 940 return; 941 } 942 943 bufObj = get_buffer(ctx, target); 944 if (!bufObj) { 945 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(target)" ); 946 return; 947 } 948 if (bufObj->Name == 0) { 949 _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB" ); 950 return; 951 } 952 953 if (bufObj->Pointer) { 954 /* Unmap the existing buffer. We'll replace it now. Not an error. */ 955 ctx->Driver.UnmapBuffer(ctx, target, bufObj); 956 bufObj->Access = GL_READ_WRITE_ARB; 957 bufObj->Pointer = NULL; 958 } 959 960 ASSERT(ctx->Driver.BufferData); 961 962 /* Give the buffer object to the driver! <data> may be null! */ 963 ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj ); 964} 965 966 967void GLAPIENTRY 968_mesa_BufferSubDataARB(GLenum target, GLintptrARB offset, 969 GLsizeiptrARB size, const GLvoid * data) 970{ 971 GET_CURRENT_CONTEXT(ctx); 972 struct gl_buffer_object *bufObj; 973 ASSERT_OUTSIDE_BEGIN_END(ctx); 974 975 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, 976 "glBufferSubDataARB" ); 977 if (!bufObj) { 978 /* error already recorded */ 979 return; 980 } 981 982 ASSERT(ctx->Driver.BufferSubData); 983 ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj ); 984} 985 986 987void GLAPIENTRY 988_mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset, 989 GLsizeiptrARB size, void * data) 990{ 991 GET_CURRENT_CONTEXT(ctx); 992 struct gl_buffer_object *bufObj; 993 ASSERT_OUTSIDE_BEGIN_END(ctx); 994 995 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, 996 "glGetBufferSubDataARB" ); 997 if (!bufObj) { 998 /* error already recorded */ 999 return; 1000 } 1001 1002 ASSERT(ctx->Driver.GetBufferSubData); 1003 ctx->Driver.GetBufferSubData( ctx, target, offset, size, data, bufObj ); 1004} 1005 1006 1007void * GLAPIENTRY 1008_mesa_MapBufferARB(GLenum target, GLenum access) 1009{ 1010 GET_CURRENT_CONTEXT(ctx); 1011 struct gl_buffer_object * bufObj; 1012 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); 1013 1014 switch (access) { 1015 case GL_READ_ONLY_ARB: 1016 case GL_WRITE_ONLY_ARB: 1017 case GL_READ_WRITE_ARB: 1018 /* OK */ 1019 break; 1020 default: 1021 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)"); 1022 return NULL; 1023 } 1024 1025 bufObj = get_buffer(ctx, target); 1026 if (!bufObj) { 1027 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(target)" ); 1028 return NULL; 1029 } 1030 if (bufObj->Name == 0) { 1031 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB" ); 1032 return NULL; 1033 } 1034 if (bufObj->Pointer) { 1035 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)"); 1036 return NULL; 1037 } 1038 1039 ASSERT(ctx->Driver.MapBuffer); 1040 bufObj->Pointer = ctx->Driver.MapBuffer( ctx, target, access, bufObj ); 1041 if (!bufObj->Pointer) { 1042 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(access)"); 1043 } 1044 1045 bufObj->Access = access; 1046 1047 return bufObj->Pointer; 1048} 1049 1050 1051GLboolean GLAPIENTRY 1052_mesa_UnmapBufferARB(GLenum target) 1053{ 1054 GET_CURRENT_CONTEXT(ctx); 1055 struct gl_buffer_object *bufObj; 1056 GLboolean status = GL_TRUE; 1057 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 1058 1059 bufObj = get_buffer(ctx, target); 1060 if (!bufObj) { 1061 _mesa_error(ctx, GL_INVALID_ENUM, "glUnmapBufferARB(target)" ); 1062 return GL_FALSE; 1063 } 1064 if (bufObj->Name == 0) { 1065 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" ); 1066 return GL_FALSE; 1067 } 1068 if (!bufObj->Pointer) { 1069 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB"); 1070 return GL_FALSE; 1071 } 1072 1073 status = ctx->Driver.UnmapBuffer( ctx, target, bufObj ); 1074 bufObj->Access = GL_READ_WRITE_ARB; 1075 bufObj->Pointer = NULL; 1076 1077 return status; 1078} 1079 1080 1081void GLAPIENTRY 1082_mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params) 1083{ 1084 GET_CURRENT_CONTEXT(ctx); 1085 struct gl_buffer_object *bufObj; 1086 ASSERT_OUTSIDE_BEGIN_END(ctx); 1087 1088 bufObj = get_buffer(ctx, target); 1089 if (!bufObj) { 1090 _mesa_error(ctx, GL_INVALID_ENUM, "GetBufferParameterivARB(target)" ); 1091 return; 1092 } 1093 if (bufObj->Name == 0) { 1094 _mesa_error(ctx, GL_INVALID_OPERATION, "GetBufferParameterivARB" ); 1095 return; 1096 } 1097 1098 switch (pname) { 1099 case GL_BUFFER_SIZE_ARB: 1100 *params = (GLint) bufObj->Size; 1101 break; 1102 case GL_BUFFER_USAGE_ARB: 1103 *params = bufObj->Usage; 1104 break; 1105 case GL_BUFFER_ACCESS_ARB: 1106 *params = bufObj->Access; 1107 break; 1108 case GL_BUFFER_MAPPED_ARB: 1109 *params = (bufObj->Pointer != NULL); 1110 break; 1111 default: 1112 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname)"); 1113 return; 1114 } 1115} 1116 1117 1118void GLAPIENTRY 1119_mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params) 1120{ 1121 GET_CURRENT_CONTEXT(ctx); 1122 struct gl_buffer_object * bufObj; 1123 ASSERT_OUTSIDE_BEGIN_END(ctx); 1124 1125 if (pname != GL_BUFFER_MAP_POINTER_ARB) { 1126 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)"); 1127 return; 1128 } 1129 1130 bufObj = get_buffer(ctx, target); 1131 if (!bufObj) { 1132 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(target)" ); 1133 return; 1134 } 1135 if (bufObj->Name == 0) { 1136 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferPointervARB" ); 1137 return; 1138 } 1139 1140 *params = bufObj->Pointer; 1141} 1142