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