bufferobj.c revision 4a49301e
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 41 42/* Debug flags */ 43/*#define VBO_DEBUG*/ 44/*#define BOUNDS_CHECK*/ 45 46 47#ifdef FEATURE_OES_mapbuffer 48#define DEFAULT_ACCESS GL_MAP_WRITE_BIT 49#else 50#define DEFAULT_ACCESS (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT) 51#endif 52 53 54/** 55 * Return pointer to address of a buffer object target. 56 * \param ctx the GL context 57 * \param target the buffer object target to be retrieved. 58 * \return pointer to pointer to the buffer object bound to \c target in the 59 * specified context or \c NULL if \c target is invalid. 60 */ 61static INLINE struct gl_buffer_object ** 62get_buffer_target(GLcontext *ctx, GLenum target) 63{ 64 switch (target) { 65 case GL_ARRAY_BUFFER_ARB: 66 return &ctx->Array.ArrayBufferObj; 67 case GL_ELEMENT_ARRAY_BUFFER_ARB: 68 return &ctx->Array.ElementArrayBufferObj; 69 case GL_PIXEL_PACK_BUFFER_EXT: 70 return &ctx->Pack.BufferObj; 71 case GL_PIXEL_UNPACK_BUFFER_EXT: 72 return &ctx->Unpack.BufferObj; 73 case GL_COPY_READ_BUFFER: 74 if (ctx->Extensions.ARB_copy_buffer) { 75 return &ctx->CopyReadBuffer; 76 } 77 break; 78 case GL_COPY_WRITE_BUFFER: 79 if (ctx->Extensions.ARB_copy_buffer) { 80 return &ctx->CopyWriteBuffer; 81 } 82 break; 83 default: 84 return NULL; 85 } 86 return NULL; 87} 88 89 90/** 91 * Get the buffer object bound to the specified target in a GL context. 92 * \param ctx the GL context 93 * \param target the buffer object target to be retrieved. 94 * \return pointer to the buffer object bound to \c target in the 95 * specified context or \c NULL if \c target is invalid. 96 */ 97static INLINE struct gl_buffer_object * 98get_buffer(GLcontext *ctx, GLenum target) 99{ 100 struct gl_buffer_object **bufObj = get_buffer_target(ctx, target); 101 if (bufObj) 102 return *bufObj; 103 return NULL; 104} 105 106 107/** 108 * Convert a GLbitfield describing the mapped buffer access flags 109 * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY. 110 */ 111static GLenum 112simplified_access_mode(GLbitfield access) 113{ 114 const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; 115 if ((access & rwFlags) == rwFlags) 116 return GL_READ_WRITE; 117 if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT) 118 return GL_READ_ONLY; 119 if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT) 120 return GL_WRITE_ONLY; 121 return GL_READ_WRITE; /* this should never happen, but no big deal */ 122} 123 124 125/** 126 * Tests the subdata range parameters and sets the GL error code for 127 * \c glBufferSubDataARB and \c glGetBufferSubDataARB. 128 * 129 * \param ctx GL context. 130 * \param target Buffer object target on which to operate. 131 * \param offset Offset of the first byte of the subdata range. 132 * \param size Size, in bytes, of the subdata range. 133 * \param caller Name of calling function for recording errors. 134 * \return A pointer to the buffer object bound to \c target in the 135 * specified context or \c NULL if any of the parameter or state 136 * conditions for \c glBufferSubDataARB or \c glGetBufferSubDataARB 137 * are invalid. 138 * 139 * \sa glBufferSubDataARB, glGetBufferSubDataARB 140 */ 141static struct gl_buffer_object * 142buffer_object_subdata_range_good( GLcontext * ctx, GLenum target, 143 GLintptrARB offset, GLsizeiptrARB size, 144 const char *caller ) 145{ 146 struct gl_buffer_object *bufObj; 147 148 if (size < 0) { 149 _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller); 150 return NULL; 151 } 152 153 if (offset < 0) { 154 _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller); 155 return NULL; 156 } 157 158 bufObj = get_buffer(ctx, target); 159 if (!bufObj) { 160 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", caller); 161 return NULL; 162 } 163 if (!_mesa_is_bufferobj(bufObj)) { 164 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); 165 return NULL; 166 } 167 if (offset + size > bufObj->Size) { 168 _mesa_error(ctx, GL_INVALID_VALUE, 169 "%s(size + offset > buffer size)", caller); 170 return NULL; 171 } 172 if (_mesa_bufferobj_mapped(bufObj)) { 173 /* Buffer is currently mapped */ 174 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); 175 return NULL; 176 } 177 178 return bufObj; 179} 180 181 182/** 183 * Allocate and initialize a new buffer object. 184 * 185 * Default callback for the \c dd_function_table::NewBufferObject() hook. 186 */ 187static struct gl_buffer_object * 188_mesa_new_buffer_object( GLcontext *ctx, GLuint name, GLenum target ) 189{ 190 struct gl_buffer_object *obj; 191 192 (void) ctx; 193 194 obj = MALLOC_STRUCT(gl_buffer_object); 195 _mesa_initialize_buffer_object(obj, name, target); 196 return obj; 197} 198 199 200/** 201 * Delete a buffer object. 202 * 203 * Default callback for the \c dd_function_table::DeleteBuffer() hook. 204 */ 205static void 206_mesa_delete_buffer_object( GLcontext *ctx, struct gl_buffer_object *bufObj ) 207{ 208 (void) ctx; 209 210 if (bufObj->Data) 211 _mesa_free(bufObj->Data); 212 213 /* assign strange values here to help w/ debugging */ 214 bufObj->RefCount = -1000; 215 bufObj->Name = ~0; 216 217 _glthread_DESTROY_MUTEX(bufObj->Mutex); 218 _mesa_free(bufObj); 219} 220 221 222 223/** 224 * Set ptr to bufObj w/ reference counting. 225 */ 226void 227_mesa_reference_buffer_object(GLcontext *ctx, 228 struct gl_buffer_object **ptr, 229 struct gl_buffer_object *bufObj) 230{ 231 if (*ptr == bufObj) 232 return; 233 234 if (*ptr) { 235 /* Unreference the old buffer */ 236 GLboolean deleteFlag = GL_FALSE; 237 struct gl_buffer_object *oldObj = *ptr; 238 239 _glthread_LOCK_MUTEX(oldObj->Mutex); 240 ASSERT(oldObj->RefCount > 0); 241 oldObj->RefCount--; 242#if 0 243 printf("BufferObj %p %d DECR to %d\n", 244 (void *) oldObj, oldObj->Name, oldObj->RefCount); 245#endif 246 deleteFlag = (oldObj->RefCount == 0); 247 _glthread_UNLOCK_MUTEX(oldObj->Mutex); 248 249 if (deleteFlag) { 250 251 /* some sanity checking: don't delete a buffer still in use */ 252#if 0 253 /* unfortunately, these tests are invalid during context tear-down */ 254 ASSERT(ctx->Array.ArrayBufferObj != bufObj); 255 ASSERT(ctx->Array.ElementArrayBufferObj != bufObj); 256 ASSERT(ctx->Array.ArrayObj->Vertex.BufferObj != bufObj); 257#endif 258 259 ASSERT(ctx->Driver.DeleteBuffer); 260 ctx->Driver.DeleteBuffer(ctx, oldObj); 261 } 262 263 *ptr = NULL; 264 } 265 ASSERT(!*ptr); 266 267 if (bufObj) { 268 /* reference new buffer */ 269 _glthread_LOCK_MUTEX(bufObj->Mutex); 270 if (bufObj->RefCount == 0) { 271 /* this buffer's being deleted (look just above) */ 272 /* Not sure this can every really happen. Warn if it does. */ 273 _mesa_problem(NULL, "referencing deleted buffer object"); 274 *ptr = NULL; 275 } 276 else { 277 bufObj->RefCount++; 278#if 0 279 printf("BufferObj %p %d INCR to %d\n", 280 (void *) bufObj, bufObj->Name, bufObj->RefCount); 281#endif 282 *ptr = bufObj; 283 } 284 _glthread_UNLOCK_MUTEX(bufObj->Mutex); 285 } 286} 287 288 289/** 290 * Initialize a buffer object to default values. 291 */ 292void 293_mesa_initialize_buffer_object( struct gl_buffer_object *obj, 294 GLuint name, GLenum target ) 295{ 296 (void) target; 297 298 _mesa_bzero(obj, sizeof(struct gl_buffer_object)); 299 _glthread_INIT_MUTEX(obj->Mutex); 300 obj->RefCount = 1; 301 obj->Name = name; 302 obj->Usage = GL_STATIC_DRAW_ARB; 303 obj->AccessFlags = DEFAULT_ACCESS; 304} 305 306 307/** 308 * Allocate space for and store data in a buffer object. Any data that was 309 * previously stored in the buffer object is lost. If \c data is \c NULL, 310 * memory will be allocated, but no copy will occur. 311 * 312 * This is the default callback for \c dd_function_table::BufferData() 313 * Note that all GL error checking will have been done already. 314 * 315 * \param ctx GL context. 316 * \param target Buffer object target on which to operate. 317 * \param size Size, in bytes, of the new data store. 318 * \param data Pointer to the data to store in the buffer object. This 319 * pointer may be \c NULL. 320 * \param usage Hints about how the data will be used. 321 * \param bufObj Object to be used. 322 * 323 * \return GL_TRUE for success, GL_FALSE for failure 324 * \sa glBufferDataARB, dd_function_table::BufferData. 325 */ 326static GLboolean 327_mesa_buffer_data( GLcontext *ctx, GLenum target, GLsizeiptrARB size, 328 const GLvoid * data, GLenum usage, 329 struct gl_buffer_object * bufObj ) 330{ 331 void * new_data; 332 333 (void) ctx; (void) target; 334 335 new_data = _mesa_realloc( bufObj->Data, bufObj->Size, size ); 336 if (new_data) { 337 bufObj->Data = (GLubyte *) new_data; 338 bufObj->Size = size; 339 bufObj->Usage = usage; 340 341 if (data) { 342 _mesa_memcpy( bufObj->Data, data, size ); 343 } 344 345 return GL_TRUE; 346 } 347 else { 348 return GL_FALSE; 349 } 350} 351 352 353/** 354 * Replace data in a subrange of buffer object. If the data range 355 * specified by \c size + \c offset extends beyond the end of the buffer or 356 * if \c data is \c NULL, no copy is performed. 357 * 358 * This is the default callback for \c dd_function_table::BufferSubData() 359 * Note that all GL error checking will have been done already. 360 * 361 * \param ctx GL context. 362 * \param target Buffer object target on which to operate. 363 * \param offset Offset of the first byte to be modified. 364 * \param size Size, in bytes, of the data range. 365 * \param data Pointer to the data to store in the buffer object. 366 * \param bufObj Object to be used. 367 * 368 * \sa glBufferSubDataARB, dd_function_table::BufferSubData. 369 */ 370static void 371_mesa_buffer_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset, 372 GLsizeiptrARB size, const GLvoid * data, 373 struct gl_buffer_object * bufObj ) 374{ 375 (void) ctx; (void) target; 376 377 /* this should have been caught in _mesa_BufferSubData() */ 378 ASSERT(size + offset <= bufObj->Size); 379 380 if (bufObj->Data) { 381 _mesa_memcpy( (GLubyte *) bufObj->Data + offset, data, size ); 382 } 383} 384 385 386/** 387 * Retrieve data from a subrange of buffer object. If the data range 388 * specified by \c size + \c offset extends beyond the end of the buffer or 389 * if \c data is \c NULL, no copy is performed. 390 * 391 * This is the default callback for \c dd_function_table::GetBufferSubData() 392 * Note that all GL error checking will have been done already. 393 * 394 * \param ctx GL context. 395 * \param target Buffer object target on which to operate. 396 * \param offset Offset of the first byte to be fetched. 397 * \param size Size, in bytes, of the data range. 398 * \param data Destination for data 399 * \param bufObj Object to be used. 400 * 401 * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData. 402 */ 403static void 404_mesa_buffer_get_subdata( GLcontext *ctx, GLenum target, GLintptrARB offset, 405 GLsizeiptrARB size, GLvoid * data, 406 struct gl_buffer_object * bufObj ) 407{ 408 (void) ctx; (void) target; 409 410 if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) { 411 _mesa_memcpy( data, (GLubyte *) bufObj->Data + offset, size ); 412 } 413} 414 415 416/** 417 * Default callback for \c dd_function_tabel::MapBuffer(). 418 * 419 * The function parameters will have been already tested for errors. 420 * 421 * \param ctx GL context. 422 * \param target Buffer object target on which to operate. 423 * \param access Information about how the buffer will be accessed. 424 * \param bufObj Object to be mapped. 425 * \return A pointer to the object's internal data store that can be accessed 426 * by the processor 427 * 428 * \sa glMapBufferARB, dd_function_table::MapBuffer 429 */ 430static void * 431_mesa_buffer_map( GLcontext *ctx, GLenum target, GLenum access, 432 struct gl_buffer_object *bufObj ) 433{ 434 (void) ctx; 435 (void) target; 436 (void) access; 437 /* Just return a direct pointer to the data */ 438 if (_mesa_bufferobj_mapped(bufObj)) { 439 /* already mapped! */ 440 return NULL; 441 } 442 bufObj->Pointer = bufObj->Data; 443 bufObj->Length = bufObj->Size; 444 bufObj->Offset = 0; 445 return bufObj->Pointer; 446} 447 448 449/** 450 * Default fallback for \c dd_function_table::MapBufferRange(). 451 * Called via glMapBufferRange(). 452 */ 453static void * 454_mesa_buffer_map_range( GLcontext *ctx, GLenum target, GLintptr offset, 455 GLsizeiptr length, GLbitfield access, 456 struct gl_buffer_object *bufObj ) 457{ 458 (void) ctx; 459 (void) target; 460 assert(!_mesa_bufferobj_mapped(bufObj)); 461 /* Just return a direct pointer to the data */ 462 bufObj->Pointer = bufObj->Data + offset; 463 bufObj->Length = length; 464 bufObj->Offset = offset; 465 bufObj->AccessFlags = access; 466 return bufObj->Pointer; 467} 468 469 470/** 471 * Default fallback for \c dd_function_table::FlushMappedBufferRange(). 472 * Called via glFlushMappedBufferRange(). 473 */ 474static void 475_mesa_buffer_flush_mapped_range( GLcontext *ctx, GLenum target, 476 GLintptr offset, GLsizeiptr length, 477 struct gl_buffer_object *obj ) 478{ 479 (void) ctx; 480 (void) target; 481 (void) offset; 482 (void) length; 483 (void) obj; 484 /* no-op */ 485} 486 487 488/** 489 * Default callback for \c dd_function_table::MapBuffer(). 490 * 491 * The input parameters will have been already tested for errors. 492 * 493 * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer 494 */ 495static GLboolean 496_mesa_buffer_unmap( GLcontext *ctx, GLenum target, 497 struct gl_buffer_object *bufObj ) 498{ 499 (void) ctx; 500 (void) target; 501 /* XXX we might assert here that bufObj->Pointer is non-null */ 502 bufObj->Pointer = NULL; 503 bufObj->Length = 0; 504 bufObj->Offset = 0; 505 bufObj->AccessFlags = 0x0; 506 return GL_TRUE; 507} 508 509 510/** 511 * Default fallback for \c dd_function_table::CopyBufferSubData(). 512 * Called via glCopyBuffserSubData(). 513 */ 514static void 515_mesa_copy_buffer_subdata(GLcontext *ctx, 516 struct gl_buffer_object *src, 517 struct gl_buffer_object *dst, 518 GLintptr readOffset, GLintptr writeOffset, 519 GLsizeiptr size) 520{ 521 GLubyte *srcPtr, *dstPtr; 522 523 /* buffer should not already be mapped */ 524 assert(!_mesa_bufferobj_mapped(src)); 525 assert(!_mesa_bufferobj_mapped(dst)); 526 527 srcPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_READ_BUFFER, 528 GL_READ_ONLY, src); 529 dstPtr = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_COPY_WRITE_BUFFER, 530 GL_WRITE_ONLY, dst); 531 532 if (srcPtr && dstPtr) 533 _mesa_memcpy(dstPtr + writeOffset, srcPtr + readOffset, size); 534 535 ctx->Driver.UnmapBuffer(ctx, GL_COPY_READ_BUFFER, src); 536 ctx->Driver.UnmapBuffer(ctx, GL_COPY_WRITE_BUFFER, dst); 537} 538 539 540 541/** 542 * Initialize the state associated with buffer objects 543 */ 544void 545_mesa_init_buffer_objects( GLcontext *ctx ) 546{ 547 _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, 548 ctx->Shared->NullBufferObj); 549 _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, 550 ctx->Shared->NullBufferObj); 551 552 _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, 553 ctx->Shared->NullBufferObj); 554 _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, 555 ctx->Shared->NullBufferObj); 556} 557 558 559void 560_mesa_free_buffer_objects( GLcontext *ctx ) 561{ 562 _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL); 563 _mesa_reference_buffer_object(ctx, &ctx->Array.ElementArrayBufferObj, NULL); 564 565 _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, NULL); 566 _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, NULL); 567} 568 569 570/** 571 * Bind the specified target to buffer for the specified context. 572 * Called by glBindBuffer() and other functions. 573 */ 574static void 575bind_buffer_object(GLcontext *ctx, GLenum target, GLuint buffer) 576{ 577 struct gl_buffer_object *oldBufObj; 578 struct gl_buffer_object *newBufObj = NULL; 579 struct gl_buffer_object **bindTarget = NULL; 580 581 bindTarget = get_buffer_target(ctx, target); 582 if (!bindTarget) { 583 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)"); 584 return; 585 } 586 587 /* Get pointer to old buffer object (to be unbound) */ 588 oldBufObj = *bindTarget; 589 if (oldBufObj && oldBufObj->Name == buffer) 590 return; /* rebinding the same buffer object- no change */ 591 592 /* 593 * Get pointer to new buffer object (newBufObj) 594 */ 595 if (buffer == 0) { 596 /* The spec says there's not a buffer object named 0, but we use 597 * one internally because it simplifies things. 598 */ 599 newBufObj = ctx->Shared->NullBufferObj; 600 } 601 else { 602 /* non-default buffer object */ 603 newBufObj = _mesa_lookup_bufferobj(ctx, buffer); 604 if (!newBufObj) { 605 /* if this is a new buffer object id, allocate a buffer object now */ 606 ASSERT(ctx->Driver.NewBufferObject); 607 newBufObj = ctx->Driver.NewBufferObject(ctx, buffer, target); 608 if (!newBufObj) { 609 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB"); 610 return; 611 } 612 _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, newBufObj); 613 } 614 } 615 616 /* bind new buffer */ 617 _mesa_reference_buffer_object(ctx, bindTarget, newBufObj); 618 619 /* Pass BindBuffer call to device driver */ 620 if (ctx->Driver.BindBuffer) 621 ctx->Driver.BindBuffer( ctx, target, newBufObj ); 622} 623 624 625/** 626 * Update the default buffer objects in the given context to reference those 627 * specified in the shared state and release those referencing the old 628 * shared state. 629 */ 630void 631_mesa_update_default_objects_buffer_objects(GLcontext *ctx) 632{ 633 /* Bind the NullBufferObj to remove references to those 634 * in the shared context hash table. 635 */ 636 bind_buffer_object( ctx, GL_ARRAY_BUFFER_ARB, 0); 637 bind_buffer_object( ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, 0); 638 bind_buffer_object( ctx, GL_PIXEL_PACK_BUFFER_ARB, 0); 639 bind_buffer_object( ctx, GL_PIXEL_UNPACK_BUFFER_ARB, 0); 640} 641 642 643/** 644 * When we're about to read pixel data out of a PBO (via glDrawPixels, 645 * glTexImage, etc) or write data into a PBO (via glReadPixels, 646 * glGetTexImage, etc) we call this function to check that we're not 647 * going to read out of bounds. 648 * 649 * XXX This would also be a convenient time to check that the PBO isn't 650 * currently mapped. Whoever calls this function should check for that. 651 * Remember, we can't use a PBO when it's mapped! 652 * 653 * If we're not using a PBO, this is a no-op. 654 * 655 * \param width width of image to read/write 656 * \param height height of image to read/write 657 * \param depth depth of image to read/write 658 * \param format format of image to read/write 659 * \param type datatype of image to read/write 660 * \param ptr the user-provided pointer/offset 661 * \return GL_TRUE if the PBO access is OK, GL_FALSE if the access would 662 * go out of bounds. 663 */ 664GLboolean 665_mesa_validate_pbo_access(GLuint dimensions, 666 const struct gl_pixelstore_attrib *pack, 667 GLsizei width, GLsizei height, GLsizei depth, 668 GLenum format, GLenum type, const GLvoid *ptr) 669{ 670 GLvoid *start, *end; 671 const GLubyte *sizeAddr; /* buffer size, cast to a pointer */ 672 673 if (!_mesa_is_bufferobj(pack->BufferObj)) 674 return GL_TRUE; /* no PBO, OK */ 675 676 if (pack->BufferObj->Size == 0) 677 /* no buffer! */ 678 return GL_FALSE; 679 680 /* get address of first pixel we'll read */ 681 start = _mesa_image_address(dimensions, pack, ptr, width, height, 682 format, type, 0, 0, 0); 683 684 /* get address just past the last pixel we'll read */ 685 end = _mesa_image_address(dimensions, pack, ptr, width, height, 686 format, type, depth-1, height-1, width); 687 688 689 sizeAddr = ((const GLubyte *) 0) + pack->BufferObj->Size; 690 691 if ((const GLubyte *) start > sizeAddr) { 692 /* This will catch negative values / wrap-around */ 693 return GL_FALSE; 694 } 695 if ((const GLubyte *) end > sizeAddr) { 696 /* Image read goes beyond end of buffer */ 697 return GL_FALSE; 698 } 699 700 /* OK! */ 701 return GL_TRUE; 702} 703 704 705/** 706 * For commands that read from a PBO (glDrawPixels, glTexImage, 707 * glPolygonStipple, etc), if we're reading from a PBO, map it read-only 708 * and return the pointer into the PBO. If we're not reading from a 709 * PBO, return \p src as-is. 710 * If non-null return, must call _mesa_unmap_pbo_source() when done. 711 * 712 * \return NULL if error, else pointer to start of data 713 */ 714const GLvoid * 715_mesa_map_pbo_source(GLcontext *ctx, 716 const struct gl_pixelstore_attrib *unpack, 717 const GLvoid *src) 718{ 719 const GLubyte *buf; 720 721 if (_mesa_is_bufferobj(unpack->BufferObj)) { 722 /* unpack from PBO */ 723 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, 724 GL_READ_ONLY_ARB, 725 unpack->BufferObj); 726 if (!buf) 727 return NULL; 728 729 buf = ADD_POINTERS(buf, src); 730 } 731 else { 732 /* unpack from normal memory */ 733 buf = src; 734 } 735 736 return buf; 737} 738 739 740/** 741 * Combine PBO-read validation and mapping. 742 * If any GL errors are detected, they'll be recorded and NULL returned. 743 * \sa _mesa_validate_pbo_access 744 * \sa _mesa_map_pbo_source 745 * A call to this function should have a matching call to 746 * _mesa_unmap_pbo_source(). 747 */ 748const GLvoid * 749_mesa_map_validate_pbo_source(GLcontext *ctx, 750 GLuint dimensions, 751 const struct gl_pixelstore_attrib *unpack, 752 GLsizei width, GLsizei height, GLsizei depth, 753 GLenum format, GLenum type, const GLvoid *ptr, 754 const char *where) 755{ 756 ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); 757 758 if (!_mesa_is_bufferobj(unpack->BufferObj)) { 759 /* non-PBO access: no validation to be done */ 760 return ptr; 761 } 762 763 if (!_mesa_validate_pbo_access(dimensions, unpack, 764 width, height, depth, format, type, ptr)) { 765 _mesa_error(ctx, GL_INVALID_OPERATION, 766 "%s(out of bounds PBO access)", where); 767 return NULL; 768 } 769 770 if (_mesa_bufferobj_mapped(unpack->BufferObj)) { 771 /* buffer is already mapped - that's an error */ 772 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); 773 return NULL; 774 } 775 776 ptr = _mesa_map_pbo_source(ctx, unpack, ptr); 777 return ptr; 778} 779 780 781/** 782 * Counterpart to _mesa_map_pbo_source() 783 */ 784void 785_mesa_unmap_pbo_source(GLcontext *ctx, 786 const struct gl_pixelstore_attrib *unpack) 787{ 788 ASSERT(unpack != &ctx->Pack); /* catch pack/unpack mismatch */ 789 if (_mesa_is_bufferobj(unpack->BufferObj)) { 790 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, 791 unpack->BufferObj); 792 } 793} 794 795 796/** 797 * For commands that write to a PBO (glReadPixels, glGetColorTable, etc), 798 * if we're writing to a PBO, map it write-only and return the pointer 799 * into the PBO. If we're not writing to a PBO, return \p dst as-is. 800 * If non-null return, must call _mesa_unmap_pbo_dest() when done. 801 * 802 * \return NULL if error, else pointer to start of data 803 */ 804void * 805_mesa_map_pbo_dest(GLcontext *ctx, 806 const struct gl_pixelstore_attrib *pack, 807 GLvoid *dest) 808{ 809 void *buf; 810 811 if (_mesa_is_bufferobj(pack->BufferObj)) { 812 /* pack into PBO */ 813 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, 814 GL_WRITE_ONLY_ARB, 815 pack->BufferObj); 816 if (!buf) 817 return NULL; 818 819 buf = ADD_POINTERS(buf, dest); 820 } 821 else { 822 /* pack to normal memory */ 823 buf = dest; 824 } 825 826 return buf; 827} 828 829 830/** 831 * Combine PBO-write validation and mapping. 832 * If any GL errors are detected, they'll be recorded and NULL returned. 833 * \sa _mesa_validate_pbo_access 834 * \sa _mesa_map_pbo_dest 835 * A call to this function should have a matching call to 836 * _mesa_unmap_pbo_dest(). 837 */ 838GLvoid * 839_mesa_map_validate_pbo_dest(GLcontext *ctx, 840 GLuint dimensions, 841 const struct gl_pixelstore_attrib *unpack, 842 GLsizei width, GLsizei height, GLsizei depth, 843 GLenum format, GLenum type, GLvoid *ptr, 844 const char *where) 845{ 846 ASSERT(dimensions == 1 || dimensions == 2 || dimensions == 3); 847 848 if (!_mesa_is_bufferobj(unpack->BufferObj)) { 849 /* non-PBO access: no validation to be done */ 850 return ptr; 851 } 852 853 if (!_mesa_validate_pbo_access(dimensions, unpack, 854 width, height, depth, format, type, ptr)) { 855 _mesa_error(ctx, GL_INVALID_OPERATION, 856 "%s(out of bounds PBO access)", where); 857 return NULL; 858 } 859 860 if (_mesa_bufferobj_mapped(unpack->BufferObj)) { 861 /* buffer is already mapped - that's an error */ 862 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(PBO is mapped)", where); 863 return NULL; 864 } 865 866 ptr = _mesa_map_pbo_dest(ctx, unpack, ptr); 867 return ptr; 868} 869 870 871/** 872 * Counterpart to _mesa_map_pbo_dest() 873 */ 874void 875_mesa_unmap_pbo_dest(GLcontext *ctx, 876 const struct gl_pixelstore_attrib *pack) 877{ 878 ASSERT(pack != &ctx->Unpack); /* catch pack/unpack mismatch */ 879 if (_mesa_is_bufferobj(pack->BufferObj)) { 880 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT, pack->BufferObj); 881 } 882} 883 884 885 886/** 887 * Return the gl_buffer_object for the given ID. 888 * Always return NULL for ID 0. 889 */ 890struct gl_buffer_object * 891_mesa_lookup_bufferobj(GLcontext *ctx, GLuint buffer) 892{ 893 if (buffer == 0) 894 return NULL; 895 else 896 return (struct gl_buffer_object *) 897 _mesa_HashLookup(ctx->Shared->BufferObjects, buffer); 898} 899 900 901/** 902 * If *ptr points to obj, set ptr = the Null/default buffer object. 903 * This is a helper for buffer object deletion. 904 * The GL spec says that deleting a buffer object causes it to get 905 * unbound from all arrays in the current context. 906 */ 907static void 908unbind(GLcontext *ctx, 909 struct gl_buffer_object **ptr, 910 struct gl_buffer_object *obj) 911{ 912 if (*ptr == obj) { 913 _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj); 914 } 915} 916 917 918/** 919 * Plug default/fallback buffer object functions into the device 920 * driver hooks. 921 */ 922void 923_mesa_init_buffer_object_functions(struct dd_function_table *driver) 924{ 925 /* GL_ARB_vertex/pixel_buffer_object */ 926 driver->NewBufferObject = _mesa_new_buffer_object; 927 driver->DeleteBuffer = _mesa_delete_buffer_object; 928 driver->BindBuffer = NULL; 929 driver->BufferData = _mesa_buffer_data; 930 driver->BufferSubData = _mesa_buffer_subdata; 931 driver->GetBufferSubData = _mesa_buffer_get_subdata; 932 driver->MapBuffer = _mesa_buffer_map; 933 driver->UnmapBuffer = _mesa_buffer_unmap; 934 935 /* GL_ARB_map_buffer_range */ 936 driver->MapBufferRange = _mesa_buffer_map_range; 937 driver->FlushMappedBufferRange = _mesa_buffer_flush_mapped_range; 938 939 /* GL_ARB_copy_buffer */ 940 driver->CopyBufferSubData = _mesa_copy_buffer_subdata; 941} 942 943 944 945/**********************************************************************/ 946/* API Functions */ 947/**********************************************************************/ 948 949void GLAPIENTRY 950_mesa_BindBufferARB(GLenum target, GLuint buffer) 951{ 952 GET_CURRENT_CONTEXT(ctx); 953 ASSERT_OUTSIDE_BEGIN_END(ctx); 954 955 bind_buffer_object(ctx, target, buffer); 956} 957 958 959/** 960 * Delete a set of buffer objects. 961 * 962 * \param n Number of buffer objects to delete. 963 * \param ids Array of \c n buffer object IDs. 964 */ 965void GLAPIENTRY 966_mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids) 967{ 968 GET_CURRENT_CONTEXT(ctx); 969 GLsizei i; 970 ASSERT_OUTSIDE_BEGIN_END(ctx); 971 972 if (n < 0) { 973 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)"); 974 return; 975 } 976 977 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 978 979 for (i = 0; i < n; i++) { 980 struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]); 981 if (bufObj) { 982 struct gl_array_object *arrayObj = ctx->Array.ArrayObj; 983 GLuint j; 984 985 ASSERT(bufObj->Name == ids[i]); 986 987 if (_mesa_bufferobj_mapped(bufObj)) { 988 /* if mapped, unmap it now */ 989 ctx->Driver.UnmapBuffer(ctx, 0, bufObj); 990 bufObj->AccessFlags = DEFAULT_ACCESS; 991 bufObj->Pointer = NULL; 992 } 993 994 /* unbind any vertex pointers bound to this buffer */ 995 unbind(ctx, &arrayObj->Vertex.BufferObj, bufObj); 996 unbind(ctx, &arrayObj->Weight.BufferObj, bufObj); 997 unbind(ctx, &arrayObj->Normal.BufferObj, bufObj); 998 unbind(ctx, &arrayObj->Color.BufferObj, bufObj); 999 unbind(ctx, &arrayObj->SecondaryColor.BufferObj, bufObj); 1000 unbind(ctx, &arrayObj->FogCoord.BufferObj, bufObj); 1001 unbind(ctx, &arrayObj->Index.BufferObj, bufObj); 1002 unbind(ctx, &arrayObj->EdgeFlag.BufferObj, bufObj); 1003 for (j = 0; j < Elements(arrayObj->TexCoord); j++) { 1004 unbind(ctx, &arrayObj->TexCoord[j].BufferObj, bufObj); 1005 } 1006 for (j = 0; j < Elements(arrayObj->VertexAttrib); j++) { 1007 unbind(ctx, &arrayObj->VertexAttrib[j].BufferObj, bufObj); 1008 } 1009 1010 if (ctx->Array.ArrayBufferObj == bufObj) { 1011 _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 ); 1012 } 1013 if (ctx->Array.ElementArrayBufferObj == bufObj) { 1014 _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 ); 1015 } 1016 1017 /* unbind any pixel pack/unpack pointers bound to this buffer */ 1018 if (ctx->Pack.BufferObj == bufObj) { 1019 _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 ); 1020 } 1021 if (ctx->Unpack.BufferObj == bufObj) { 1022 _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 ); 1023 } 1024 1025 /* The ID is immediately freed for re-use */ 1026 _mesa_HashRemove(ctx->Shared->BufferObjects, bufObj->Name); 1027 _mesa_reference_buffer_object(ctx, &bufObj, NULL); 1028 } 1029 } 1030 1031 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 1032} 1033 1034 1035/** 1036 * Generate a set of unique buffer object IDs and store them in \c buffer. 1037 * 1038 * \param n Number of IDs to generate. 1039 * \param buffer Array of \c n locations to store the IDs. 1040 */ 1041void GLAPIENTRY 1042_mesa_GenBuffersARB(GLsizei n, GLuint *buffer) 1043{ 1044 GET_CURRENT_CONTEXT(ctx); 1045 GLuint first; 1046 GLint i; 1047 ASSERT_OUTSIDE_BEGIN_END(ctx); 1048 1049 if (n < 0) { 1050 _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB"); 1051 return; 1052 } 1053 1054 if (!buffer) { 1055 return; 1056 } 1057 1058 /* 1059 * This must be atomic (generation and allocation of buffer object IDs) 1060 */ 1061 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 1062 1063 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n); 1064 1065 /* Allocate new, empty buffer objects and return identifiers */ 1066 for (i = 0; i < n; i++) { 1067 struct gl_buffer_object *bufObj; 1068 GLuint name = first + i; 1069 GLenum target = 0; 1070 bufObj = ctx->Driver.NewBufferObject( ctx, name, target ); 1071 if (!bufObj) { 1072 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 1073 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenBuffersARB"); 1074 return; 1075 } 1076 _mesa_HashInsert(ctx->Shared->BufferObjects, first + i, bufObj); 1077 buffer[i] = first + i; 1078 } 1079 1080 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 1081} 1082 1083 1084/** 1085 * Determine if ID is the name of a buffer object. 1086 * 1087 * \param id ID of the potential buffer object. 1088 * \return \c GL_TRUE if \c id is the name of a buffer object, 1089 * \c GL_FALSE otherwise. 1090 */ 1091GLboolean GLAPIENTRY 1092_mesa_IsBufferARB(GLuint id) 1093{ 1094 struct gl_buffer_object *bufObj; 1095 GET_CURRENT_CONTEXT(ctx); 1096 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 1097 1098 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 1099 bufObj = _mesa_lookup_bufferobj(ctx, id); 1100 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 1101 1102 return bufObj ? GL_TRUE : GL_FALSE; 1103} 1104 1105 1106void GLAPIENTRY 1107_mesa_BufferDataARB(GLenum target, GLsizeiptrARB size, 1108 const GLvoid * data, GLenum usage) 1109{ 1110 GET_CURRENT_CONTEXT(ctx); 1111 struct gl_buffer_object *bufObj; 1112 ASSERT_OUTSIDE_BEGIN_END(ctx); 1113 1114 if (size < 0) { 1115 _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)"); 1116 return; 1117 } 1118 1119 switch (usage) { 1120 case GL_STREAM_DRAW_ARB: 1121 case GL_STREAM_READ_ARB: 1122 case GL_STREAM_COPY_ARB: 1123 case GL_STATIC_DRAW_ARB: 1124 case GL_STATIC_READ_ARB: 1125 case GL_STATIC_COPY_ARB: 1126 case GL_DYNAMIC_DRAW_ARB: 1127 case GL_DYNAMIC_READ_ARB: 1128 case GL_DYNAMIC_COPY_ARB: 1129 /* OK */ 1130 break; 1131 default: 1132 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(usage)"); 1133 return; 1134 } 1135 1136 bufObj = get_buffer(ctx, target); 1137 if (!bufObj) { 1138 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferDataARB(target)" ); 1139 return; 1140 } 1141 if (!_mesa_is_bufferobj(bufObj)) { 1142 _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferDataARB(buffer 0)" ); 1143 return; 1144 } 1145 1146 if (_mesa_bufferobj_mapped(bufObj)) { 1147 /* Unmap the existing buffer. We'll replace it now. Not an error. */ 1148 ctx->Driver.UnmapBuffer(ctx, target, bufObj); 1149 bufObj->AccessFlags = DEFAULT_ACCESS; 1150 ASSERT(bufObj->Pointer == NULL); 1151 } 1152 1153 FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT); 1154 1155 bufObj->Written = GL_TRUE; 1156 1157#ifdef VBO_DEBUG 1158 _mesa_printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n", 1159 bufObj->Name, size, data, usage); 1160#endif 1161 1162#ifdef BOUNDS_CHECK 1163 size += 100; 1164#endif 1165 1166 ASSERT(ctx->Driver.BufferData); 1167 if (!ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj )) { 1168 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferDataARB()"); 1169 } 1170} 1171 1172 1173void GLAPIENTRY 1174_mesa_BufferSubDataARB(GLenum target, GLintptrARB offset, 1175 GLsizeiptrARB size, const GLvoid * data) 1176{ 1177 GET_CURRENT_CONTEXT(ctx); 1178 struct gl_buffer_object *bufObj; 1179 ASSERT_OUTSIDE_BEGIN_END(ctx); 1180 1181 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, 1182 "glBufferSubDataARB" ); 1183 if (!bufObj) { 1184 /* error already recorded */ 1185 return; 1186 } 1187 1188 bufObj->Written = GL_TRUE; 1189 1190 ASSERT(ctx->Driver.BufferSubData); 1191 ctx->Driver.BufferSubData( ctx, target, offset, size, data, bufObj ); 1192} 1193 1194 1195void GLAPIENTRY 1196_mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset, 1197 GLsizeiptrARB size, void * data) 1198{ 1199 GET_CURRENT_CONTEXT(ctx); 1200 struct gl_buffer_object *bufObj; 1201 ASSERT_OUTSIDE_BEGIN_END(ctx); 1202 1203 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, 1204 "glGetBufferSubDataARB" ); 1205 if (!bufObj) { 1206 /* error already recorded */ 1207 return; 1208 } 1209 1210 ASSERT(ctx->Driver.GetBufferSubData); 1211 ctx->Driver.GetBufferSubData( ctx, target, offset, size, data, bufObj ); 1212} 1213 1214 1215void * GLAPIENTRY 1216_mesa_MapBufferARB(GLenum target, GLenum access) 1217{ 1218 GET_CURRENT_CONTEXT(ctx); 1219 struct gl_buffer_object * bufObj; 1220 GLbitfield accessFlags; 1221 void *map; 1222 1223 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); 1224 1225 switch (access) { 1226 case GL_READ_ONLY_ARB: 1227 accessFlags = GL_MAP_READ_BIT; 1228 break; 1229 case GL_WRITE_ONLY_ARB: 1230 accessFlags = GL_MAP_WRITE_BIT; 1231 break; 1232 case GL_READ_WRITE_ARB: 1233 accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; 1234 break; 1235 default: 1236 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)"); 1237 return NULL; 1238 } 1239 1240 bufObj = get_buffer(ctx, target); 1241 if (!bufObj) { 1242 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(target)" ); 1243 return NULL; 1244 } 1245 if (!_mesa_is_bufferobj(bufObj)) { 1246 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(buffer 0)" ); 1247 return NULL; 1248 } 1249 if (_mesa_bufferobj_mapped(bufObj)) { 1250 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)"); 1251 return NULL; 1252 } 1253 1254 ASSERT(ctx->Driver.MapBuffer); 1255 map = ctx->Driver.MapBuffer( ctx, target, access, bufObj ); 1256 if (!map) { 1257 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); 1258 return NULL; 1259 } 1260 else { 1261 /* The driver callback should have set these fields. 1262 * This is important because other modules (like VBO) might call 1263 * the driver function directly. 1264 */ 1265 ASSERT(bufObj->Pointer == map); 1266 ASSERT(bufObj->Length == bufObj->Size); 1267 ASSERT(bufObj->Offset == 0); 1268 bufObj->AccessFlags = accessFlags; 1269 } 1270 1271 if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB) 1272 bufObj->Written = GL_TRUE; 1273 1274#ifdef VBO_DEBUG 1275 _mesa_printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n", 1276 bufObj->Name, bufObj->Size, access); 1277 if (access == GL_WRITE_ONLY_ARB) { 1278 GLuint i; 1279 GLubyte *b = (GLubyte *) bufObj->Pointer; 1280 for (i = 0; i < bufObj->Size; i++) 1281 b[i] = i & 0xff; 1282 } 1283#endif 1284 1285#ifdef BOUNDS_CHECK 1286 { 1287 GLubyte *buf = (GLubyte *) bufObj->Pointer; 1288 GLuint i; 1289 /* buffer is 100 bytes larger than requested, fill with magic value */ 1290 for (i = 0; i < 100; i++) { 1291 buf[bufObj->Size - i - 1] = 123; 1292 } 1293 } 1294#endif 1295 1296 return bufObj->Pointer; 1297} 1298 1299 1300GLboolean GLAPIENTRY 1301_mesa_UnmapBufferARB(GLenum target) 1302{ 1303 GET_CURRENT_CONTEXT(ctx); 1304 struct gl_buffer_object *bufObj; 1305 GLboolean status = GL_TRUE; 1306 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 1307 1308 bufObj = get_buffer(ctx, target); 1309 if (!bufObj) { 1310 _mesa_error(ctx, GL_INVALID_ENUM, "glUnmapBufferARB(target)" ); 1311 return GL_FALSE; 1312 } 1313 if (!_mesa_is_bufferobj(bufObj)) { 1314 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB" ); 1315 return GL_FALSE; 1316 } 1317 if (!_mesa_bufferobj_mapped(bufObj)) { 1318 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB"); 1319 return GL_FALSE; 1320 } 1321 1322#ifdef BOUNDS_CHECK 1323 if (bufObj->Access != GL_READ_ONLY_ARB) { 1324 GLubyte *buf = (GLubyte *) bufObj->Pointer; 1325 GLuint i; 1326 /* check that last 100 bytes are still = magic value */ 1327 for (i = 0; i < 100; i++) { 1328 GLuint pos = bufObj->Size - i - 1; 1329 if (buf[pos] != 123) { 1330 _mesa_warning(ctx, "Out of bounds buffer object write detected" 1331 " at position %d (value = %u)\n", 1332 pos, buf[pos]); 1333 } 1334 } 1335 } 1336#endif 1337 1338#ifdef VBO_DEBUG 1339 if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) { 1340 GLuint i, unchanged = 0; 1341 GLubyte *b = (GLubyte *) bufObj->Pointer; 1342 GLint pos = -1; 1343 /* check which bytes changed */ 1344 for (i = 0; i < bufObj->Size - 1; i++) { 1345 if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) { 1346 unchanged++; 1347 if (pos == -1) 1348 pos = i; 1349 } 1350 } 1351 if (unchanged) { 1352 _mesa_printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n", 1353 bufObj->Name, unchanged, bufObj->Size, pos); 1354 } 1355 } 1356#endif 1357 1358 status = ctx->Driver.UnmapBuffer( ctx, target, bufObj ); 1359 bufObj->AccessFlags = DEFAULT_ACCESS; 1360 ASSERT(bufObj->Pointer == NULL); 1361 ASSERT(bufObj->Offset == 0); 1362 ASSERT(bufObj->Length == 0); 1363 1364 return status; 1365} 1366 1367 1368void GLAPIENTRY 1369_mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params) 1370{ 1371 GET_CURRENT_CONTEXT(ctx); 1372 struct gl_buffer_object *bufObj; 1373 ASSERT_OUTSIDE_BEGIN_END(ctx); 1374 1375 bufObj = get_buffer(ctx, target); 1376 if (!bufObj) { 1377 _mesa_error(ctx, GL_INVALID_ENUM, "GetBufferParameterivARB(target)" ); 1378 return; 1379 } 1380 if (!_mesa_is_bufferobj(bufObj)) { 1381 _mesa_error(ctx, GL_INVALID_OPERATION, "GetBufferParameterivARB" ); 1382 return; 1383 } 1384 1385 switch (pname) { 1386 case GL_BUFFER_SIZE_ARB: 1387 *params = (GLint) bufObj->Size; 1388 break; 1389 case GL_BUFFER_USAGE_ARB: 1390 *params = bufObj->Usage; 1391 break; 1392 case GL_BUFFER_ACCESS_ARB: 1393 *params = simplified_access_mode(bufObj->AccessFlags); 1394 break; 1395 case GL_BUFFER_MAPPED_ARB: 1396 *params = _mesa_bufferobj_mapped(bufObj); 1397 break; 1398 default: 1399 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname)"); 1400 return; 1401 } 1402} 1403 1404 1405void GLAPIENTRY 1406_mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params) 1407{ 1408 GET_CURRENT_CONTEXT(ctx); 1409 struct gl_buffer_object * bufObj; 1410 ASSERT_OUTSIDE_BEGIN_END(ctx); 1411 1412 if (pname != GL_BUFFER_MAP_POINTER_ARB) { 1413 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)"); 1414 return; 1415 } 1416 1417 bufObj = get_buffer(ctx, target); 1418 if (!bufObj) { 1419 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(target)" ); 1420 return; 1421 } 1422 if (!_mesa_is_bufferobj(bufObj)) { 1423 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetBufferPointervARB" ); 1424 return; 1425 } 1426 1427 *params = bufObj->Pointer; 1428} 1429 1430 1431void GLAPIENTRY 1432_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, 1433 GLintptr readOffset, GLintptr writeOffset, 1434 GLsizeiptr size) 1435{ 1436 GET_CURRENT_CONTEXT(ctx); 1437 struct gl_buffer_object *src, *dst; 1438 ASSERT_OUTSIDE_BEGIN_END(ctx); 1439 1440 src = get_buffer(ctx, readTarget); 1441 if (!src || !_mesa_is_bufferobj(src)) { 1442 _mesa_error(ctx, GL_INVALID_ENUM, 1443 "glCopyBuffserSubData(readTarget = 0x%x)", readTarget); 1444 return; 1445 } 1446 1447 dst = get_buffer(ctx, writeTarget); 1448 if (!dst || !_mesa_is_bufferobj(dst)) { 1449 _mesa_error(ctx, GL_INVALID_ENUM, 1450 "glCopyBuffserSubData(writeTarget = 0x%x)", writeTarget); 1451 return; 1452 } 1453 1454 if (_mesa_bufferobj_mapped(src)) { 1455 _mesa_error(ctx, GL_INVALID_OPERATION, 1456 "glCopyBuffserSubData(readBuffer is mapped)"); 1457 return; 1458 } 1459 1460 if (_mesa_bufferobj_mapped(dst)) { 1461 _mesa_error(ctx, GL_INVALID_OPERATION, 1462 "glCopyBuffserSubData(writeBuffer is mapped)"); 1463 return; 1464 } 1465 1466 if (readOffset < 0) { 1467 _mesa_error(ctx, GL_INVALID_VALUE, 1468 "glCopyBuffserSubData(readOffset = %d)", readOffset); 1469 return; 1470 } 1471 1472 if (writeOffset < 0) { 1473 _mesa_error(ctx, GL_INVALID_VALUE, 1474 "glCopyBuffserSubData(writeOffset = %d)", writeOffset); 1475 return; 1476 } 1477 1478 if (readOffset + size > src->Size) { 1479 _mesa_error(ctx, GL_INVALID_VALUE, 1480 "glCopyBuffserSubData(readOffset + size = %d)", 1481 readOffset, size); 1482 return; 1483 } 1484 1485 if (writeOffset + size > dst->Size) { 1486 _mesa_error(ctx, GL_INVALID_VALUE, 1487 "glCopyBuffserSubData(writeOffset + size = %d)", 1488 writeOffset, size); 1489 return; 1490 } 1491 1492 if (src == dst) { 1493 if (readOffset + size <= writeOffset) { 1494 /* OK */ 1495 } 1496 else if (writeOffset + size <= readOffset) { 1497 /* OK */ 1498 } 1499 else { 1500 /* overlapping src/dst is illegal */ 1501 _mesa_error(ctx, GL_INVALID_VALUE, 1502 "glCopyBuffserSubData(overlapping src/dst)"); 1503 return; 1504 } 1505 } 1506 1507 ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size); 1508} 1509 1510 1511/** 1512 * See GL_ARB_map_buffer_range spec 1513 */ 1514void * GLAPIENTRY 1515_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, 1516 GLbitfield access) 1517{ 1518 GET_CURRENT_CONTEXT(ctx); 1519 struct gl_buffer_object *bufObj; 1520 void *map; 1521 1522 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); 1523 1524 if (!ctx->Extensions.ARB_map_buffer_range) { 1525 _mesa_error(ctx, GL_INVALID_OPERATION, 1526 "glMapBufferRange(extension not supported)"); 1527 return NULL; 1528 } 1529 1530 if (offset < 0) { 1531 _mesa_error(ctx, GL_INVALID_VALUE, 1532 "glMapBufferRange(offset = %ld)", offset); 1533 return NULL; 1534 } 1535 1536 if (length < 0) { 1537 _mesa_error(ctx, GL_INVALID_VALUE, 1538 "glMapBufferRange(length = %ld)", length); 1539 return NULL; 1540 } 1541 1542 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) { 1543 _mesa_error(ctx, GL_INVALID_OPERATION, 1544 "glMapBufferRange(access indicates neither read or write)"); 1545 return NULL; 1546 } 1547 1548 if (access & GL_MAP_READ_BIT) { 1549 if ((access & GL_MAP_INVALIDATE_RANGE_BIT) || 1550 (access & GL_MAP_INVALIDATE_BUFFER_BIT) || 1551 (access & GL_MAP_UNSYNCHRONIZED_BIT)) { 1552 _mesa_error(ctx, GL_INVALID_OPERATION, 1553 "glMapBufferRange(invalid access flags)"); 1554 return NULL; 1555 } 1556 } 1557 1558 if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) && 1559 ((access & GL_MAP_WRITE_BIT) == 0)) { 1560 _mesa_error(ctx, GL_INVALID_OPERATION, 1561 "glMapBufferRange(invalid access flags)"); 1562 return NULL; 1563 } 1564 1565 bufObj = get_buffer(ctx, target); 1566 if (!bufObj || !_mesa_is_bufferobj(bufObj)) { 1567 _mesa_error(ctx, GL_INVALID_ENUM, 1568 "glMapBufferRange(target = 0x%x)", target); 1569 return NULL; 1570 } 1571 1572 if (offset + length > bufObj->Size) { 1573 _mesa_error(ctx, GL_INVALID_VALUE, 1574 "glMapBufferRange(offset + length > size)"); 1575 return NULL; 1576 } 1577 1578 if (_mesa_bufferobj_mapped(bufObj)) { 1579 _mesa_error(ctx, GL_INVALID_OPERATION, 1580 "glMapBufferRange(buffer already mapped)"); 1581 return NULL; 1582 } 1583 1584 ASSERT(ctx->Driver.MapBufferRange); 1585 map = ctx->Driver.MapBufferRange(ctx, target, offset, length, 1586 access, bufObj); 1587 if (!map) { 1588 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); 1589 } 1590 else { 1591 /* The driver callback should have set all these fields. 1592 * This is important because other modules (like VBO) might call 1593 * the driver function directly. 1594 */ 1595 ASSERT(bufObj->Pointer == map); 1596 ASSERT(bufObj->Length == length); 1597 ASSERT(bufObj->Offset == offset); 1598 ASSERT(bufObj->AccessFlags == access); 1599 } 1600 1601 return map; 1602} 1603 1604 1605/** 1606 * See GL_ARB_map_buffer_range spec 1607 */ 1608void GLAPIENTRY 1609_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) 1610{ 1611 GET_CURRENT_CONTEXT(ctx); 1612 struct gl_buffer_object *bufObj; 1613 ASSERT_OUTSIDE_BEGIN_END(ctx); 1614 1615 if (!ctx->Extensions.ARB_map_buffer_range) { 1616 _mesa_error(ctx, GL_INVALID_OPERATION, 1617 "glMapBufferRange(extension not supported)"); 1618 return; 1619 } 1620 1621 if (offset < 0) { 1622 _mesa_error(ctx, GL_INVALID_VALUE, 1623 "glMapBufferRange(offset = %ld)", offset); 1624 return; 1625 } 1626 1627 if (length < 0) { 1628 _mesa_error(ctx, GL_INVALID_VALUE, 1629 "glMapBufferRange(length = %ld)", length); 1630 return; 1631 } 1632 1633 bufObj = get_buffer(ctx, target); 1634 if (!bufObj) { 1635 _mesa_error(ctx, GL_INVALID_ENUM, 1636 "glMapBufferRange(target = 0x%x)", target); 1637 return; 1638 } 1639 1640 if (!_mesa_is_bufferobj(bufObj)) { 1641 _mesa_error(ctx, GL_INVALID_OPERATION, 1642 "glMapBufferRange(current buffer is 0)"); 1643 return; 1644 } 1645 1646 if (!_mesa_bufferobj_mapped(bufObj)) { 1647 /* buffer is not mapped */ 1648 _mesa_error(ctx, GL_INVALID_OPERATION, 1649 "glMapBufferRange(buffer is not mapped)"); 1650 return; 1651 } 1652 1653 if ((bufObj->AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) { 1654 _mesa_error(ctx, GL_INVALID_OPERATION, 1655 "glMapBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)"); 1656 return; 1657 } 1658 1659 if (offset + length > bufObj->Length) { 1660 _mesa_error(ctx, GL_INVALID_VALUE, 1661 "glMapBufferRange(offset %ld + length %ld > mapped length %ld)", 1662 offset, length, bufObj->Length); 1663 return; 1664 } 1665 1666 ASSERT(bufObj->AccessFlags & GL_MAP_WRITE_BIT); 1667 1668 if (ctx->Driver.FlushMappedBufferRange) 1669 ctx->Driver.FlushMappedBufferRange(ctx, target, offset, length, bufObj); 1670} 1671