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