bufferobj.c revision cdc920a0
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.6 4 * 5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 6 * Copyright (C) 2009 VMware, Inc. All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included 16 * in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 26 27/** 28 * \file bufferobj.c 29 * \brief Functions for the GL_ARB_vertex/pixel_buffer_object extensions. 30 * \author Brian Paul, Ian Romanick 31 */ 32 33 34#include "glheader.h" 35#include "hash.h" 36#include "imports.h" 37#include "image.h" 38#include "context.h" 39#include "bufferobj.h" 40#include "fbobject.h" 41#include "texobj.h" 42 43 44/* Debug flags */ 45/*#define VBO_DEBUG*/ 46/*#define BOUNDS_CHECK*/ 47 48 49#ifdef FEATURE_OES_mapbuffer 50#define DEFAULT_ACCESS GL_MAP_WRITE_BIT 51#else 52#define DEFAULT_ACCESS (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT) 53#endif 54 55 56/** 57 * Return pointer to address of a buffer object target. 58 * \param ctx the GL context 59 * \param target the buffer object target to be retrieved. 60 * \return pointer to pointer to the buffer object bound to \c target in the 61 * specified context or \c NULL if \c target is invalid. 62 */ 63static INLINE struct gl_buffer_object ** 64get_buffer_target(GLcontext *ctx, GLenum target) 65{ 66 switch (target) { 67 case GL_ARRAY_BUFFER_ARB: 68 return &ctx->Array.ArrayBufferObj; 69 case GL_ELEMENT_ARRAY_BUFFER_ARB: 70 return &ctx->Array.ElementArrayBufferObj; 71 case GL_PIXEL_PACK_BUFFER_EXT: 72 return &ctx->Pack.BufferObj; 73 case GL_PIXEL_UNPACK_BUFFER_EXT: 74 return &ctx->Unpack.BufferObj; 75 case GL_COPY_READ_BUFFER: 76 if (ctx->Extensions.ARB_copy_buffer) { 77 return &ctx->CopyReadBuffer; 78 } 79 break; 80 case GL_COPY_WRITE_BUFFER: 81 if (ctx->Extensions.ARB_copy_buffer) { 82 return &ctx->CopyWriteBuffer; 83 } 84 break; 85 default: 86 return NULL; 87 } 88 return NULL; 89} 90 91 92/** 93 * Get the buffer object bound to the specified target in a GL context. 94 * \param ctx the GL context 95 * \param target the buffer object target to be retrieved. 96 * \return pointer to the buffer object bound to \c target in the 97 * specified context or \c NULL if \c target is invalid. 98 */ 99static INLINE struct gl_buffer_object * 100get_buffer(GLcontext *ctx, GLenum target) 101{ 102 struct gl_buffer_object **bufObj = get_buffer_target(ctx, target); 103 if (bufObj) 104 return *bufObj; 105 return NULL; 106} 107 108 109/** 110 * Convert a GLbitfield describing the mapped buffer access flags 111 * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY. 112 */ 113static GLenum 114simplified_access_mode(GLbitfield access) 115{ 116 const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; 117 if ((access & rwFlags) == rwFlags) 118 return GL_READ_WRITE; 119 if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT) 120 return GL_READ_ONLY; 121 if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT) 122 return GL_WRITE_ONLY; 123 return GL_READ_WRITE; /* this should never happen, but no big deal */ 124} 125 126 127/** 128 * Tests the subdata range parameters and sets the GL error code for 129 * \c glBufferSubDataARB and \c glGetBufferSubDataARB. 130 * 131 * \param ctx GL context. 132 * \param target Buffer object target on which to operate. 133 * \param offset Offset of the first byte of the subdata range. 134 * \param size Size, in bytes, of the subdata range. 135 * \param caller Name of calling function for recording errors. 136 * \return A pointer to the buffer object bound to \c target in the 137 * specified context or \c NULL if any of the parameter or state 138 * conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB 139 * are invalid. 140 * 141 * \sa glBufferSubDataARB, glGetBufferSubDataARB 142 */ 143static struct gl_buffer_object * 144buffer_object_subdata_range_good( GLcontext * ctx, GLenum target, 145 GLintptrARB offset, GLsizeiptrARB size, 146 const char *caller ) 147{ 148 struct gl_buffer_object *bufObj; 149 150 if (size < 0) { 151 _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller); 152 return NULL; 153 } 154 155 if (offset < 0) { 156 _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller); 157 return NULL; 158 } 159 160 bufObj = get_buffer(ctx, target); 161 if (!bufObj) { 162 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", caller); 163 return NULL; 164 } 165 if (!_mesa_is_bufferobj(bufObj)) { 166 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); 167 return NULL; 168 } 169 if (offset + size > bufObj->Size) { 170 _mesa_error(ctx, GL_INVALID_VALUE, 171 "%s(size + offset > buffer size)", caller); 172 return NULL; 173 } 174 if (_mesa_bufferobj_mapped(bufObj)) { 175 /* Buffer is currently mapped */ 176 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); 177 return NULL; 178 } 179 180 return bufObj; 181} 182 183 184/** 185 * Allocate and initialize a new buffer object. 186 * 187 * Default callback for the \c dd_function_table::NewBufferObject() hook. 188 */ 189static struct gl_buffer_object * 190_mesa_new_buffer_object( GLcontext *ctx, GLuint name, GLenum target ) 191{ 192 struct gl_buffer_object *obj; 193 194 (void) ctx; 195 196 obj = MALLOC_STRUCT(gl_buffer_object); 197 _mesa_initialize_buffer_object(obj, name, target); 198 return obj; 199} 200 201 202/** 203 * Delete a buffer object. 204 * 205 * Default callback for the \c dd_function_table::DeleteBuffer() hook. 206 */ 207static void 208_mesa_delete_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj ) 209{ 210 (void) ctx; 211 212 if (bufObj->Data) 213 free(bufObj->Data); 214 215 /* assign strange values here to help w/ debugging */ 216 bufObj->RefCount = -1000; 217 bufObj->Name = ~0; 218 219 _glthread_DESTROY_MUTEX(bufObj->Mutex); 220 free(bufObj); 221} 222 223 224 225/** 226 * Set ptr to bufObj w/ reference counting. 227 */ 228void 229_mesa_reference_buffer_object(GLcontext *ctx, 230 struct gl_buffer_object **ptr, 231 struct gl_buffer_object *bufObj) 232{ 233 if (*ptr == bufObj) 234 return; 235 236 if (*ptr) { 237 /* Unreference the old buffer */ 238 GLboolean deleteFlag = GL_FALSE; 239 struct gl_buffer_object *oldObj = *ptr; 240 241 _glthread_LOCK_MUTEX(oldObj->Mutex); 242 ASSERT(oldObj->RefCount > 0); 243 oldObj->RefCount--; 244#if 0 245 printf("BufferObj %p %d DECR to %d\n", 246 (void *) oldObj, oldObj->Name, oldObj->RefCount); 247#endif 248 deleteFlag = (oldObj->RefCount == 0); 249 _glthread_UNLOCK_MUTEX(oldObj->Mutex); 250 251 if (deleteFlag) { 252 253 /* some sanity checking: don't delete a buffer still in use */ 254#if 0 255 /* unfortunately, these tests are invalid during context tear-down */ 256 ASSERT(ctx->Array.ArrayBufferObj != bufObj); 257 ASSERT(ctx->Array.ElementArrayBufferObj != bufObj); 258 ASSERT(ctx->Array.ArrayObj->Vertex.BufferObj != bufObj); 259#endif 260 261 ASSERT(ctx->Driver.DeleteBuffer); 262 ctx->Driver.DeleteBuffer(ctx, oldObj); 263 } 264 265 *ptr = NULL; 266 } 267 ASSERT(!*ptr); 268 269 if (bufObj) { 270 /* reference new buffer */ 271 _glthread_LOCK_MUTEX(bufObj->Mutex); 272 if (bufObj->RefCount == 0) { 273 /* this buffer's being deleted (look just above) */ 274 /* Not sure this can every really happen. Warn if it does. */ 275 _mesa_problem(NULL, "referencing deleted buffer object"); 276 *ptr = NULL; 277 } 278 else { 279 bufObj->RefCount++; 280#if 0 281 printf("BufferObj %p %d INCR to %d\n", 282 (void *) bufObj, bufObj->Name, bufObj->RefCount); 283#endif 284 *ptr = bufObj; 285 } 286 _glthread_UNLOCK_MUTEX(bufObj->Mutex); 287 } 288} 289 290 291/** 292 * Initialize a buffer object to default values. 293 */ 294void 295_mesa_initialize_buffer_object( struct gl_buffer_object *obj, 296 GLuint name, GLenum target ) 297{ 298 (void) target; 299 300 memset(obj, 0, sizeof(struct gl_buffer_object)); 301 _glthread_INIT_MUTEX(obj->Mutex); 302 obj->RefCount = 1; 303 obj->Name = name; 304 obj->Usage = GL_STATIC_DRAW_ARB; 305 obj->AccessFlags = DEFAULT_ACCESS; 306} 307 308 309/** 310 * Allocate space for and store data in a buffer object. Any data that was 311 * previously stored in the buffer object is lost. If \c data is \c NULL, 312 * memory will be allocated, but no copy will occur. 313 * 314 * This is the default callback for \c dd_function_table::BufferData() 315 * Note that all GL error checking will have been done already. 316 * 317 * \param ctx GL context. 318 * \param target Buffer object target on which to operate. 319 * \param size Size, in bytes, of the new data store. 320 * \param data Pointer to the data to store in the buffer object. This 321 * pointer may be \c NULL. 322 * \param usage Hints about how the data will be used. 323 * \param bufObj Object to be used. 324 * 325 * \return GL_TRUE for success, GL_FALSE for failure 326 * \sa glBufferDataARB, dd_function_table::BufferData. 327 */ 328static GLboolean 329_mesa_buffer_data( GLcontext *ctx, GLenum target, GLsizeiptrARB size, 330 const GLvoid * data, GLenum usage, 331 struct gl_buffer_object * bufObj ) 332{ 333 void * new_data; 334 335 (void) ctx; (void) target; 336 337 new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size ); 338 if (new_data) { 339 bufObj->Data = (GLubyte *) new_data; 340 bufObj->Size = size; 341 bufObj->Usage = usage; 342 343 if (data) { 344 memcpy( bufObj->Data, data, size ); 345 } 346 347 return GL_TRUE; 348 } 349 else { 350 return GL_FALSE; 351 } 352} 353 354 355/** 356 * Replace data in a subrange of buffer object. If the data range 357 * specified by \c size + \c offset extends beyond the end of the buffer or 358 * if \c data is \c NULL, no copy is performed. 359 * 360 * This is the default callback for \c dd_function_table::BufferSubData() 361 * Note that all GL error checking will have been done already. 362 * 363 * \param ctx GL context. 364 * \param target Buffer object target on which to operate. 365 * \param offset Offset of the first byte to be modified. 366 * \param size Size, in bytes, of the data range. 367 * \param data Pointer to the data to store in the buffer object. 368 * \param bufObj Object to be used. 369 * 370 * \sa glBufferSubDataARB, dd_function_table::BufferSubData. 371 */ 372static void 373_mesa_buffer_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset, 374 GLsizeiptrARB size, const GLvoid * data, 375 struct gl_buffer_object * bufObj ) 376{ 377 (void) ctx; (void) target; 378 379 /* this should have been caught in _mesa_BufferSubData() */ 380 ASSERT(size + offset <= bufObj->Size); 381 382 if (bufObj->Data) { 383 memcpy( (GLubyte *) bufObj->Data + offset, data, size ); 384 } 385} 386 387 388/** 389 * Retrieve data from a subrange of buffer object. If the data range 390 * specified by \c size + \c offset extends beyond the end of the buffer or 391 * if \c data is \c NULL, no copy is performed. 392 * 393 * This is the default callback for \c dd_function_table::GetBufferSubData() 394 * Note that all GL error checking will have been done already. 395 * 396 * \param ctx GL context. 397 * \param target Buffer object target on which to operate. 398 * \param offset Offset of the first byte to be fetched. 399 * \param size Size, in bytes, of the data range. 400 * \param data Destination for data 401 * \param bufObj Object to be used. 402 * 403 * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData. 404 */ 405static void 406_mesa_buffer_get_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset, 407 GLsizeiptrARB size, GLvoid * data, 408 struct gl_buffer_object * bufObj ) 409{ 410 (void) ctx; (void) target; 411 412 if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) { 413 memcpy( data, (GLubyte *) bufObj->Data + offset, size ); 414 } 415} 416 417 418/** 419 * Default callback for \c dd_function_tabel::MapBuffer(). 420 * 421 * The function parameters will have been already tested for errors. 422 * 423 * \param ctx GL context. 424 * \param target Buffer object target on which to operate. 425 * \param access Information about how the buffer will be accessed. 426 * \param bufObj Object to be mapped. 427 * \return A pointer to the object's internal data store that can be accessed 428 * by the processor 429 * 430 * \sa glMapBufferARB, dd_function_table::MapBuffer 431 */ 432static void * 433_mesa_buffer_map( GLcontext *ctx, GLenum target, GLenum access, 434 struct gl_buffer_object *bufObj ) 435{ 436 (void) ctx; 437 (void) target; 438 (void) access; 439 /* Just return a direct pointer to the data */ 440 if (_mesa_bufferobj_mapped(bufObj)) { 441 /* already mapped! */ 442 return NULL; 443 } 444 bufObj->Pointer = bufObj->Data; 445 bufObj->Length = bufObj->Size; 446 bufObj->Offset = 0; 447 return bufObj->Pointer; 448} 449 450 451/** 452 * Default fallback for \c dd_function_table::MapBufferRange(). 453 * Called via glMapBufferRange(). 454 */ 455static void * 456_mesa_buffer_map_range( GLcontext *ctx, GLenum target, GLintptr offset, 457 GLsizeiptr length, GLbitfield access, 458 struct gl_buffer_object *bufObj ) 459{ 460 (void) ctx; 461 (void) target; 462 assert(!_mesa_bufferobj_mapped(bufObj)); 463 /* Just return a direct pointer to the data */ 464 bufObj->Pointer = bufObj->Data + offset; 465 bufObj->Length = length; 466 bufObj->Offset = offset; 467 bufObj->AccessFlags = access; 468 return bufObj->Pointer; 469} 470 471 472/** 473 * Default fallback for \c dd_function_table::FlushMappedBufferRange(). 474 * Called via glFlushMappedBufferRange(). 475 */ 476static void 477_mesa_buffer_flush_mapped_range( GLcontext *ctx, GLenum target, 478 GLintptr offset, GLsizeiptr length, 479 struct gl_buffer_object *obj ) 480{ 481 (void) ctx; 482 (void) target; 483 (void) offset; 484 (void) length; 485 (void) obj; 486 /* no-op */ 487} 488 489 490/** 491 * Default callback for \c dd_function_table::MapBuffer(). 492 * 493 * The input parameters will have been already tested for errors. 494 * 495 * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer 496 */ 497static GLboolean 498_mesa_buffer_unmap( GLcontext *ctx, GLenum target, 499 struct gl_buffer_object *bufObj ) 500{ 501 (void) ctx; 502 (void) target; 503 /* XXX we might assert here that bufObj->Pointer is non-null */ 504 bufObj->Pointer = NULL; 505 bufObj->Length = 0; 506 bufObj->Offset = 0; 507 bufObj->AccessFlags = 0x0; 508 return GL_TRUE; 509} 510 511 512/** 513 * Default fallback for \c dd_function_table::CopyBufferSubData(). 514 * Called via glCopyBuffserSubData(). 515 */ 516static void 517_mesa_copy_buffer_subdata(GLcontext *ctx, 518 struct gl_buffer_object *src, 519 struct gl_buffer_object *dst, 520 GLintptr readOffset, GLintptr writeOffset, 521 GLsizeiptr size) 522{ 523 GLubyte *srcPtr, *dstPtr; 524 525 /* buffer should not already be mapped */ 526 assert(!_mesa_bufferobj_mapped(src)); 527 assert(!_mesa_bufferobj_mapped(dst)); 528 529 srcPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_READ_BUFFER, 530 GL_READ_ONLY, src); 531 dstPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_WRITE_BUFFER, 532 GL_WRITE_ONLY, dst); 533 534 if (srcPtr && dstPtr) 535 memcpy(dstPtr + writeOffset, srcPtr + readOffset, size); 536 537 ctx->Driver.UnmapBuffer(ctx, GL_COPY_READ_BUFFER, src); 538 ctx->Driver.UnmapBuffer(ctx, GL_COPY_WRITE_BUFFER, dst); 539} 540 541 542 543/** 544 * Initialize the state associated with buffer objects 545 */ 546void 547_mesa_init_buffer_objects( GLcontext *ctx ) 548{ 549 _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, 550 ctx->Shared->NullBufferObj); 551 _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, 552 ctx->Shared->NullBufferObj); 553 554 _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, 555 ctx->Shared->NullBufferObj); 556 _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, 557 ctx->Shared->NullBufferObj); 558} 559 560 561void 562_mesa_free_buffer_objects( GLcontext *ctx ) 563{ 564 _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL); 565 _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, NULL); 566 567 _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, NULL); 568 _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, NULL); 569} 570 571 572/** 573 * Bind the specified target to buffer for the specified context. 574 * Called by glBindBuffer() and other functions. 575 */ 576static void 577bind_buffer_object(GLcontext *ctx, GLenum target, GLuint buffer) 578{ 579 struct gl_buffer_object *oldBufObj; 580 struct gl_buffer_object *newBufObj = NULL; 581 struct gl_buffer_object **bindTarget = NULL; 582 583 bindTarget = get_buffer_target(ctx, target); 584 if (!bindTarget) { 585 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)"); 586 return; 587 } 588 589 /* Get pointer to old buffer object (to be unbound) */ 590 oldBufObj = *bindTarget; 591 if (oldBufObj && oldBufObj->Name == buffer) 592 return; /* rebinding the same buffer object- no change */ 593 594 /* 595 * Get pointer to new buffer object (newBufObj) 596 */ 597 if (buffer == 0) { 598 /* The spec says there's not a buffer object named 0, but we use 599 * one internally because it simplifies things. 600 */ 601 newBufObj = ctx->Shared->NullBufferObj; 602 } 603 else { 604 /* non-default buffer object */ 605 newBufObj = _mesa_lookup_bufferobj(ctx, buffer); 606 if (!newBufObj) { 607 /* if this is a new buffer object id, allocate a buffer object now */ 608 ASSERT(ctx->Driver.NewBufferObject); 609 newBufObj = ctx->Driver.NewBufferObject(ctx, buffer, target); 610 if (!newBufObj) { 611 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB"); 612 return; 613 } 614 _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, newBufObj); 615 } 616 } 617 618 /* bind new buffer */ 619 _mesa_reference_buffer_object(ctx, bindTarget, newBufObj); 620 621 /* Pass BindBuffer call to device driver */ 622 if (ctx->Driver.BindBuffer) 623 ctx->Driver.BindBuffer( ctx, target, newBufObj ); 624} 625 626 627/** 628 * Update the default buffer objects in the given context to reference those 629 * specified in the shared state and release those referencing the old 630 * shared state. 631 */ 632void 633_mesa_update_default_objects_buffer_objects(GLcontext *ctx) 634{ 635 /* Bind the NullBufferObj to remove references to those 636 * in the shared context hash table. 637 */ 638 bind_buffer_object( ctx, GL_ARRAY_BUFFER_ARB, 0); 639 bind_buffer_object( ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, 0); 640 bind_buffer_object( ctx, GL_PIXEL_PACK_BUFFER_ARB, 0); 641 bind_buffer_object( ctx, GL_PIXEL_UNPACK_BUFFER_ARB, 0); 642} 643 644 645/** 646 * When we're about to read pixel data out of a PBO (via glDrawPixels, 647 * glTexImage, etc) or write data into a PBO (via glReadPixels, 648 * glGetTexImage, etc) we call this function to check that we're not 649 * going to read out of bounds. 650 * 651 * XXX This would also be a convenient time to check that the PBO isn't 652 * currently mapped. Whoever calls this function should check for that. 653 * Remember, we can't use a PBO when it's mapped! 654 * 655 * If we're not using a PBO, this is a no-op. 656 * 657 * \param width width of image to read/write 658 * \param height height of image to read/write 659 * \param depth depth of image to read/write 660 * \param format format of image to read/write 661 * \param type datatype of image to read/write 662 * \param ptr the user-provided pointer/offset 663 * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would 664 * go out of bounds. 665 */ 666GLboolean 667_mesa_validate_pbo_access(GLuint dimensions, 668 const struct gl_pixelstore_attrib *pack, 669 GLsizei width, GLsizei height, GLsizei depth, 670 GLenum format, GLenum type, const GLvoid *ptr) 671{ 672 GLvoid *start, *end; 673 const GLubyte *sizeAddr; /* buffer size, cast to a pointer */ 674 675 if (!_mesa_is_bufferobj(pack->BufferObj)) 676 return GL_TRUE; /* no PBO, OK */ 677 678 if (pack->BufferObj->Size == 0) 679 /* no buffer! */ 680 return GL_FALSE; 681 682 /* get address of first pixel we'll read */ 683 start = _mesa_image_address(dimensions, pack, ptr, width, height, 684 format, type, 0, 0, 0); 685 686 /* get address just past the last pixel we'll read */ 687 end = _mesa_image_address(dimensions, pack, ptr, width, height, 688 format, type, depth-1, height-1, width); 689 690 691 sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size; 692 693 if ((const GLubyte *) start > sizeAddr) { 694 /* This will catch negative values / wrap-around */ 695 return GL_FALSE; 696 } 697 if ((const GLubyte *) end > sizeAddr) { 698 /* Image read goes beyond end of buffer */ 699 return GL_FALSE; 700 } 701 702 /* OK! */ 703 return GL_TRUE; 704} 705 706 707/** 708 * For commands that read from a PBO (glDrawPixels, glTexImage, 709 * glPolygonStipple, etc), if we're reading from a PBO, map it read-only 710 * and return the pointer into the PBO. If we're not reading from a 711 * PBO, return \p src as-is. 712 * If non-null return, must call _mesa_unmap_pbo_source() when done. 713 * 714 * \return NULL if error, else pointer to start of data 715 */ 716const GLvoid * 717_mesa_map_pbo_source(GLcontext *ctx, 718 const struct gl_pixelstore_attrib *unpack, 719 const GLvoid *src) 720{ 721 const GLubyte *buf; 722 723 if (_mesa_is_bufferobj(unpack->BufferObj)) { 724 /* unpack from PBO */ 725 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, 726 GL_READ_ONLY_ARB, 727 unpack->BufferObj); 728 if (!buf) 729 return NULL; 730 731 buf = ADD_POINTERS(buf, src); 732 } 733 else { 734 /* unpack from normal memory */ 735 buf = src; 736 } 737 738 return buf; 739} 740 741 742/** 743 * Combine PBO-read validation and mapping. 744 * If any GL errors are detected, they'll be recorded and NULL returned. 745 * \sa _mesa_validate_pbo_access 746 * \sa _mesa_map_pbo_source 747 * A call to this function should have a matching call to 748 * _mesa_unmap_pbo_source(). 749 */ 750const GLvoid * 751_mesa_map_validate_pbo_source(GLcontext *ctx, 752 GLuint dimensions, 753 const struct gl_pixelstore_attrib *unpack, 754 GLsizei width, GLsizei height, GLsizei depth, 755 GLenum format, GLenum type, const GLvoid *ptr, 756 const char *where) 757{ 758 ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); 759 760 if (!_mesa_is_bufferobj(unpack->BufferObj)) { 761 /* non-PBO access: no validation to be done */ 762 return ptr; 763 } 764 765 if (!_mesa_validate_pbo_access(dimensions, unpack, 766 width, height, depth, format, type, ptr)) { 767 _mesa_error(ctx, GL_INVALID_OPERATION, 768 "%s(out of bounds PBO access)", where); 769 return NULL; 770 } 771 772 if (_mesa_bufferobj_mapped(unpack->BufferObj)) { 773 /* buffer is already mapped - that's an error */ 774 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); 775 return NULL; 776 } 777 778 ptr = _mesa_map_pbo_source(ctx, unpack, ptr); 779 return ptr; 780} 781 782 783/** 784 * Counterpart to _mesa_map_pbo_source() 785 */ 786void 787_mesa_unmap_pbo_source(GLcontext *ctx, 788 const struct gl_pixelstore_attrib *unpack) 789{ 790 ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */ 791 if (_mesa_is_bufferobj(unpack->BufferObj)) { 792 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, 793 unpack->BufferObj); 794 } 795} 796 797 798/** 799 * For commands that write to a PBO (glReadPixels, glGetColorTable, etc), 800 * if we're writing to a PBO, map it write-only and return the pointer 801 * into the PBO. If we're not writing to a PBO, return \p dst as-is. 802 * If non-null return, must call _mesa_unmap_pbo_dest() when done. 803 * 804 * \return NULL if error, else pointer to start of data 805 */ 806void * 807_mesa_map_pbo_dest(GLcontext *ctx, 808 const struct gl_pixelstore_attrib *pack, 809 GLvoid *dest) 810{ 811 void *buf; 812 813 if (_mesa_is_bufferobj(pack->BufferObj)) { 814 /* pack into PBO */ 815 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, 816 GL_WRITE_ONLY_ARB, 817 pack->BufferObj); 818 if (!buf) 819 return NULL; 820 821 buf = ADD_POINTERS(buf, dest); 822 } 823 else { 824 /* pack to normal memory */ 825 buf = dest; 826 } 827 828 return buf; 829} 830 831 832/** 833 * Combine PBO-write validation and mapping. 834 * If any GL errors are detected, they'll be recorded and NULL returned. 835 * \sa _mesa_validate_pbo_access 836 * \sa _mesa_map_pbo_dest 837 * A call to this function should have a matching call to 838 * _mesa_unmap_pbo_dest(). 839 */ 840GLvoid * 841_mesa_map_validate_pbo_dest(GLcontext *ctx, 842 GLuint dimensions, 843 const struct gl_pixelstore_attrib *unpack, 844 GLsizei width, GLsizei height, GLsizei depth, 845 GLenum format, GLenum type, GLvoid *ptr, 846 const char *where) 847{ 848 ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); 849 850 if (!_mesa_is_bufferobj(unpack->BufferObj)) { 851 /* non-PBO access: no validation to be done */ 852 return ptr; 853 } 854 855 if (!_mesa_validate_pbo_access(dimensions, unpack, 856 width, height, depth, format, type, ptr)) { 857 _mesa_error(ctx, GL_INVALID_OPERATION, 858 "%s(out of bounds PBO access)", where); 859 return NULL; 860 } 861 862 if (_mesa_bufferobj_mapped(unpack->BufferObj)) { 863 /* buffer is already mapped - that's an error */ 864 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); 865 return NULL; 866 } 867 868 ptr = _mesa_map_pbo_dest(ctx, unpack, ptr); 869 return ptr; 870} 871 872 873/** 874 * Counterpart to _mesa_map_pbo_dest() 875 */ 876void 877_mesa_unmap_pbo_dest(GLcontext *ctx, 878 const struct gl_pixelstore_attrib *pack) 879{ 880 ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */ 881 if (_mesa_is_bufferobj(pack->BufferObj)) { 882 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj); 883 } 884} 885 886 887 888/** 889 * Return the gl_buffer_object for the given ID. 890 * Always return NULL for ID 0. 891 */ 892struct gl_buffer_object * 893_mesa_lookup_bufferobj(GLcontext *ctx, GLuint buffer) 894{ 895 if (buffer == 0) 896 return NULL; 897 else 898 return (struct gl_buffer_object *) 899 _mesa_HashLookup(ctx->Shared->BufferObjects, buffer); 900} 901 902 903/** 904 * If *ptr points to obj, set ptr = the Null/default buffer object. 905 * This is a helper for buffer object deletion. 906 * The GL spec says that deleting a buffer object causes it to get 907 * unbound from all arrays in the current context. 908 */ 909static void 910unbind(GLcontext *ctx, 911 struct gl_buffer_object **ptr, 912 struct gl_buffer_object *obj) 913{ 914 if (*ptr == obj) { 915 _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj); 916 } 917} 918 919 920/** 921 * Plug default/fallback buffer object functions into the device 922 * driver hooks. 923 */ 924void 925_mesa_init_buffer_object_functions(struct dd_function_table *driver) 926{ 927 /* GL_ARB_vertex/pixel_buffer_object */ 928 driver->NewBufferObject = _mesa_new_buffer_object; 929 driver->DeleteBuffer = _mesa_delete_buffer_object; 930 driver->BindBuffer = NULL; 931 driver->BufferData = _mesa_buffer_data; 932 driver->BufferSubData = _mesa_buffer_subdata; 933 driver->GetBufferSubData = _mesa_buffer_get_subdata; 934 driver->MapBuffer = _mesa_buffer_map; 935 driver->UnmapBuffer = _mesa_buffer_unmap; 936 937 /* GL_ARB_map_buffer_range */ 938 driver->MapBufferRange = _mesa_buffer_map_range; 939 driver->FlushMappedBufferRange = _mesa_buffer_flush_mapped_range; 940 941 /* GL_ARB_copy_buffer */ 942 driver->CopyBufferSubData = _mesa_copy_buffer_subdata; 943} 944 945 946 947/**********************************************************************/ 948/* API Functions */ 949/**********************************************************************/ 950 951void GLAPIENTRY 952_mesa_BindBufferARB(GLenum target, GLuint buffer) 953{ 954 GET_CURRENT_CONTEXT(ctx); 955 ASSERT_OUTSIDE_BEGIN_END(ctx); 956 957 bind_buffer_object(ctx, target, buffer); 958} 959 960 961/** 962 * Delete a set of buffer objects. 963 * 964 * \param n Number of buffer objects to delete. 965 * \param ids Array of \c n buffer object IDs. 966 */ 967void GLAPIENTRY 968_mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids) 969{ 970 GET_CURRENT_CONTEXT(ctx); 971 GLsizei i; 972 ASSERT_OUTSIDE_BEGIN_END(ctx); 973 974 if (n < 0) { 975 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)"); 976 return; 977 } 978 979 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 980 981 for (i = 0; i < n; i++) { 982 struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]); 983 if (bufObj) { 984 struct gl_array_object *arrayObj = ctx->Array.ArrayObj; 985 GLuint j; 986 987 ASSERT(bufObj->Name == ids[i]); 988 989 if (_mesa_bufferobj_mapped(bufObj)) { 990 /* if mapped, unmap it now */ 991 ctx->Driver.UnmapBuffer(ctx, 0, bufObj); 992 bufObj->AccessFlags = DEFAULT_ACCESS; 993 bufObj->Pointer = NULL; 994 } 995 996 /* unbind any vertex pointers bound to this buffer */ 997 unbind(ctx, &arrayObj->Vertex.BufferObj, bufObj); 998 unbind(ctx, &arrayObj->Weight.BufferObj, bufObj); 999 unbind(ctx, &arrayObj->Normal.BufferObj, bufObj); 1000 unbind(ctx, &arrayObj->Color.BufferObj, bufObj); 1001 unbind(ctx, &arrayObj->SecondaryColor.BufferObj, bufObj); 1002 unbind(ctx, &arrayObj->FogCoord.BufferObj, bufObj); 1003 unbind(ctx, &arrayObj->Index.BufferObj, bufObj); 1004 unbind(ctx, &arrayObj->EdgeFlag.BufferObj, bufObj); 1005 for (j = 0; j < Elements(arrayObj->TexCoord); j++) { 1006 unbind(ctx, &arrayObj->TexCoord[j].BufferObj, bufObj); 1007 } 1008 for (j = 0; j < Elements(arrayObj->VertexAttrib); j++) { 1009 unbind(ctx, &arrayObj->VertexAttrib[j].BufferObj, bufObj); 1010 } 1011 1012 if (ctx->Array.ArrayBufferObj == bufObj) { 1013 _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 ); 1014 } 1015 if (ctx->Array.ElementArrayBufferObj == bufObj) { 1016 _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 ); 1017 } 1018 1019 /* unbind any pixel pack/unpack pointers bound to this buffer */ 1020 if (ctx->Pack.BufferObj == bufObj) { 1021 _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 ); 1022 } 1023 if (ctx->Unpack.BufferObj == bufObj) { 1024 _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 ); 1025 } 1026 1027 /* The ID is immediately freed for re-use */ 1028 _mesa_HashRemove(ctx->Shared->BufferObjects, bufObj->Name); 1029 _mesa_reference_buffer_object(ctx, &bufObj, NULL); 1030 } 1031 } 1032 1033 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 1034} 1035 1036 1037/** 1038 * Generate a set of unique buffer object IDs and store them in \c buffer. 1039 * 1040 * \param n Number of IDs to generate. 1041 * \param buffer Array of \c n locations to store the IDs. 1042 */ 1043void GLAPIENTRY 1044_mesa_GenBuffersARB(GLsizei n, GLuint *buffer) 1045{ 1046 GET_CURRENT_CONTEXT(ctx); 1047 GLuint first; 1048 GLint i; 1049 ASSERT_OUTSIDE_BEGIN_END(ctx); 1050 1051 if (n < 0) { 1052 _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB"); 1053 return; 1054 } 1055 1056 if (!buffer) { 1057 return; 1058 } 1059 1060 /* 1061 * This must be atomic (generation and allocation of buffer object IDs) 1062 */ 1063 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 1064 1065 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n); 1066 1067 /* Allocate new, empty buffer objects and return identifiers */ 1068 for (i = 0; i < n; i++) { 1069 struct gl_buffer_object *bufObj; 1070 GLuint name = first + i; 1071 GLenum target = 0; 1072 bufObj = ctx->Driver.NewBufferObject( ctx, name, target ); 1073 if (!bufObj) { 1074 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 1075 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenBuffersARB"); 1076 return; 1077 } 1078 _mesa_HashInsert(ctx->Shared->BufferObjects, first + i, bufObj); 1079 buffer[i] = first + i; 1080 } 1081 1082 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 1083} 1084 1085 1086/** 1087 * Determine if ID is the name of a buffer object. 1088 * 1089 * \param id ID of the potential buffer object. 1090 * \return \c GL_TRUE if \c id is the name of a buffer object, 1091 * \c GL_FALSE otherwise. 1092 */ 1093GLboolean GLAPIENTRY 1094_mesa_IsBufferARB(GLuint id) 1095{ 1096 struct gl_buffer_object *bufObj; 1097 GET_CURRENT_CONTEXT(ctx); 1098 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 1099 1100 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 1101 bufObj = _mesa_lookup_bufferobj(ctx, id); 1102 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 1103 1104 return bufObj ? GL_TRUE : GL_FALSE; 1105} 1106 1107 1108void GLAPIENTRY 1109_mesa_BufferDataARB(GLenum target, GLsizeiptrARB size, 1110 const GLvoid * data, GLenum usage) 1111{ 1112 GET_CURRENT_CONTEXT(ctx); 1113 struct gl_buffer_object *bufObj; 1114 ASSERT_OUTSIDE_BEGIN_END(ctx); 1115 1116 if (size < 0) { 1117 _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)"); 1118 return; 1119 } 1120 1121 switch (usage) { 1122 case GL_STREAM_DRAW_ARB: 1123 case GL_STREAM_READ_ARB: 1124 case GL_STREAM_COPY_ARB: 1125 case GL_STATIC_DRAW_ARB: 1126 case GL_STATIC_READ_ARB: 1127 case GL_STATIC_COPY_ARB: 1128 case GL_DYNAMIC_DRAW_ARB: 1129 case GL_DYNAMIC_READ_ARB: 1130 case GL_DYNAMIC_COPY_ARB: 1131 /* OK */ 1132 break; 1133 default: 1134 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)"); 1135 return; 1136 } 1137 1138 bufObj = get_buffer(ctx, target); 1139 if (!bufObj) { 1140 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(target)" ); 1141 return; 1142 } 1143 if (!_mesa_is_bufferobj(bufObj)) { 1144 _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB(buffer 0)" ); 1145 return; 1146 } 1147 1148 if (_mesa_bufferobj_mapped(bufObj)) { 1149 /* Unmap the existing buffer. We'll replace it now. Not an error. */ 1150 ctx->Driver.UnmapBuffer(ctx, target, bufObj); 1151 bufObj->AccessFlags = DEFAULT_ACCESS; 1152 ASSERT(bufObj->Pointer == NULL); 1153 } 1154 1155 FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT); 1156 1157 bufObj->Written = GL_TRUE; 1158 1159#ifdef VBO_DEBUG 1160 printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n", 1161 bufObj->Name, size, data, usage); 1162#endif 1163 1164#ifdef BOUNDS_CHECK 1165 size += 100; 1166#endif 1167 1168 ASSERT(ctx->Driver.BufferData); 1169 if (!ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj )) { 1170 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferDataARB()"); 1171 } 1172} 1173 1174 1175void GLAPIENTRY 1176_mesa_BufferSubDataARB(GLenum target, GLintptrARB offset, 1177 GLsizeiptrARB size, const GLvoid * data) 1178{ 1179 GET_CURRENT_CONTEXT(ctx); 1180 struct gl_buffer_object *bufObj; 1181 ASSERT_OUTSIDE_BEGIN_END(ctx); 1182 1183 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, 1184 "glBufferSubDataARB" ); 1185 if (!bufObj) { 1186 /* error already recorded */ 1187 return; 1188 } 1189 1190 bufObj->Written = GL_TRUE; 1191 1192 ASSERT(ctx->Driver.BufferSubData); 1193 ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj ); 1194} 1195 1196 1197void GLAPIENTRY 1198_mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset, 1199 GLsizeiptrARB size, void * data) 1200{ 1201 GET_CURRENT_CONTEXT(ctx); 1202 struct gl_buffer_object *bufObj; 1203 ASSERT_OUTSIDE_BEGIN_END(ctx); 1204 1205 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, 1206 "glGetBufferSubDataARB" ); 1207 if (!bufObj) { 1208 /* error already recorded */ 1209 return; 1210 } 1211 1212 ASSERT(ctx->Driver.GetBufferSubData); 1213 ctx->Driver.GetBufferSubData( ctx, target, offset, size, data, bufObj ); 1214} 1215 1216 1217void * GLAPIENTRY 1218_mesa_MapBufferARB(GLenum target, GLenum access) 1219{ 1220 GET_CURRENT_CONTEXT(ctx); 1221 struct gl_buffer_object * bufObj; 1222 GLbitfield accessFlags; 1223 void *map; 1224 1225 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); 1226 1227 switch (access) { 1228 case GL_READ_ONLY_ARB: 1229 accessFlags = GL_MAP_READ_BIT; 1230 break; 1231 case GL_WRITE_ONLY_ARB: 1232 accessFlags = GL_MAP_WRITE_BIT; 1233 break; 1234 case GL_READ_WRITE_ARB: 1235 accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; 1236 break; 1237 default: 1238 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)"); 1239 return NULL; 1240 } 1241 1242 bufObj = get_buffer(ctx, target); 1243 if (!bufObj) { 1244 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(target)" ); 1245 return NULL; 1246 } 1247 if (!_mesa_is_bufferobj(bufObj)) { 1248 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(buffer 0)" ); 1249 return NULL; 1250 } 1251 if (_mesa_bufferobj_mapped(bufObj)) { 1252 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)"); 1253 return NULL; 1254 } 1255 1256 ASSERT(ctx->Driver.MapBuffer); 1257 map = ctx->Driver.MapBuffer( ctx, target, access, bufObj ); 1258 if (!map) { 1259 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); 1260 return NULL; 1261 } 1262 else { 1263 /* The driver callback should have set these fields. 1264 * This is important because other modules (like VBO) might call 1265 * the driver function directly. 1266 */ 1267 ASSERT(bufObj->Pointer == map); 1268 ASSERT(bufObj->Length == bufObj->Size); 1269 ASSERT(bufObj->Offset == 0); 1270 bufObj->AccessFlags = accessFlags; 1271 } 1272 1273 if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB) 1274 bufObj->Written = GL_TRUE; 1275 1276#ifdef VBO_DEBUG 1277 printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n", 1278 bufObj->Name, bufObj->Size, access); 1279 if (access == GL_WRITE_ONLY_ARB) { 1280 GLuint i; 1281 GLubyte *b = (GLubyte *) bufObj->Pointer; 1282 for (i = 0; i < bufObj->Size; i++) 1283 b[i] = i & 0xff; 1284 } 1285#endif 1286 1287#ifdef BOUNDS_CHECK 1288 { 1289 GLubyte *buf = (GLubyte *) bufObj->Pointer; 1290 GLuint i; 1291 /* buffer is 100 bytes larger than requested, fill with magic value */ 1292 for (i = 0; i < 100; i++) { 1293 buf[bufObj->Size - i - 1] = 123; 1294 } 1295 } 1296#endif 1297 1298 return bufObj->Pointer; 1299} 1300 1301 1302GLboolean GLAPIENTRY 1303_mesa_UnmapBufferARB(GLenum target) 1304{ 1305 GET_CURRENT_CONTEXT(ctx); 1306 struct gl_buffer_object *bufObj; 1307 GLboolean status = GL_TRUE; 1308 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 1309 1310 bufObj = get_buffer(ctx, target); 1311 if (!bufObj) { 1312 _mesa_error(ctx, GL_INVALID_ENUM, "glUnmapBufferARB(target)" ); 1313 return GL_FALSE; 1314 } 1315 if (!_mesa_is_bufferobj(bufObj)) { 1316 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" ); 1317 return GL_FALSE; 1318 } 1319 if (!_mesa_bufferobj_mapped(bufObj)) { 1320 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB"); 1321 return GL_FALSE; 1322 } 1323 1324#ifdef BOUNDS_CHECK 1325 if (bufObj->Access != GL_READ_ONLY_ARB) { 1326 GLubyte *buf = (GLubyte *) bufObj->Pointer; 1327 GLuint i; 1328 /* check that last 100 bytes are still = magic value */ 1329 for (i = 0; i < 100; i++) { 1330 GLuint pos = bufObj->Size - i - 1; 1331 if (buf[pos] != 123) { 1332 _mesa_warning(ctx, "Out of bounds buffer object write detected" 1333 " at position %d (value = %u)\n", 1334 pos, buf[pos]); 1335 } 1336 } 1337 } 1338#endif 1339 1340#ifdef VBO_DEBUG 1341 if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) { 1342 GLuint i, unchanged = 0; 1343 GLubyte *b = (GLubyte *) bufObj->Pointer; 1344 GLint pos = -1; 1345 /* check which bytes changed */ 1346 for (i = 0; i < bufObj->Size - 1; i++) { 1347 if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) { 1348 unchanged++; 1349 if (pos == -1) 1350 pos = i; 1351 } 1352 } 1353 if (unchanged) { 1354 printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n", 1355 bufObj->Name, unchanged, bufObj->Size, pos); 1356 } 1357 } 1358#endif 1359 1360 status = ctx->Driver.UnmapBuffer( ctx, target, bufObj ); 1361 bufObj->AccessFlags = DEFAULT_ACCESS; 1362 ASSERT(bufObj->Pointer == NULL); 1363 ASSERT(bufObj->Offset == 0); 1364 ASSERT(bufObj->Length == 0); 1365 1366 return status; 1367} 1368 1369 1370void GLAPIENTRY 1371_mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params) 1372{ 1373 GET_CURRENT_CONTEXT(ctx); 1374 struct gl_buffer_object *bufObj; 1375 ASSERT_OUTSIDE_BEGIN_END(ctx); 1376 1377 bufObj = get_buffer(ctx, target); 1378 if (!bufObj) { 1379 _mesa_error(ctx, GL_INVALID_ENUM, "GetBufferParameterivARB(target)" ); 1380 return; 1381 } 1382 if (!_mesa_is_bufferobj(bufObj)) { 1383 _mesa_error(ctx, GL_INVALID_OPERATION, "GetBufferParameterivARB" ); 1384 return; 1385 } 1386 1387 switch (pname) { 1388 case GL_BUFFER_SIZE_ARB: 1389 *params = (GLint) bufObj->Size; 1390 break; 1391 case GL_BUFFER_USAGE_ARB: 1392 *params = bufObj->Usage; 1393 break; 1394 case GL_BUFFER_ACCESS_ARB: 1395 *params = simplified_access_mode(bufObj->AccessFlags); 1396 break; 1397 case GL_BUFFER_MAPPED_ARB: 1398 *params = _mesa_bufferobj_mapped(bufObj); 1399 break; 1400 default: 1401 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname)"); 1402 return; 1403 } 1404} 1405 1406 1407/** 1408 * New in GL 3.2 1409 * This is pretty much a duplicate of GetBufferParameteriv() but the 1410 * GL_BUFFER_SIZE_ARB attribute will be 64-bits on a 64-bit system. 1411 */ 1412void GLAPIENTRY 1413_mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params) 1414{ 1415 GET_CURRENT_CONTEXT(ctx); 1416 struct gl_buffer_object *bufObj; 1417 ASSERT_OUTSIDE_BEGIN_END(ctx); 1418 1419 bufObj = get_buffer(ctx, target); 1420 if (!bufObj) { 1421 _mesa_error(ctx, GL_INVALID_ENUM, "GetBufferParameteri64v(target)" ); 1422 return; 1423 } 1424 if (!_mesa_is_bufferobj(bufObj)) { 1425 _mesa_error(ctx, GL_INVALID_OPERATION, "GetBufferParameteri64v" ); 1426 return; 1427 } 1428 1429 switch (pname) { 1430 case GL_BUFFER_SIZE_ARB: 1431 *params = bufObj->Size; 1432 break; 1433 case GL_BUFFER_USAGE_ARB: 1434 *params = bufObj->Usage; 1435 break; 1436 case GL_BUFFER_ACCESS_ARB: 1437 *params = simplified_access_mode(bufObj->AccessFlags); 1438 break; 1439 case GL_BUFFER_MAPPED_ARB: 1440 *params = _mesa_bufferobj_mapped(bufObj); 1441 break; 1442 default: 1443 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(pname)"); 1444 return; 1445 } 1446} 1447 1448 1449void GLAPIENTRY 1450_mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params) 1451{ 1452 GET_CURRENT_CONTEXT(ctx); 1453 struct gl_buffer_object * bufObj; 1454 ASSERT_OUTSIDE_BEGIN_END(ctx); 1455 1456 if (pname != GL_BUFFER_MAP_POINTER_ARB) { 1457 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)"); 1458 return; 1459 } 1460 1461 bufObj = get_buffer(ctx, target); 1462 if (!bufObj) { 1463 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(target)" ); 1464 return; 1465 } 1466 if (!_mesa_is_bufferobj(bufObj)) { 1467 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferPointervARB" ); 1468 return; 1469 } 1470 1471 *params = bufObj->Pointer; 1472} 1473 1474 1475void GLAPIENTRY 1476_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, 1477 GLintptr readOffset, GLintptr writeOffset, 1478 GLsizeiptr size) 1479{ 1480 GET_CURRENT_CONTEXT(ctx); 1481 struct gl_buffer_object *src, *dst; 1482 ASSERT_OUTSIDE_BEGIN_END(ctx); 1483 1484 src = get_buffer(ctx, readTarget); 1485 if (!src || !_mesa_is_bufferobj(src)) { 1486 _mesa_error(ctx, GL_INVALID_ENUM, 1487 "glCopyBuffserSubData(readTarget = 0x%x)", readTarget); 1488 return; 1489 } 1490 1491 dst = get_buffer(ctx, writeTarget); 1492 if (!dst || !_mesa_is_bufferobj(dst)) { 1493 _mesa_error(ctx, GL_INVALID_ENUM, 1494 "glCopyBuffserSubData(writeTarget = 0x%x)", writeTarget); 1495 return; 1496 } 1497 1498 if (_mesa_bufferobj_mapped(src)) { 1499 _mesa_error(ctx, GL_INVALID_OPERATION, 1500 "glCopyBuffserSubData(readBuffer is mapped)"); 1501 return; 1502 } 1503 1504 if (_mesa_bufferobj_mapped(dst)) { 1505 _mesa_error(ctx, GL_INVALID_OPERATION, 1506 "glCopyBuffserSubData(writeBuffer is mapped)"); 1507 return; 1508 } 1509 1510 if (readOffset < 0) { 1511 _mesa_error(ctx, GL_INVALID_VALUE, 1512 "glCopyBuffserSubData(readOffset = %d)", readOffset); 1513 return; 1514 } 1515 1516 if (writeOffset < 0) { 1517 _mesa_error(ctx, GL_INVALID_VALUE, 1518 "glCopyBuffserSubData(writeOffset = %d)", writeOffset); 1519 return; 1520 } 1521 1522 if (readOffset + size > src->Size) { 1523 _mesa_error(ctx, GL_INVALID_VALUE, 1524 "glCopyBuffserSubData(readOffset + size = %d)", 1525 readOffset, size); 1526 return; 1527 } 1528 1529 if (writeOffset + size > dst->Size) { 1530 _mesa_error(ctx, GL_INVALID_VALUE, 1531 "glCopyBuffserSubData(writeOffset + size = %d)", 1532 writeOffset, size); 1533 return; 1534 } 1535 1536 if (src == dst) { 1537 if (readOffset + size <= writeOffset) { 1538 /* OK */ 1539 } 1540 else if (writeOffset + size <= readOffset) { 1541 /* OK */ 1542 } 1543 else { 1544 /* overlapping src/dst is illegal */ 1545 _mesa_error(ctx, GL_INVALID_VALUE, 1546 "glCopyBuffserSubData(overlapping src/dst)"); 1547 return; 1548 } 1549 } 1550 1551 ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size); 1552} 1553 1554 1555/** 1556 * See GL_ARB_map_buffer_range spec 1557 */ 1558void * GLAPIENTRY 1559_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, 1560 GLbitfield access) 1561{ 1562 GET_CURRENT_CONTEXT(ctx); 1563 struct gl_buffer_object *bufObj; 1564 void *map; 1565 1566 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); 1567 1568 if (!ctx->Extensions.ARB_map_buffer_range) { 1569 _mesa_error(ctx, GL_INVALID_OPERATION, 1570 "glMapBufferRange(extension not supported)"); 1571 return NULL; 1572 } 1573 1574 if (offset < 0) { 1575 _mesa_error(ctx, GL_INVALID_VALUE, 1576 "glMapBufferRange(offset = %ld)", offset); 1577 return NULL; 1578 } 1579 1580 if (length < 0) { 1581 _mesa_error(ctx, GL_INVALID_VALUE, 1582 "glMapBufferRange(length = %ld)", length); 1583 return NULL; 1584 } 1585 1586 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) { 1587 _mesa_error(ctx, GL_INVALID_OPERATION, 1588 "glMapBufferRange(access indicates neither read or write)"); 1589 return NULL; 1590 } 1591 1592 if (access & GL_MAP_READ_BIT) { 1593 if ((access & GL_MAP_INVALIDATE_RANGE_BIT) || 1594 (access & GL_MAP_INVALIDATE_BUFFER_BIT) || 1595 (access & GL_MAP_UNSYNCHRONIZED_BIT)) { 1596 _mesa_error(ctx, GL_INVALID_OPERATION, 1597 "glMapBufferRange(invalid access flags)"); 1598 return NULL; 1599 } 1600 } 1601 1602 if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) && 1603 ((access & GL_MAP_WRITE_BIT) == 0)) { 1604 _mesa_error(ctx, GL_INVALID_OPERATION, 1605 "glMapBufferRange(invalid access flags)"); 1606 return NULL; 1607 } 1608 1609 bufObj = get_buffer(ctx, target); 1610 if (!bufObj || !_mesa_is_bufferobj(bufObj)) { 1611 _mesa_error(ctx, GL_INVALID_ENUM, 1612 "glMapBufferRange(target = 0x%x)", target); 1613 return NULL; 1614 } 1615 1616 if (offset + length > bufObj->Size) { 1617 _mesa_error(ctx, GL_INVALID_VALUE, 1618 "glMapBufferRange(offset + length > size)"); 1619 return NULL; 1620 } 1621 1622 if (_mesa_bufferobj_mapped(bufObj)) { 1623 _mesa_error(ctx, GL_INVALID_OPERATION, 1624 "glMapBufferRange(buffer already mapped)"); 1625 return NULL; 1626 } 1627 1628 ASSERT(ctx->Driver.MapBufferRange); 1629 map = ctx->Driver.MapBufferRange(ctx, target, offset, length, 1630 access, bufObj); 1631 if (!map) { 1632 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); 1633 } 1634 else { 1635 /* The driver callback should have set all these fields. 1636 * This is important because other modules (like VBO) might call 1637 * the driver function directly. 1638 */ 1639 ASSERT(bufObj->Pointer == map); 1640 ASSERT(bufObj->Length == length); 1641 ASSERT(bufObj->Offset == offset); 1642 ASSERT(bufObj->AccessFlags == access); 1643 } 1644 1645 return map; 1646} 1647 1648 1649/** 1650 * See GL_ARB_map_buffer_range spec 1651 */ 1652void GLAPIENTRY 1653_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) 1654{ 1655 GET_CURRENT_CONTEXT(ctx); 1656 struct gl_buffer_object *bufObj; 1657 ASSERT_OUTSIDE_BEGIN_END(ctx); 1658 1659 if (!ctx->Extensions.ARB_map_buffer_range) { 1660 _mesa_error(ctx, GL_INVALID_OPERATION, 1661 "glMapBufferRange(extension not supported)"); 1662 return; 1663 } 1664 1665 if (offset < 0) { 1666 _mesa_error(ctx, GL_INVALID_VALUE, 1667 "glMapBufferRange(offset = %ld)", offset); 1668 return; 1669 } 1670 1671 if (length < 0) { 1672 _mesa_error(ctx, GL_INVALID_VALUE, 1673 "glMapBufferRange(length = %ld)", length); 1674 return; 1675 } 1676 1677 bufObj = get_buffer(ctx, target); 1678 if (!bufObj) { 1679 _mesa_error(ctx, GL_INVALID_ENUM, 1680 "glMapBufferRange(target = 0x%x)", target); 1681 return; 1682 } 1683 1684 if (!_mesa_is_bufferobj(bufObj)) { 1685 _mesa_error(ctx, GL_INVALID_OPERATION, 1686 "glMapBufferRange(current buffer is 0)"); 1687 return; 1688 } 1689 1690 if (!_mesa_bufferobj_mapped(bufObj)) { 1691 /* buffer is not mapped */ 1692 _mesa_error(ctx, GL_INVALID_OPERATION, 1693 "glMapBufferRange(buffer is not mapped)"); 1694 return; 1695 } 1696 1697 if ((bufObj->AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) { 1698 _mesa_error(ctx, GL_INVALID_OPERATION, 1699 "glMapBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)"); 1700 return; 1701 } 1702 1703 if (offset + length > bufObj->Length) { 1704 _mesa_error(ctx, GL_INVALID_VALUE, 1705 "glMapBufferRange(offset %ld + length %ld > mapped length %ld)", 1706 offset, length, bufObj->Length); 1707 return; 1708 } 1709 1710 ASSERT(bufObj->AccessFlags & GL_MAP_WRITE_BIT); 1711 1712 if (ctx->Driver.FlushMappedBufferRange) 1713 ctx->Driver.FlushMappedBufferRange(ctx, target, offset, length, bufObj); 1714} 1715 1716 1717#if FEATURE_APPLE_object_purgeable 1718static GLenum 1719_mesa_BufferObjectPurgeable(GLcontext *ctx, GLuint name, GLenum option) 1720{ 1721 struct gl_buffer_object *bufObj; 1722 GLenum retval; 1723 1724 bufObj = _mesa_lookup_bufferobj(ctx, name); 1725 if (!bufObj) { 1726 _mesa_error(ctx, GL_INVALID_VALUE, 1727 "glObjectPurgeable(name = 0x%x)", name); 1728 return 0; 1729 } 1730 if (!_mesa_is_bufferobj(bufObj)) { 1731 _mesa_error(ctx, GL_INVALID_OPERATION, "glObjectPurgeable(buffer 0)" ); 1732 return 0; 1733 } 1734 1735 if (bufObj->Purgeable) { 1736 _mesa_error(ctx, GL_INVALID_OPERATION, 1737 "glObjectPurgeable(name = 0x%x) is already purgeable", name); 1738 return GL_VOLATILE_APPLE; 1739 } 1740 1741 bufObj->Purgeable = GL_TRUE; 1742 1743 retval = GL_VOLATILE_APPLE; 1744 if (ctx->Driver.BufferObjectPurgeable) 1745 retval = ctx->Driver.BufferObjectPurgeable(ctx, bufObj, option); 1746 1747 return retval; 1748} 1749 1750 1751static GLenum 1752_mesa_RenderObjectPurgeable(GLcontext *ctx, GLuint name, GLenum option) 1753{ 1754 struct gl_renderbuffer *bufObj; 1755 GLenum retval; 1756 1757 bufObj = _mesa_lookup_renderbuffer(ctx, name); 1758 if (!bufObj) { 1759 _mesa_error(ctx, GL_INVALID_VALUE, 1760 "glObjectUnpurgeable(name = 0x%x)", name); 1761 return 0; 1762 } 1763 1764 if (bufObj->Purgeable) { 1765 _mesa_error(ctx, GL_INVALID_OPERATION, 1766 "glObjectPurgeable(name = 0x%x) is already purgeable", name); 1767 return GL_VOLATILE_APPLE; 1768 } 1769 1770 bufObj->Purgeable = GL_TRUE; 1771 1772 retval = GL_VOLATILE_APPLE; 1773 if (ctx->Driver.RenderObjectPurgeable) 1774 retval = ctx->Driver.RenderObjectPurgeable(ctx, bufObj, option); 1775 1776 return retval; 1777} 1778 1779 1780static GLenum 1781_mesa_TextureObjectPurgeable(GLcontext *ctx, GLuint name, GLenum option) 1782{ 1783 struct gl_texture_object *bufObj; 1784 GLenum retval; 1785 1786 bufObj = _mesa_lookup_texture(ctx, name); 1787 if (!bufObj) { 1788 _mesa_error(ctx, GL_INVALID_VALUE, 1789 "glObjectPurgeable(name = 0x%x)", name); 1790 return 0; 1791 } 1792 1793 if (bufObj->Purgeable) { 1794 _mesa_error(ctx, GL_INVALID_OPERATION, 1795 "glObjectPurgeable(name = 0x%x) is already purgeable", name); 1796 return GL_VOLATILE_APPLE; 1797 } 1798 1799 bufObj->Purgeable = GL_TRUE; 1800 1801 retval = GL_VOLATILE_APPLE; 1802 if (ctx->Driver.TextureObjectPurgeable) 1803 retval = ctx->Driver.TextureObjectPurgeable(ctx, bufObj, option); 1804 1805 return retval; 1806} 1807 1808 1809GLenum GLAPIENTRY 1810_mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option) 1811{ 1812 GLenum retval; 1813 1814 GET_CURRENT_CONTEXT(ctx); 1815 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 1816 1817 if (name == 0) { 1818 _mesa_error(ctx, GL_INVALID_VALUE, 1819 "glObjectPurgeable(name = 0x%x)", name); 1820 return 0; 1821 } 1822 1823 switch (option) { 1824 case GL_VOLATILE_APPLE: 1825 case GL_RELEASED_APPLE: 1826 /* legal */ 1827 break; 1828 default: 1829 _mesa_error(ctx, GL_INVALID_ENUM, 1830 "glObjectPurgeable(name = 0x%x) invalid option: %d", 1831 name, option); 1832 return 0; 1833 } 1834 1835 switch (objectType) { 1836 case GL_TEXTURE: 1837 retval = _mesa_TextureObjectPurgeable (ctx, name, option); 1838 break; 1839 case GL_RENDERBUFFER_EXT: 1840 retval = _mesa_RenderObjectPurgeable (ctx, name, option); 1841 break; 1842 case GL_BUFFER_OBJECT_APPLE: 1843 retval = _mesa_BufferObjectPurgeable (ctx, name, option); 1844 break; 1845 default: 1846 _mesa_error(ctx, GL_INVALID_ENUM, 1847 "glObjectPurgeable(name = 0x%x) invalid type: %d", 1848 name, objectType); 1849 return 0; 1850 } 1851 1852 /* In strict conformance to the spec, we must only return VOLATILE when 1853 * when passed the VOLATILE option. Madness. 1854 * 1855 * XXX First fix the spec, then fix me. 1856 */ 1857 return option == GL_VOLATILE_APPLE ? GL_VOLATILE_APPLE : retval; 1858} 1859 1860 1861static GLenum 1862_mesa_BufferObjectUnpurgeable(GLcontext *ctx, GLuint name, GLenum option) 1863{ 1864 struct gl_buffer_object *bufObj; 1865 GLenum retval; 1866 1867 bufObj = _mesa_lookup_bufferobj(ctx, name); 1868 if (!bufObj) { 1869 _mesa_error(ctx, GL_INVALID_VALUE, 1870 "glObjectUnpurgeable(name = 0x%x)", name); 1871 return 0; 1872 } 1873 1874 if (! bufObj->Purgeable) { 1875 _mesa_error(ctx, GL_INVALID_OPERATION, 1876 "glObjectUnpurgeable(name = 0x%x) object is " 1877 " already \"unpurged\"", name); 1878 return 0; 1879 } 1880 1881 bufObj->Purgeable = GL_FALSE; 1882 1883 retval = GL_RETAINED_APPLE; 1884 if (ctx->Driver.BufferObjectUnpurgeable) 1885 retval = ctx->Driver.BufferObjectUnpurgeable(ctx, bufObj, option); 1886 1887 return retval; 1888} 1889 1890 1891static GLenum 1892_mesa_RenderObjectUnpurgeable(GLcontext *ctx, GLuint name, GLenum option) 1893{ 1894 struct gl_renderbuffer *bufObj; 1895 GLenum retval; 1896 1897 bufObj = _mesa_lookup_renderbuffer(ctx, name); 1898 if (!bufObj) { 1899 _mesa_error(ctx, GL_INVALID_VALUE, 1900 "glObjectUnpurgeable(name = 0x%x)", name); 1901 return 0; 1902 } 1903 1904 if (! bufObj->Purgeable) { 1905 _mesa_error(ctx, GL_INVALID_OPERATION, 1906 "glObjectUnpurgeable(name = 0x%x) object is " 1907 " already \"unpurged\"", name); 1908 return 0; 1909 } 1910 1911 bufObj->Purgeable = GL_FALSE; 1912 1913 retval = GL_RETAINED_APPLE; 1914 if (ctx->Driver.RenderObjectUnpurgeable) 1915 retval = ctx->Driver.RenderObjectUnpurgeable(ctx, bufObj, option); 1916 1917 return option; 1918} 1919 1920 1921static GLenum 1922_mesa_TextureObjectUnpurgeable(GLcontext *ctx, GLuint name, GLenum option) 1923{ 1924 struct gl_texture_object *bufObj; 1925 GLenum retval; 1926 1927 bufObj = _mesa_lookup_texture(ctx, name); 1928 if (!bufObj) { 1929 _mesa_error(ctx, GL_INVALID_VALUE, 1930 "glObjectUnpurgeable(name = 0x%x)", name); 1931 return 0; 1932 } 1933 1934 if (! bufObj->Purgeable) { 1935 _mesa_error(ctx, GL_INVALID_OPERATION, 1936 "glObjectUnpurgeable(name = 0x%x) object is" 1937 " already \"unpurged\"", name); 1938 return 0; 1939 } 1940 1941 bufObj->Purgeable = GL_FALSE; 1942 1943 retval = GL_RETAINED_APPLE; 1944 if (ctx->Driver.TextureObjectUnpurgeable) 1945 retval = ctx->Driver.TextureObjectUnpurgeable(ctx, bufObj, option); 1946 1947 return retval; 1948} 1949 1950 1951GLenum GLAPIENTRY 1952_mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option) 1953{ 1954 GET_CURRENT_CONTEXT(ctx); 1955 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 1956 1957 if (name == 0) { 1958 _mesa_error(ctx, GL_INVALID_VALUE, 1959 "glObjectUnpurgeable(name = 0x%x)", name); 1960 return 0; 1961 } 1962 1963 switch (option) { 1964 case GL_RETAINED_APPLE: 1965 case GL_UNDEFINED_APPLE: 1966 /* legal */ 1967 break; 1968 default: 1969 _mesa_error(ctx, GL_INVALID_ENUM, 1970 "glObjectUnpurgeable(name = 0x%x) invalid option: %d", 1971 name, option); 1972 return 0; 1973 } 1974 1975 switch (objectType) { 1976 case GL_BUFFER_OBJECT_APPLE: 1977 return _mesa_BufferObjectUnpurgeable(ctx, name, option); 1978 case GL_TEXTURE: 1979 return _mesa_TextureObjectUnpurgeable(ctx, name, option); 1980 case GL_RENDERBUFFER_EXT: 1981 return _mesa_RenderObjectUnpurgeable(ctx, name, option); 1982 default: 1983 _mesa_error(ctx, GL_INVALID_ENUM, 1984 "glObjectUnpurgeable(name = 0x%x) invalid type: %d", 1985 name, objectType); 1986 return 0; 1987 } 1988} 1989 1990 1991static void 1992_mesa_GetBufferObjectParameterivAPPLE(GLcontext *ctx, GLuint name, 1993 GLenum pname, GLint* params) 1994{ 1995 struct gl_buffer_object *bufObj; 1996 1997 bufObj = _mesa_lookup_bufferobj(ctx, name); 1998 if (!bufObj) { 1999 _mesa_error(ctx, GL_INVALID_VALUE, 2000 "glGetObjectParameteriv(name = 0x%x) invalid object", name); 2001 return; 2002 } 2003 2004 switch (pname) { 2005 case GL_PURGEABLE_APPLE: 2006 *params = bufObj->Purgeable; 2007 break; 2008 default: 2009 _mesa_error(ctx, GL_INVALID_ENUM, 2010 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", 2011 name, pname); 2012 break; 2013 } 2014} 2015 2016 2017static void 2018_mesa_GetRenderObjectParameterivAPPLE(GLcontext *ctx, GLuint name, 2019 GLenum pname, GLint* params) 2020{ 2021 struct gl_renderbuffer *bufObj; 2022 2023 bufObj = _mesa_lookup_renderbuffer(ctx, name); 2024 if (!bufObj) { 2025 _mesa_error(ctx, GL_INVALID_VALUE, 2026 "glObjectUnpurgeable(name = 0x%x)", name); 2027 return; 2028 } 2029 2030 switch (pname) { 2031 case GL_PURGEABLE_APPLE: 2032 *params = bufObj->Purgeable; 2033 break; 2034 default: 2035 _mesa_error(ctx, GL_INVALID_ENUM, 2036 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", 2037 name, pname); 2038 break; 2039 } 2040} 2041 2042 2043static void 2044_mesa_GetTextureObjectParameterivAPPLE(GLcontext *ctx, GLuint name, 2045 GLenum pname, GLint* params) 2046{ 2047 struct gl_texture_object *bufObj; 2048 2049 bufObj = _mesa_lookup_texture(ctx, name); 2050 if (!bufObj) { 2051 _mesa_error(ctx, GL_INVALID_VALUE, 2052 "glObjectUnpurgeable(name = 0x%x)", name); 2053 return; 2054 } 2055 2056 switch (pname) { 2057 case GL_PURGEABLE_APPLE: 2058 *params = bufObj->Purgeable; 2059 break; 2060 default: 2061 _mesa_error(ctx, GL_INVALID_ENUM, 2062 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", 2063 name, pname); 2064 break; 2065 } 2066} 2067 2068 2069void GLAPIENTRY 2070_mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname, 2071 GLint* params) 2072{ 2073 GET_CURRENT_CONTEXT(ctx); 2074 2075 if (name == 0) { 2076 _mesa_error(ctx, GL_INVALID_VALUE, 2077 "glGetObjectParameteriv(name = 0x%x)", name); 2078 return; 2079 } 2080 2081 switch (objectType) { 2082 case GL_TEXTURE: 2083 _mesa_GetTextureObjectParameterivAPPLE (ctx, name, pname, params); 2084 break; 2085 case GL_BUFFER_OBJECT_APPLE: 2086 _mesa_GetBufferObjectParameterivAPPLE (ctx, name, pname, params); 2087 break; 2088 case GL_RENDERBUFFER_EXT: 2089 _mesa_GetRenderObjectParameterivAPPLE (ctx, name, pname, params); 2090 break; 2091 default: 2092 _mesa_error(ctx, GL_INVALID_ENUM, 2093 "glGetObjectParameteriv(name = 0x%x) invalid type: %d", 2094 name, objectType); 2095 } 2096} 2097 2098#endif /* FEATURE_APPLE_object_purgeable */ 2099