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 #include <stdbool.h> 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 */ 58 static 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 */ 68 static inline struct gl_buffer_object ** 69 get_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 */ 122 static inline struct gl_buffer_object * 123 get_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 141 static inline GLbitfield 142 default_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 */ 169 static GLenum 170 simplified_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 */ 199 static struct gl_buffer_object * 200 buffer_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 */ 243 static 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 */ 261 static 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 */ 285 void 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 */ 348 void 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 */ 368 static void 369 count_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 */ 383 GLuint 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 */ 413 static 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 */ 457 static 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 */ 490 static 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 */ 507 static 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 */ 527 static 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 */ 547 static 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 */ 564 static 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 */ 611 void 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 644 void 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 666 static bool 667 handle_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 && ctx->API == API_OPENGL_CORE) { 675 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindBuffer(non-gen name)"); 676 return false; 677 } 678 679 if (!buf || buf == &DummyBufferObject) { 680 /* If this is a new buffer object id, or one which was generated but 681 * never used before, allocate a buffer object now. 682 */ 683 ASSERT(ctx->Driver.NewBufferObject); 684 buf = ctx->Driver.NewBufferObject(ctx, buffer, target); 685 if (!buf) { 686 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindBufferARB"); 687 return false; 688 } 689 _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, buf); 690 *buf_handle = buf; 691 } 692 693 return true; 694 } 695 696 /** 697 * Bind the specified target to buffer for the specified context. 698 * Called by glBindBuffer() and other functions. 699 */ 700 static void 701 bind_buffer_object(struct gl_context *ctx, GLenum target, GLuint buffer) 702 { 703 struct gl_buffer_object *oldBufObj; 704 struct gl_buffer_object *newBufObj = NULL; 705 struct gl_buffer_object **bindTarget = NULL; 706 707 bindTarget = get_buffer_target(ctx, target); 708 if (!bindTarget) { 709 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)", target); 710 return; 711 } 712 713 /* Get pointer to old buffer object (to be unbound) */ 714 oldBufObj = *bindTarget; 715 if (oldBufObj && oldBufObj->Name == buffer && !oldBufObj->DeletePending) 716 return; /* rebinding the same buffer object- no change */ 717 718 /* 719 * Get pointer to new buffer object (newBufObj) 720 */ 721 if (buffer == 0) { 722 /* The spec says there's not a buffer object named 0, but we use 723 * one internally because it simplifies things. 724 */ 725 newBufObj = ctx->Shared->NullBufferObj; 726 } 727 else { 728 /* non-default buffer object */ 729 newBufObj = _mesa_lookup_bufferobj(ctx, buffer); 730 if (!handle_bind_buffer_gen(ctx, target, buffer, &newBufObj)) 731 return; 732 } 733 734 /* bind new buffer */ 735 _mesa_reference_buffer_object(ctx, bindTarget, newBufObj); 736 737 /* Pass BindBuffer call to device driver */ 738 if (ctx->Driver.BindBuffer) 739 ctx->Driver.BindBuffer( ctx, target, newBufObj ); 740 } 741 742 743 /** 744 * Update the default buffer objects in the given context to reference those 745 * specified in the shared state and release those referencing the old 746 * shared state. 747 */ 748 void 749 _mesa_update_default_objects_buffer_objects(struct gl_context *ctx) 750 { 751 /* Bind the NullBufferObj to remove references to those 752 * in the shared context hash table. 753 */ 754 bind_buffer_object( ctx, GL_ARRAY_BUFFER_ARB, 0); 755 bind_buffer_object( ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, 0); 756 bind_buffer_object( ctx, GL_PIXEL_PACK_BUFFER_ARB, 0); 757 bind_buffer_object( ctx, GL_PIXEL_UNPACK_BUFFER_ARB, 0); 758 } 759 760 761 762 /** 763 * Return the gl_buffer_object for the given ID. 764 * Always return NULL for ID 0. 765 */ 766 struct gl_buffer_object * 767 _mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer) 768 { 769 if (buffer == 0) 770 return NULL; 771 else 772 return (struct gl_buffer_object *) 773 _mesa_HashLookup(ctx->Shared->BufferObjects, buffer); 774 } 775 776 777 /** 778 * If *ptr points to obj, set ptr = the Null/default buffer object. 779 * This is a helper for buffer object deletion. 780 * The GL spec says that deleting a buffer object causes it to get 781 * unbound from all arrays in the current context. 782 */ 783 static void 784 unbind(struct gl_context *ctx, 785 struct gl_buffer_object **ptr, 786 struct gl_buffer_object *obj) 787 { 788 if (*ptr == obj) { 789 _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj); 790 } 791 } 792 793 794 /** 795 * Plug default/fallback buffer object functions into the device 796 * driver hooks. 797 */ 798 void 799 _mesa_init_buffer_object_functions(struct dd_function_table *driver) 800 { 801 /* GL_ARB_vertex/pixel_buffer_object */ 802 driver->NewBufferObject = _mesa_new_buffer_object; 803 driver->DeleteBuffer = _mesa_delete_buffer_object; 804 driver->BindBuffer = NULL; 805 driver->BufferData = _mesa_buffer_data; 806 driver->BufferSubData = _mesa_buffer_subdata; 807 driver->GetBufferSubData = _mesa_buffer_get_subdata; 808 driver->UnmapBuffer = _mesa_buffer_unmap; 809 810 /* GL_ARB_map_buffer_range */ 811 driver->MapBufferRange = _mesa_buffer_map_range; 812 driver->FlushMappedBufferRange = _mesa_buffer_flush_mapped_range; 813 814 /* GL_ARB_copy_buffer */ 815 driver->CopyBufferSubData = _mesa_copy_buffer_subdata; 816 } 817 818 819 820 /**********************************************************************/ 821 /* API Functions */ 822 /**********************************************************************/ 823 824 void GLAPIENTRY 825 _mesa_BindBufferARB(GLenum target, GLuint buffer) 826 { 827 GET_CURRENT_CONTEXT(ctx); 828 ASSERT_OUTSIDE_BEGIN_END(ctx); 829 830 if (MESA_VERBOSE & VERBOSE_API) 831 _mesa_debug(ctx, "glBindBuffer(%s, %u)\n", 832 _mesa_lookup_enum_by_nr(target), buffer); 833 834 bind_buffer_object(ctx, target, buffer); 835 } 836 837 838 /** 839 * Delete a set of buffer objects. 840 * 841 * \param n Number of buffer objects to delete. 842 * \param ids Array of \c n buffer object IDs. 843 */ 844 void GLAPIENTRY 845 _mesa_DeleteBuffersARB(GLsizei n, const GLuint *ids) 846 { 847 GET_CURRENT_CONTEXT(ctx); 848 GLsizei i; 849 ASSERT_OUTSIDE_BEGIN_END(ctx); 850 FLUSH_VERTICES(ctx, 0); 851 852 if (n < 0) { 853 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)"); 854 return; 855 } 856 857 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 858 859 for (i = 0; i < n; i++) { 860 struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]); 861 if (bufObj) { 862 struct gl_array_object *arrayObj = ctx->Array.ArrayObj; 863 GLuint j; 864 865 ASSERT(bufObj->Name == ids[i] || bufObj == &DummyBufferObject); 866 867 if (_mesa_bufferobj_mapped(bufObj)) { 868 /* if mapped, unmap it now */ 869 ctx->Driver.UnmapBuffer(ctx, bufObj); 870 bufObj->AccessFlags = default_access_mode(ctx); 871 bufObj->Pointer = NULL; 872 } 873 874 /* unbind any vertex pointers bound to this buffer */ 875 for (j = 0; j < Elements(arrayObj->VertexAttrib); j++) { 876 unbind(ctx, &arrayObj->VertexAttrib[j].BufferObj, bufObj); 877 } 878 879 if (ctx->Array.ArrayBufferObj == bufObj) { 880 _mesa_BindBufferARB( GL_ARRAY_BUFFER_ARB, 0 ); 881 } 882 if (arrayObj->ElementArrayBufferObj == bufObj) { 883 _mesa_BindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 ); 884 } 885 886 /* unbind ARB_copy_buffer binding points */ 887 if (ctx->CopyReadBuffer == bufObj) { 888 _mesa_BindBufferARB( GL_COPY_READ_BUFFER, 0 ); 889 } 890 if (ctx->CopyWriteBuffer == bufObj) { 891 _mesa_BindBufferARB( GL_COPY_WRITE_BUFFER, 0 ); 892 } 893 894 /* unbind transform feedback binding points */ 895 if (ctx->TransformFeedback.CurrentBuffer == bufObj) { 896 _mesa_BindBufferARB( GL_TRANSFORM_FEEDBACK_BUFFER, 0 ); 897 } 898 for (j = 0; j < MAX_FEEDBACK_BUFFERS; j++) { 899 if (ctx->TransformFeedback.CurrentObject->Buffers[j] == bufObj) { 900 _mesa_BindBufferBase( GL_TRANSFORM_FEEDBACK_BUFFER, j, 0 ); 901 } 902 } 903 904 /* unbind UBO binding points */ 905 for (j = 0; j < ctx->Const.MaxUniformBufferBindings; j++) { 906 if (ctx->UniformBufferBindings[j].BufferObject == bufObj) { 907 _mesa_BindBufferBase( GL_UNIFORM_BUFFER, j, 0 ); 908 } 909 } 910 911 if (ctx->UniformBuffer == bufObj) { 912 _mesa_BindBufferARB( GL_UNIFORM_BUFFER, 0 ); 913 } 914 915 /* unbind any pixel pack/unpack pointers bound to this buffer */ 916 if (ctx->Pack.BufferObj == bufObj) { 917 _mesa_BindBufferARB( GL_PIXEL_PACK_BUFFER_EXT, 0 ); 918 } 919 if (ctx->Unpack.BufferObj == bufObj) { 920 _mesa_BindBufferARB( GL_PIXEL_UNPACK_BUFFER_EXT, 0 ); 921 } 922 923 if (ctx->Texture.BufferObject == bufObj) { 924 _mesa_BindBufferARB( GL_TEXTURE_BUFFER, 0 ); 925 } 926 927 /* The ID is immediately freed for re-use */ 928 _mesa_HashRemove(ctx->Shared->BufferObjects, ids[i]); 929 /* Make sure we do not run into the classic ABA problem on bind. 930 * We don't want to allow re-binding a buffer object that's been 931 * "deleted" by glDeleteBuffers(). 932 * 933 * The explicit rebinding to the default object in the current context 934 * prevents the above in the current context, but another context 935 * sharing the same objects might suffer from this problem. 936 * The alternative would be to do the hash lookup in any case on bind 937 * which would introduce more runtime overhead than this. 938 */ 939 bufObj->DeletePending = GL_TRUE; 940 _mesa_reference_buffer_object(ctx, &bufObj, NULL); 941 } 942 } 943 944 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 945 } 946 947 948 /** 949 * Generate a set of unique buffer object IDs and store them in \c buffer. 950 * 951 * \param n Number of IDs to generate. 952 * \param buffer Array of \c n locations to store the IDs. 953 */ 954 void GLAPIENTRY 955 _mesa_GenBuffersARB(GLsizei n, GLuint *buffer) 956 { 957 GET_CURRENT_CONTEXT(ctx); 958 GLuint first; 959 GLint i; 960 ASSERT_OUTSIDE_BEGIN_END(ctx); 961 962 if (MESA_VERBOSE & VERBOSE_API) 963 _mesa_debug(ctx, "glGenBuffers(%d)\n", n); 964 965 if (n < 0) { 966 _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB"); 967 return; 968 } 969 970 if (!buffer) { 971 return; 972 } 973 974 /* 975 * This must be atomic (generation and allocation of buffer object IDs) 976 */ 977 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 978 979 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n); 980 981 /* Insert the ID and pointer to dummy buffer object into hash table */ 982 for (i = 0; i < n; i++) { 983 _mesa_HashInsert(ctx->Shared->BufferObjects, first + i, 984 &DummyBufferObject); 985 buffer[i] = first + i; 986 } 987 988 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 989 } 990 991 992 /** 993 * Determine if ID is the name of a buffer object. 994 * 995 * \param id ID of the potential buffer object. 996 * \return \c GL_TRUE if \c id is the name of a buffer object, 997 * \c GL_FALSE otherwise. 998 */ 999 GLboolean GLAPIENTRY 1000 _mesa_IsBufferARB(GLuint id) 1001 { 1002 struct gl_buffer_object *bufObj; 1003 GET_CURRENT_CONTEXT(ctx); 1004 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 1005 1006 _glthread_LOCK_MUTEX(ctx->Shared->Mutex); 1007 bufObj = _mesa_lookup_bufferobj(ctx, id); 1008 _glthread_UNLOCK_MUTEX(ctx->Shared->Mutex); 1009 1010 return bufObj && bufObj != &DummyBufferObject; 1011 } 1012 1013 1014 void GLAPIENTRY 1015 _mesa_BufferDataARB(GLenum target, GLsizeiptrARB size, 1016 const GLvoid * data, GLenum usage) 1017 { 1018 GET_CURRENT_CONTEXT(ctx); 1019 struct gl_buffer_object *bufObj; 1020 bool valid_usage; 1021 ASSERT_OUTSIDE_BEGIN_END(ctx); 1022 1023 if (MESA_VERBOSE & VERBOSE_API) 1024 _mesa_debug(ctx, "glBufferData(%s, %ld, %p, %s)\n", 1025 _mesa_lookup_enum_by_nr(target), 1026 (long int) size, data, 1027 _mesa_lookup_enum_by_nr(usage)); 1028 1029 if (size < 0) { 1030 _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)"); 1031 return; 1032 } 1033 1034 switch (usage) { 1035 case GL_STREAM_DRAW_ARB: 1036 valid_usage = (ctx->API != API_OPENGLES); 1037 break; 1038 1039 case GL_STATIC_DRAW_ARB: 1040 case GL_DYNAMIC_DRAW_ARB: 1041 valid_usage = true; 1042 break; 1043 1044 case GL_STREAM_READ_ARB: 1045 case GL_STREAM_COPY_ARB: 1046 case GL_STATIC_READ_ARB: 1047 case GL_STATIC_COPY_ARB: 1048 case GL_DYNAMIC_READ_ARB: 1049 case GL_DYNAMIC_COPY_ARB: 1050 valid_usage = _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx); 1051 break; 1052 1053 default: 1054 valid_usage = false; 1055 break; 1056 } 1057 1058 if (!valid_usage) { 1059 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferData(usage)"); 1060 return; 1061 } 1062 1063 bufObj = get_buffer(ctx, "glBufferDataARB", target); 1064 if (!bufObj) 1065 return; 1066 1067 if (_mesa_bufferobj_mapped(bufObj)) { 1068 /* Unmap the existing buffer. We'll replace it now. Not an error. */ 1069 ctx->Driver.UnmapBuffer(ctx, bufObj); 1070 bufObj->AccessFlags = default_access_mode(ctx); 1071 ASSERT(bufObj->Pointer == NULL); 1072 } 1073 1074 FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT); 1075 1076 bufObj->Written = GL_TRUE; 1077 1078 #ifdef VBO_DEBUG 1079 printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n", 1080 bufObj->Name, size, data, usage); 1081 #endif 1082 1083 #ifdef BOUNDS_CHECK 1084 size += 100; 1085 #endif 1086 1087 ASSERT(ctx->Driver.BufferData); 1088 if (!ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj )) { 1089 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferDataARB()"); 1090 } 1091 } 1092 1093 1094 void GLAPIENTRY 1095 _mesa_BufferSubDataARB(GLenum target, GLintptrARB offset, 1096 GLsizeiptrARB size, const GLvoid * data) 1097 { 1098 GET_CURRENT_CONTEXT(ctx); 1099 struct gl_buffer_object *bufObj; 1100 ASSERT_OUTSIDE_BEGIN_END(ctx); 1101 1102 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, 1103 "glBufferSubDataARB" ); 1104 if (!bufObj) { 1105 /* error already recorded */ 1106 return; 1107 } 1108 1109 if (size == 0) 1110 return; 1111 1112 bufObj->Written = GL_TRUE; 1113 1114 ASSERT(ctx->Driver.BufferSubData); 1115 ctx->Driver.BufferSubData( ctx, offset, size, data, bufObj ); 1116 } 1117 1118 1119 void GLAPIENTRY 1120 _mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset, 1121 GLsizeiptrARB size, void * data) 1122 { 1123 GET_CURRENT_CONTEXT(ctx); 1124 struct gl_buffer_object *bufObj; 1125 ASSERT_OUTSIDE_BEGIN_END(ctx); 1126 1127 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, 1128 "glGetBufferSubDataARB" ); 1129 if (!bufObj) { 1130 /* error already recorded */ 1131 return; 1132 } 1133 1134 ASSERT(ctx->Driver.GetBufferSubData); 1135 ctx->Driver.GetBufferSubData( ctx, offset, size, data, bufObj ); 1136 } 1137 1138 1139 void * GLAPIENTRY 1140 _mesa_MapBufferARB(GLenum target, GLenum access) 1141 { 1142 GET_CURRENT_CONTEXT(ctx); 1143 struct gl_buffer_object * bufObj; 1144 GLbitfield accessFlags; 1145 void *map; 1146 bool valid_access; 1147 1148 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); 1149 1150 switch (access) { 1151 case GL_READ_ONLY_ARB: 1152 accessFlags = GL_MAP_READ_BIT; 1153 valid_access = _mesa_is_desktop_gl(ctx); 1154 break; 1155 case GL_WRITE_ONLY_ARB: 1156 accessFlags = GL_MAP_WRITE_BIT; 1157 valid_access = true; 1158 break; 1159 case GL_READ_WRITE_ARB: 1160 accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; 1161 valid_access = _mesa_is_desktop_gl(ctx); 1162 break; 1163 default: 1164 valid_access = false; 1165 break; 1166 } 1167 1168 if (!valid_access) { 1169 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)"); 1170 return NULL; 1171 } 1172 1173 bufObj = get_buffer(ctx, "glMapBufferARB", target); 1174 if (!bufObj) 1175 return NULL; 1176 1177 if (_mesa_bufferobj_mapped(bufObj)) { 1178 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)"); 1179 return NULL; 1180 } 1181 1182 if (!bufObj->Size) { 1183 _mesa_error(ctx, GL_OUT_OF_MEMORY, 1184 "glMapBuffer(buffer size = 0)"); 1185 return NULL; 1186 } 1187 1188 ASSERT(ctx->Driver.MapBufferRange); 1189 map = ctx->Driver.MapBufferRange(ctx, 0, bufObj->Size, accessFlags, bufObj); 1190 if (!map) { 1191 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); 1192 return NULL; 1193 } 1194 else { 1195 /* The driver callback should have set these fields. 1196 * This is important because other modules (like VBO) might call 1197 * the driver function directly. 1198 */ 1199 ASSERT(bufObj->Pointer == map); 1200 ASSERT(bufObj->Length == bufObj->Size); 1201 ASSERT(bufObj->Offset == 0); 1202 bufObj->AccessFlags = accessFlags; 1203 } 1204 1205 if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB) 1206 bufObj->Written = GL_TRUE; 1207 1208 #ifdef VBO_DEBUG 1209 printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n", 1210 bufObj->Name, bufObj->Size, access); 1211 if (access == GL_WRITE_ONLY_ARB) { 1212 GLuint i; 1213 GLubyte *b = (GLubyte *) bufObj->Pointer; 1214 for (i = 0; i < bufObj->Size; i++) 1215 b[i] = i & 0xff; 1216 } 1217 #endif 1218 1219 #ifdef BOUNDS_CHECK 1220 { 1221 GLubyte *buf = (GLubyte *) bufObj->Pointer; 1222 GLuint i; 1223 /* buffer is 100 bytes larger than requested, fill with magic value */ 1224 for (i = 0; i < 100; i++) { 1225 buf[bufObj->Size - i - 1] = 123; 1226 } 1227 } 1228 #endif 1229 1230 return bufObj->Pointer; 1231 } 1232 1233 1234 GLboolean GLAPIENTRY 1235 _mesa_UnmapBufferARB(GLenum target) 1236 { 1237 GET_CURRENT_CONTEXT(ctx); 1238 struct gl_buffer_object *bufObj; 1239 GLboolean status = GL_TRUE; 1240 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 1241 1242 bufObj = get_buffer(ctx, "glUnmapBufferARB", target); 1243 if (!bufObj) 1244 return GL_FALSE; 1245 1246 if (!_mesa_bufferobj_mapped(bufObj)) { 1247 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB"); 1248 return GL_FALSE; 1249 } 1250 1251 #ifdef BOUNDS_CHECK 1252 if (bufObj->Access != GL_READ_ONLY_ARB) { 1253 GLubyte *buf = (GLubyte *) bufObj->Pointer; 1254 GLuint i; 1255 /* check that last 100 bytes are still = magic value */ 1256 for (i = 0; i < 100; i++) { 1257 GLuint pos = bufObj->Size - i - 1; 1258 if (buf[pos] != 123) { 1259 _mesa_warning(ctx, "Out of bounds buffer object write detected" 1260 " at position %d (value = %u)\n", 1261 pos, buf[pos]); 1262 } 1263 } 1264 } 1265 #endif 1266 1267 #ifdef VBO_DEBUG 1268 if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) { 1269 GLuint i, unchanged = 0; 1270 GLubyte *b = (GLubyte *) bufObj->Pointer; 1271 GLint pos = -1; 1272 /* check which bytes changed */ 1273 for (i = 0; i < bufObj->Size - 1; i++) { 1274 if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) { 1275 unchanged++; 1276 if (pos == -1) 1277 pos = i; 1278 } 1279 } 1280 if (unchanged) { 1281 printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n", 1282 bufObj->Name, unchanged, bufObj->Size, pos); 1283 } 1284 } 1285 #endif 1286 1287 status = ctx->Driver.UnmapBuffer( ctx, bufObj ); 1288 bufObj->AccessFlags = default_access_mode(ctx); 1289 ASSERT(bufObj->Pointer == NULL); 1290 ASSERT(bufObj->Offset == 0); 1291 ASSERT(bufObj->Length == 0); 1292 1293 return status; 1294 } 1295 1296 1297 void GLAPIENTRY 1298 _mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params) 1299 { 1300 GET_CURRENT_CONTEXT(ctx); 1301 struct gl_buffer_object *bufObj; 1302 ASSERT_OUTSIDE_BEGIN_END(ctx); 1303 1304 bufObj = get_buffer(ctx, "glGetBufferParameterivARB", target); 1305 if (!bufObj) 1306 return; 1307 1308 switch (pname) { 1309 case GL_BUFFER_SIZE_ARB: 1310 *params = (GLint) bufObj->Size; 1311 return; 1312 case GL_BUFFER_USAGE_ARB: 1313 *params = bufObj->Usage; 1314 return; 1315 case GL_BUFFER_ACCESS_ARB: 1316 *params = simplified_access_mode(bufObj->AccessFlags); 1317 return; 1318 case GL_BUFFER_MAPPED_ARB: 1319 *params = _mesa_bufferobj_mapped(bufObj); 1320 return; 1321 case GL_BUFFER_ACCESS_FLAGS: 1322 if ((!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_map_buffer_range) 1323 && !_mesa_is_gles3(ctx)) 1324 goto invalid_pname; 1325 *params = bufObj->AccessFlags; 1326 return; 1327 case GL_BUFFER_MAP_OFFSET: 1328 if ((!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_map_buffer_range) 1329 && !_mesa_is_gles3(ctx)) 1330 goto invalid_pname; 1331 *params = (GLint) bufObj->Offset; 1332 return; 1333 case GL_BUFFER_MAP_LENGTH: 1334 if ((!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_map_buffer_range) 1335 && !_mesa_is_gles3(ctx)) 1336 goto invalid_pname; 1337 *params = (GLint) bufObj->Length; 1338 return; 1339 default: 1340 ; /* fall-through */ 1341 } 1342 1343 invalid_pname: 1344 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname=%s)", 1345 _mesa_lookup_enum_by_nr(pname)); 1346 } 1347 1348 1349 /** 1350 * New in GL 3.2 1351 * This is pretty much a duplicate of GetBufferParameteriv() but the 1352 * GL_BUFFER_SIZE_ARB attribute will be 64-bits on a 64-bit system. 1353 */ 1354 void GLAPIENTRY 1355 _mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params) 1356 { 1357 GET_CURRENT_CONTEXT(ctx); 1358 struct gl_buffer_object *bufObj; 1359 ASSERT_OUTSIDE_BEGIN_END(ctx); 1360 1361 bufObj = get_buffer(ctx, "glGetBufferParameteri64v", target); 1362 if (!bufObj) 1363 return; 1364 1365 switch (pname) { 1366 case GL_BUFFER_SIZE_ARB: 1367 *params = bufObj->Size; 1368 return; 1369 case GL_BUFFER_USAGE_ARB: 1370 *params = bufObj->Usage; 1371 return; 1372 case GL_BUFFER_ACCESS_ARB: 1373 *params = simplified_access_mode(bufObj->AccessFlags); 1374 return; 1375 case GL_BUFFER_ACCESS_FLAGS: 1376 if (!ctx->Extensions.ARB_map_buffer_range) 1377 goto invalid_pname; 1378 *params = bufObj->AccessFlags; 1379 return; 1380 case GL_BUFFER_MAPPED_ARB: 1381 *params = _mesa_bufferobj_mapped(bufObj); 1382 return; 1383 case GL_BUFFER_MAP_OFFSET: 1384 if (!ctx->Extensions.ARB_map_buffer_range) 1385 goto invalid_pname; 1386 *params = bufObj->Offset; 1387 return; 1388 case GL_BUFFER_MAP_LENGTH: 1389 if (!ctx->Extensions.ARB_map_buffer_range) 1390 goto invalid_pname; 1391 *params = bufObj->Length; 1392 return; 1393 default: 1394 ; /* fall-through */ 1395 } 1396 1397 invalid_pname: 1398 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(pname=%s)", 1399 _mesa_lookup_enum_by_nr(pname)); 1400 } 1401 1402 1403 void GLAPIENTRY 1404 _mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params) 1405 { 1406 GET_CURRENT_CONTEXT(ctx); 1407 struct gl_buffer_object * bufObj; 1408 ASSERT_OUTSIDE_BEGIN_END(ctx); 1409 1410 if (pname != GL_BUFFER_MAP_POINTER_ARB) { 1411 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)"); 1412 return; 1413 } 1414 1415 bufObj = get_buffer(ctx, "glGetBufferPointervARB", target); 1416 if (!bufObj) 1417 return; 1418 1419 *params = bufObj->Pointer; 1420 } 1421 1422 1423 void GLAPIENTRY 1424 _mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, 1425 GLintptr readOffset, GLintptr writeOffset, 1426 GLsizeiptr size) 1427 { 1428 GET_CURRENT_CONTEXT(ctx); 1429 struct gl_buffer_object *src, *dst; 1430 ASSERT_OUTSIDE_BEGIN_END(ctx); 1431 1432 src = get_buffer(ctx, "glCopyBufferSubData", readTarget); 1433 if (!src) 1434 return; 1435 1436 dst = get_buffer(ctx, "glCopyBufferSubData", writeTarget); 1437 if (!dst) 1438 return; 1439 1440 if (_mesa_bufferobj_mapped(src)) { 1441 _mesa_error(ctx, GL_INVALID_OPERATION, 1442 "glCopyBufferSubData(readBuffer is mapped)"); 1443 return; 1444 } 1445 1446 if (_mesa_bufferobj_mapped(dst)) { 1447 _mesa_error(ctx, GL_INVALID_OPERATION, 1448 "glCopyBufferSubData(writeBuffer is mapped)"); 1449 return; 1450 } 1451 1452 if (readOffset < 0) { 1453 _mesa_error(ctx, GL_INVALID_VALUE, 1454 "glCopyBufferSubData(readOffset = %d)", (int) readOffset); 1455 return; 1456 } 1457 1458 if (writeOffset < 0) { 1459 _mesa_error(ctx, GL_INVALID_VALUE, 1460 "glCopyBufferSubData(writeOffset = %d)", (int) writeOffset); 1461 return; 1462 } 1463 1464 if (size < 0) { 1465 _mesa_error(ctx, GL_INVALID_VALUE, 1466 "glCopyBufferSubData(writeOffset = %d)", (int) size); 1467 return; 1468 } 1469 1470 if (readOffset + size > src->Size) { 1471 _mesa_error(ctx, GL_INVALID_VALUE, 1472 "glCopyBufferSubData(readOffset + size = %d)", 1473 (int) (readOffset + size)); 1474 return; 1475 } 1476 1477 if (writeOffset + size > dst->Size) { 1478 _mesa_error(ctx, GL_INVALID_VALUE, 1479 "glCopyBufferSubData(writeOffset + size = %d)", 1480 (int) (writeOffset + size)); 1481 return; 1482 } 1483 1484 if (src == dst) { 1485 if (readOffset + size <= writeOffset) { 1486 /* OK */ 1487 } 1488 else if (writeOffset + size <= readOffset) { 1489 /* OK */ 1490 } 1491 else { 1492 /* overlapping src/dst is illegal */ 1493 _mesa_error(ctx, GL_INVALID_VALUE, 1494 "glCopyBufferSubData(overlapping src/dst)"); 1495 return; 1496 } 1497 } 1498 1499 ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size); 1500 } 1501 1502 1503 /** 1504 * See GL_ARB_map_buffer_range spec 1505 */ 1506 void * GLAPIENTRY 1507 _mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, 1508 GLbitfield access) 1509 { 1510 GET_CURRENT_CONTEXT(ctx); 1511 struct gl_buffer_object *bufObj; 1512 void *map; 1513 1514 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); 1515 1516 if (!ctx->Extensions.ARB_map_buffer_range) { 1517 _mesa_error(ctx, GL_INVALID_OPERATION, 1518 "glMapBufferRange(extension not supported)"); 1519 return NULL; 1520 } 1521 1522 if (offset < 0) { 1523 _mesa_error(ctx, GL_INVALID_VALUE, 1524 "glMapBufferRange(offset = %ld)", (long)offset); 1525 return NULL; 1526 } 1527 1528 if (length < 0) { 1529 _mesa_error(ctx, GL_INVALID_VALUE, 1530 "glMapBufferRange(length = %ld)", (long)length); 1531 return NULL; 1532 } 1533 1534 if (access & ~(GL_MAP_READ_BIT | 1535 GL_MAP_WRITE_BIT | 1536 GL_MAP_INVALIDATE_RANGE_BIT | 1537 GL_MAP_INVALIDATE_BUFFER_BIT | 1538 GL_MAP_FLUSH_EXPLICIT_BIT | 1539 GL_MAP_UNSYNCHRONIZED_BIT)) { 1540 /* generate an error if any undefind bit is set */ 1541 _mesa_error(ctx, GL_INVALID_VALUE, "glMapBufferRange(access)"); 1542 return NULL; 1543 } 1544 1545 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) { 1546 _mesa_error(ctx, GL_INVALID_OPERATION, 1547 "glMapBufferRange(access indicates neither read or write)"); 1548 return NULL; 1549 } 1550 1551 if ((access & GL_MAP_READ_BIT) && 1552 (access & (GL_MAP_INVALIDATE_RANGE_BIT | 1553 GL_MAP_INVALIDATE_BUFFER_BIT | 1554 GL_MAP_UNSYNCHRONIZED_BIT))) { 1555 _mesa_error(ctx, GL_INVALID_OPERATION, 1556 "glMapBufferRange(invalid access flags)"); 1557 return NULL; 1558 } 1559 1560 if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) && 1561 ((access & GL_MAP_WRITE_BIT) == 0)) { 1562 _mesa_error(ctx, GL_INVALID_OPERATION, 1563 "glMapBufferRange(invalid access flags)"); 1564 return NULL; 1565 } 1566 1567 bufObj = get_buffer(ctx, "glMapBufferRange", target); 1568 if (!bufObj) 1569 return NULL; 1570 1571 if (offset + length > bufObj->Size) { 1572 _mesa_error(ctx, GL_INVALID_VALUE, 1573 "glMapBufferRange(offset + length > size)"); 1574 return NULL; 1575 } 1576 1577 if (_mesa_bufferobj_mapped(bufObj)) { 1578 _mesa_error(ctx, GL_INVALID_OPERATION, 1579 "glMapBufferRange(buffer already mapped)"); 1580 return NULL; 1581 } 1582 1583 if (!bufObj->Size) { 1584 _mesa_error(ctx, GL_OUT_OF_MEMORY, 1585 "glMapBufferRange(buffer size = 0)"); 1586 return NULL; 1587 } 1588 1589 /* Mapping zero bytes should return a non-null pointer. */ 1590 if (!length) { 1591 static long dummy = 0; 1592 bufObj->Pointer = &dummy; 1593 bufObj->Length = length; 1594 bufObj->Offset = offset; 1595 bufObj->AccessFlags = access; 1596 return bufObj->Pointer; 1597 } 1598 1599 ASSERT(ctx->Driver.MapBufferRange); 1600 map = ctx->Driver.MapBufferRange(ctx, offset, length, access, bufObj); 1601 if (!map) { 1602 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); 1603 } 1604 else { 1605 /* The driver callback should have set all these fields. 1606 * This is important because other modules (like VBO) might call 1607 * the driver function directly. 1608 */ 1609 ASSERT(bufObj->Pointer == map); 1610 ASSERT(bufObj->Length == length); 1611 ASSERT(bufObj->Offset == offset); 1612 ASSERT(bufObj->AccessFlags == access); 1613 } 1614 1615 return map; 1616 } 1617 1618 1619 /** 1620 * See GL_ARB_map_buffer_range spec 1621 */ 1622 void GLAPIENTRY 1623 _mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) 1624 { 1625 GET_CURRENT_CONTEXT(ctx); 1626 struct gl_buffer_object *bufObj; 1627 ASSERT_OUTSIDE_BEGIN_END(ctx); 1628 1629 if (!ctx->Extensions.ARB_map_buffer_range) { 1630 _mesa_error(ctx, GL_INVALID_OPERATION, 1631 "glFlushMappedBufferRange(extension not supported)"); 1632 return; 1633 } 1634 1635 if (offset < 0) { 1636 _mesa_error(ctx, GL_INVALID_VALUE, 1637 "glFlushMappedBufferRange(offset = %ld)", (long)offset); 1638 return; 1639 } 1640 1641 if (length < 0) { 1642 _mesa_error(ctx, GL_INVALID_VALUE, 1643 "glFlushMappedBufferRange(length = %ld)", (long)length); 1644 return; 1645 } 1646 1647 bufObj = get_buffer(ctx, "glFlushMappedBufferRange", target); 1648 if (!bufObj) 1649 return; 1650 1651 if (!_mesa_bufferobj_mapped(bufObj)) { 1652 /* buffer is not mapped */ 1653 _mesa_error(ctx, GL_INVALID_OPERATION, 1654 "glFlushMappedBufferRange(buffer is not mapped)"); 1655 return; 1656 } 1657 1658 if ((bufObj->AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) { 1659 _mesa_error(ctx, GL_INVALID_OPERATION, 1660 "glFlushMappedBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)"); 1661 return; 1662 } 1663 1664 if (offset + length > bufObj->Length) { 1665 _mesa_error(ctx, GL_INVALID_VALUE, 1666 "glFlushMappedBufferRange(offset %ld + length %ld > mapped length %ld)", 1667 (long)offset, (long)length, (long)bufObj->Length); 1668 return; 1669 } 1670 1671 ASSERT(bufObj->AccessFlags & GL_MAP_WRITE_BIT); 1672 1673 if (ctx->Driver.FlushMappedBufferRange) 1674 ctx->Driver.FlushMappedBufferRange(ctx, offset, length, bufObj); 1675 } 1676 1677 1678 #if FEATURE_APPLE_object_purgeable 1679 static GLenum 1680 buffer_object_purgeable(struct gl_context *ctx, GLuint name, GLenum option) 1681 { 1682 struct gl_buffer_object *bufObj; 1683 GLenum retval; 1684 1685 bufObj = _mesa_lookup_bufferobj(ctx, name); 1686 if (!bufObj) { 1687 _mesa_error(ctx, GL_INVALID_VALUE, 1688 "glObjectPurgeable(name = 0x%x)", name); 1689 return 0; 1690 } 1691 if (!_mesa_is_bufferobj(bufObj)) { 1692 _mesa_error(ctx, GL_INVALID_OPERATION, "glObjectPurgeable(buffer 0)" ); 1693 return 0; 1694 } 1695 1696 if (bufObj->Purgeable) { 1697 _mesa_error(ctx, GL_INVALID_OPERATION, 1698 "glObjectPurgeable(name = 0x%x) is already purgeable", name); 1699 return GL_VOLATILE_APPLE; 1700 } 1701 1702 bufObj->Purgeable = GL_TRUE; 1703 1704 retval = GL_VOLATILE_APPLE; 1705 if (ctx->Driver.BufferObjectPurgeable) 1706 retval = ctx->Driver.BufferObjectPurgeable(ctx, bufObj, option); 1707 1708 return retval; 1709 } 1710 1711 1712 static GLenum 1713 renderbuffer_purgeable(struct gl_context *ctx, GLuint name, GLenum option) 1714 { 1715 struct gl_renderbuffer *bufObj; 1716 GLenum retval; 1717 1718 bufObj = _mesa_lookup_renderbuffer(ctx, name); 1719 if (!bufObj) { 1720 _mesa_error(ctx, GL_INVALID_VALUE, 1721 "glObjectUnpurgeable(name = 0x%x)", name); 1722 return 0; 1723 } 1724 1725 if (bufObj->Purgeable) { 1726 _mesa_error(ctx, GL_INVALID_OPERATION, 1727 "glObjectPurgeable(name = 0x%x) is already purgeable", name); 1728 return GL_VOLATILE_APPLE; 1729 } 1730 1731 bufObj->Purgeable = GL_TRUE; 1732 1733 retval = GL_VOLATILE_APPLE; 1734 if (ctx->Driver.RenderObjectPurgeable) 1735 retval = ctx->Driver.RenderObjectPurgeable(ctx, bufObj, option); 1736 1737 return retval; 1738 } 1739 1740 1741 static GLenum 1742 texture_object_purgeable(struct gl_context *ctx, GLuint name, GLenum option) 1743 { 1744 struct gl_texture_object *bufObj; 1745 GLenum retval; 1746 1747 bufObj = _mesa_lookup_texture(ctx, name); 1748 if (!bufObj) { 1749 _mesa_error(ctx, GL_INVALID_VALUE, 1750 "glObjectPurgeable(name = 0x%x)", name); 1751 return 0; 1752 } 1753 1754 if (bufObj->Purgeable) { 1755 _mesa_error(ctx, GL_INVALID_OPERATION, 1756 "glObjectPurgeable(name = 0x%x) is already purgeable", name); 1757 return GL_VOLATILE_APPLE; 1758 } 1759 1760 bufObj->Purgeable = GL_TRUE; 1761 1762 retval = GL_VOLATILE_APPLE; 1763 if (ctx->Driver.TextureObjectPurgeable) 1764 retval = ctx->Driver.TextureObjectPurgeable(ctx, bufObj, option); 1765 1766 return retval; 1767 } 1768 1769 1770 GLenum GLAPIENTRY 1771 _mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option) 1772 { 1773 GLenum retval; 1774 1775 GET_CURRENT_CONTEXT(ctx); 1776 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 1777 1778 if (name == 0) { 1779 _mesa_error(ctx, GL_INVALID_VALUE, 1780 "glObjectPurgeable(name = 0x%x)", name); 1781 return 0; 1782 } 1783 1784 switch (option) { 1785 case GL_VOLATILE_APPLE: 1786 case GL_RELEASED_APPLE: 1787 /* legal */ 1788 break; 1789 default: 1790 _mesa_error(ctx, GL_INVALID_ENUM, 1791 "glObjectPurgeable(name = 0x%x) invalid option: %d", 1792 name, option); 1793 return 0; 1794 } 1795 1796 switch (objectType) { 1797 case GL_TEXTURE: 1798 retval = texture_object_purgeable(ctx, name, option); 1799 break; 1800 case GL_RENDERBUFFER_EXT: 1801 retval = renderbuffer_purgeable(ctx, name, option); 1802 break; 1803 case GL_BUFFER_OBJECT_APPLE: 1804 retval = buffer_object_purgeable(ctx, name, option); 1805 break; 1806 default: 1807 _mesa_error(ctx, GL_INVALID_ENUM, 1808 "glObjectPurgeable(name = 0x%x) invalid type: %d", 1809 name, objectType); 1810 return 0; 1811 } 1812 1813 /* In strict conformance to the spec, we must only return VOLATILE when 1814 * when passed the VOLATILE option. Madness. 1815 * 1816 * XXX First fix the spec, then fix me. 1817 */ 1818 return option == GL_VOLATILE_APPLE ? GL_VOLATILE_APPLE : retval; 1819 } 1820 1821 1822 static GLenum 1823 buffer_object_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option) 1824 { 1825 struct gl_buffer_object *bufObj; 1826 GLenum retval; 1827 1828 bufObj = _mesa_lookup_bufferobj(ctx, name); 1829 if (!bufObj) { 1830 _mesa_error(ctx, GL_INVALID_VALUE, 1831 "glObjectUnpurgeable(name = 0x%x)", name); 1832 return 0; 1833 } 1834 1835 if (! bufObj->Purgeable) { 1836 _mesa_error(ctx, GL_INVALID_OPERATION, 1837 "glObjectUnpurgeable(name = 0x%x) object is " 1838 " already \"unpurged\"", name); 1839 return 0; 1840 } 1841 1842 bufObj->Purgeable = GL_FALSE; 1843 1844 retval = option; 1845 if (ctx->Driver.BufferObjectUnpurgeable) 1846 retval = ctx->Driver.BufferObjectUnpurgeable(ctx, bufObj, option); 1847 1848 return retval; 1849 } 1850 1851 1852 static GLenum 1853 renderbuffer_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option) 1854 { 1855 struct gl_renderbuffer *bufObj; 1856 GLenum retval; 1857 1858 bufObj = _mesa_lookup_renderbuffer(ctx, name); 1859 if (!bufObj) { 1860 _mesa_error(ctx, GL_INVALID_VALUE, 1861 "glObjectUnpurgeable(name = 0x%x)", name); 1862 return 0; 1863 } 1864 1865 if (! bufObj->Purgeable) { 1866 _mesa_error(ctx, GL_INVALID_OPERATION, 1867 "glObjectUnpurgeable(name = 0x%x) object is " 1868 " already \"unpurged\"", name); 1869 return 0; 1870 } 1871 1872 bufObj->Purgeable = GL_FALSE; 1873 1874 retval = option; 1875 if (ctx->Driver.RenderObjectUnpurgeable) 1876 retval = ctx->Driver.RenderObjectUnpurgeable(ctx, bufObj, option); 1877 1878 return retval; 1879 } 1880 1881 1882 static GLenum 1883 texture_object_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option) 1884 { 1885 struct gl_texture_object *bufObj; 1886 GLenum retval; 1887 1888 bufObj = _mesa_lookup_texture(ctx, name); 1889 if (!bufObj) { 1890 _mesa_error(ctx, GL_INVALID_VALUE, 1891 "glObjectUnpurgeable(name = 0x%x)", name); 1892 return 0; 1893 } 1894 1895 if (! bufObj->Purgeable) { 1896 _mesa_error(ctx, GL_INVALID_OPERATION, 1897 "glObjectUnpurgeable(name = 0x%x) object is" 1898 " already \"unpurged\"", name); 1899 return 0; 1900 } 1901 1902 bufObj->Purgeable = GL_FALSE; 1903 1904 retval = option; 1905 if (ctx->Driver.TextureObjectUnpurgeable) 1906 retval = ctx->Driver.TextureObjectUnpurgeable(ctx, bufObj, option); 1907 1908 return retval; 1909 } 1910 1911 1912 GLenum GLAPIENTRY 1913 _mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option) 1914 { 1915 GET_CURRENT_CONTEXT(ctx); 1916 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 1917 1918 if (name == 0) { 1919 _mesa_error(ctx, GL_INVALID_VALUE, 1920 "glObjectUnpurgeable(name = 0x%x)", name); 1921 return 0; 1922 } 1923 1924 switch (option) { 1925 case GL_RETAINED_APPLE: 1926 case GL_UNDEFINED_APPLE: 1927 /* legal */ 1928 break; 1929 default: 1930 _mesa_error(ctx, GL_INVALID_ENUM, 1931 "glObjectUnpurgeable(name = 0x%x) invalid option: %d", 1932 name, option); 1933 return 0; 1934 } 1935 1936 switch (objectType) { 1937 case GL_BUFFER_OBJECT_APPLE: 1938 return buffer_object_unpurgeable(ctx, name, option); 1939 case GL_TEXTURE: 1940 return texture_object_unpurgeable(ctx, name, option); 1941 case GL_RENDERBUFFER_EXT: 1942 return renderbuffer_unpurgeable(ctx, name, option); 1943 default: 1944 _mesa_error(ctx, GL_INVALID_ENUM, 1945 "glObjectUnpurgeable(name = 0x%x) invalid type: %d", 1946 name, objectType); 1947 return 0; 1948 } 1949 } 1950 1951 1952 static void 1953 get_buffer_object_parameteriv(struct gl_context *ctx, GLuint name, 1954 GLenum pname, GLint *params) 1955 { 1956 struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, name); 1957 if (!bufObj) { 1958 _mesa_error(ctx, GL_INVALID_VALUE, 1959 "glGetObjectParameteriv(name = 0x%x) invalid object", name); 1960 return; 1961 } 1962 1963 switch (pname) { 1964 case GL_PURGEABLE_APPLE: 1965 *params = bufObj->Purgeable; 1966 break; 1967 default: 1968 _mesa_error(ctx, GL_INVALID_ENUM, 1969 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", 1970 name, pname); 1971 break; 1972 } 1973 } 1974 1975 1976 static void 1977 get_renderbuffer_parameteriv(struct gl_context *ctx, GLuint name, 1978 GLenum pname, GLint *params) 1979 { 1980 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name); 1981 if (!rb) { 1982 _mesa_error(ctx, GL_INVALID_VALUE, 1983 "glObjectUnpurgeable(name = 0x%x)", name); 1984 return; 1985 } 1986 1987 switch (pname) { 1988 case GL_PURGEABLE_APPLE: 1989 *params = rb->Purgeable; 1990 break; 1991 default: 1992 _mesa_error(ctx, GL_INVALID_ENUM, 1993 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", 1994 name, pname); 1995 break; 1996 } 1997 } 1998 1999 2000 static void 2001 get_texture_object_parameteriv(struct gl_context *ctx, GLuint name, 2002 GLenum pname, GLint *params) 2003 { 2004 struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name); 2005 if (!texObj) { 2006 _mesa_error(ctx, GL_INVALID_VALUE, 2007 "glObjectUnpurgeable(name = 0x%x)", name); 2008 return; 2009 } 2010 2011 switch (pname) { 2012 case GL_PURGEABLE_APPLE: 2013 *params = texObj->Purgeable; 2014 break; 2015 default: 2016 _mesa_error(ctx, GL_INVALID_ENUM, 2017 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", 2018 name, pname); 2019 break; 2020 } 2021 } 2022 2023 2024 void GLAPIENTRY 2025 _mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname, 2026 GLint *params) 2027 { 2028 GET_CURRENT_CONTEXT(ctx); 2029 2030 if (name == 0) { 2031 _mesa_error(ctx, GL_INVALID_VALUE, 2032 "glGetObjectParameteriv(name = 0x%x)", name); 2033 return; 2034 } 2035 2036 switch (objectType) { 2037 case GL_TEXTURE: 2038 get_texture_object_parameteriv(ctx, name, pname, params); 2039 break; 2040 case GL_BUFFER_OBJECT_APPLE: 2041 get_buffer_object_parameteriv(ctx, name, pname, params); 2042 break; 2043 case GL_RENDERBUFFER_EXT: 2044 get_renderbuffer_parameteriv(ctx, name, pname, params); 2045 break; 2046 default: 2047 _mesa_error(ctx, GL_INVALID_ENUM, 2048 "glGetObjectParameteriv(name = 0x%x) invalid type: %d", 2049 name, objectType); 2050 } 2051 } 2052 2053 #endif /* FEATURE_APPLE_object_purgeable */ 2054 2055 static void 2056 set_ubo_binding(struct gl_context *ctx, 2057 int index, 2058 struct gl_buffer_object *bufObj, 2059 GLintptr offset, 2060 GLsizeiptr size, 2061 GLboolean autoSize) 2062 { 2063 struct gl_uniform_buffer_binding *binding; 2064 2065 binding = &ctx->UniformBufferBindings[index]; 2066 if (binding->BufferObject == bufObj && 2067 binding->Offset == offset && 2068 binding->Size == size && 2069 binding->AutomaticSize == autoSize) { 2070 return; 2071 } 2072 2073 FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT); 2074 2075 _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj); 2076 binding->Offset = offset; 2077 binding->Size = size; 2078 binding->AutomaticSize = autoSize; 2079 } 2080 2081 /** 2082 * Bind a region of a buffer object to a uniform block binding point. 2083 * \param index the uniform buffer binding point index 2084 * \param bufObj the buffer object 2085 * \param offset offset to the start of buffer object region 2086 * \param size size of the buffer object region 2087 */ 2088 static void 2089 bind_buffer_range_uniform_buffer(struct gl_context *ctx, 2090 GLuint index, 2091 struct gl_buffer_object *bufObj, 2092 GLintptr offset, 2093 GLsizeiptr size) 2094 { 2095 if (index >= ctx->Const.MaxUniformBufferBindings) { 2096 _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index); 2097 return; 2098 } 2099 2100 if (offset & (ctx->Const.UniformBufferOffsetAlignment - 1)) { 2101 _mesa_error(ctx, GL_INVALID_VALUE, 2102 "glBindBufferRange(offset misalgned %d/%d)", (int) offset, 2103 ctx->Const.UniformBufferOffsetAlignment); 2104 return; 2105 } 2106 2107 if (bufObj == ctx->Shared->NullBufferObj) { 2108 offset = -1; 2109 size = -1; 2110 } 2111 2112 _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj); 2113 set_ubo_binding(ctx, index, bufObj, offset, size, GL_FALSE); 2114 } 2115 2116 2117 /** 2118 * Bind a buffer object to a uniform block binding point. 2119 * As above, but offset = 0. 2120 */ 2121 static void 2122 bind_buffer_base_uniform_buffer(struct gl_context *ctx, 2123 GLuint index, 2124 struct gl_buffer_object *bufObj) 2125 { 2126 if (index >= ctx->Const.MaxUniformBufferBindings) { 2127 _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index); 2128 return; 2129 } 2130 2131 _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj); 2132 if (bufObj == ctx->Shared->NullBufferObj) 2133 set_ubo_binding(ctx, index, bufObj, -1, -1, GL_TRUE); 2134 else 2135 set_ubo_binding(ctx, index, bufObj, 0, 0, GL_TRUE); 2136 } 2137 2138 void GLAPIENTRY 2139 _mesa_BindBufferRange(GLenum target, GLuint index, 2140 GLuint buffer, GLintptr offset, GLsizeiptr size) 2141 { 2142 GET_CURRENT_CONTEXT(ctx); 2143 struct gl_buffer_object *bufObj; 2144 2145 if (buffer == 0) { 2146 bufObj = ctx->Shared->NullBufferObj; 2147 } else { 2148 bufObj = _mesa_lookup_bufferobj(ctx, buffer); 2149 } 2150 if (!handle_bind_buffer_gen(ctx, target, buffer, &bufObj)) 2151 return; 2152 2153 if (!bufObj) { 2154 _mesa_error(ctx, GL_INVALID_OPERATION, 2155 "glBindBufferRange(invalid buffer=%u)", buffer); 2156 return; 2157 } 2158 2159 if (size <= 0) { 2160 _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(size=%d)", 2161 (int) size); 2162 return; 2163 } 2164 2165 if (offset + size > bufObj->Size) { 2166 _mesa_error(ctx, GL_INVALID_VALUE, 2167 "glBindBufferRange(offset + size %d > buffer size %d)", 2168 (int) (offset + size), (int) (bufObj->Size)); 2169 return; 2170 } 2171 2172 switch (target) { 2173 case GL_TRANSFORM_FEEDBACK_BUFFER: 2174 _mesa_bind_buffer_range_transform_feedback(ctx, index, bufObj, 2175 offset, size); 2176 return; 2177 case GL_UNIFORM_BUFFER: 2178 bind_buffer_range_uniform_buffer(ctx, index, bufObj, offset, size); 2179 return; 2180 default: 2181 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferRange(target)"); 2182 return; 2183 } 2184 } 2185 2186 void GLAPIENTRY 2187 _mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer) 2188 { 2189 GET_CURRENT_CONTEXT(ctx); 2190 struct gl_buffer_object *bufObj; 2191 2192 if (buffer == 0) { 2193 bufObj = ctx->Shared->NullBufferObj; 2194 } else { 2195 bufObj = _mesa_lookup_bufferobj(ctx, buffer); 2196 } 2197 if (!handle_bind_buffer_gen(ctx, target, buffer, &bufObj)) 2198 return; 2199 2200 if (!bufObj) { 2201 _mesa_error(ctx, GL_INVALID_OPERATION, 2202 "glBindBufferBase(invalid buffer=%u)", buffer); 2203 return; 2204 } 2205 2206 /* Note that there's some oddness in the GL 3.1-GL 3.3 specifications with 2207 * regards to BindBufferBase. It says (GL 3.1 core spec, page 63): 2208 * 2209 * "BindBufferBase is equivalent to calling BindBufferRange with offset 2210 * zero and size equal to the size of buffer." 2211 * 2212 * but it says for glGetIntegeri_v (GL 3.1 core spec, page 230): 2213 * 2214 * "If the parameter (starting offset or size) was not specified when the 2215 * buffer object was bound, zero is returned." 2216 * 2217 * What happens if the size of the buffer changes? Does the size of the 2218 * buffer at the moment glBindBufferBase was called still play a role, like 2219 * the first quote would imply, or is the size meaningless in the 2220 * glBindBufferBase case like the second quote would suggest? The GL 4.1 2221 * core spec page 45 says: 2222 * 2223 * "It is equivalent to calling BindBufferRange with offset zero, while 2224 * size is determined by the size of the bound buffer at the time the 2225 * binding is used." 2226 * 2227 * My interpretation is that the GL 4.1 spec was a clarification of the 2228 * behavior, not a change. In particular, this choice will only make 2229 * rendering work in cases where it would have had undefined results. 2230 */ 2231 2232 switch (target) { 2233 case GL_TRANSFORM_FEEDBACK_BUFFER: 2234 _mesa_bind_buffer_base_transform_feedback(ctx, index, bufObj); 2235 return; 2236 case GL_UNIFORM_BUFFER: 2237 bind_buffer_base_uniform_buffer(ctx, index, bufObj); 2238 return; 2239 default: 2240 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)"); 2241 return; 2242 } 2243 } 2244 2245 static void GLAPIENTRY 2246 _mesa_InvalidateBufferSubData(GLuint buffer, GLintptr offset, 2247 GLsizeiptr length) 2248 { 2249 GET_CURRENT_CONTEXT(ctx); 2250 struct gl_buffer_object *bufObj; 2251 const GLintptr end = offset + length; 2252 2253 bufObj = _mesa_lookup_bufferobj(ctx, buffer); 2254 if (!bufObj) { 2255 _mesa_error(ctx, GL_INVALID_VALUE, 2256 "glInvalidateBufferSubData(name = 0x%x) invalid object", 2257 buffer); 2258 return; 2259 } 2260 2261 /* The GL_ARB_invalidate_subdata spec says: 2262 * 2263 * "An INVALID_VALUE error is generated if <offset> or <length> is 2264 * negative, or if <offset> + <length> is greater than the value of 2265 * BUFFER_SIZE." 2266 */ 2267 if (end < 0 || end > bufObj->Size) { 2268 _mesa_error(ctx, GL_INVALID_VALUE, 2269 "glInvalidateBufferSubData(invalid offset or length)"); 2270 return; 2271 } 2272 2273 /* The GL_ARB_invalidate_subdata spec says: 2274 * 2275 * "An INVALID_OPERATION error is generated if the buffer is currently 2276 * mapped by MapBuffer, or if the invalidate range intersects the range 2277 * currently mapped by MapBufferRange." 2278 */ 2279 if (_mesa_bufferobj_mapped(bufObj)) { 2280 const GLintptr mapEnd = bufObj->Offset + bufObj->Length; 2281 2282 /* The regions do not overlap if and only if the end of the discard 2283 * region is before the mapped region or the start of the discard region 2284 * is after the mapped region. 2285 * 2286 * Note that 'end' and 'mapEnd' are the first byte *after* the discard 2287 * region and the mapped region, repsectively. It is okay for that byte 2288 * to be mapped (for 'end') or discarded (for 'mapEnd'). 2289 */ 2290 if (!(end <= bufObj->Offset || offset >= mapEnd)) { 2291 _mesa_error(ctx, GL_INVALID_OPERATION, 2292 "glInvalidateBufferSubData(intersection with mapped " 2293 "range)"); 2294 return; 2295 } 2296 } 2297 2298 /* We don't actually do anything for this yet. Just return after 2299 * validating the parameters and generating the required errors. 2300 */ 2301 return; 2302 } 2303 2304 static void GLAPIENTRY 2305 _mesa_InvalidateBufferData(GLuint buffer) 2306 { 2307 GET_CURRENT_CONTEXT(ctx); 2308 struct gl_buffer_object *bufObj; 2309 2310 bufObj = _mesa_lookup_bufferobj(ctx, buffer); 2311 if (!bufObj) { 2312 _mesa_error(ctx, GL_INVALID_VALUE, 2313 "glInvalidateBufferData(name = 0x%x) invalid object", 2314 buffer); 2315 return; 2316 } 2317 2318 /* The GL_ARB_invalidate_subdata spec says: 2319 * 2320 * "An INVALID_OPERATION error is generated if the buffer is currently 2321 * mapped by MapBuffer, or if the invalidate range intersects the range 2322 * currently mapped by MapBufferRange." 2323 */ 2324 if (_mesa_bufferobj_mapped(bufObj)) { 2325 _mesa_error(ctx, GL_INVALID_OPERATION, 2326 "glInvalidateBufferData(intersection with mapped " 2327 "range)"); 2328 return; 2329 } 2330 2331 /* We don't actually do anything for this yet. Just return after 2332 * validating the parameters and generating the required errors. 2333 */ 2334 return; 2335 } 2336 2337 void 2338 _mesa_init_bufferobj_dispatch(struct gl_context *ctx, struct _glapi_table *disp) 2339 { 2340 SET_BindBufferARB(disp, _mesa_BindBufferARB); 2341 SET_BufferDataARB(disp, _mesa_BufferDataARB); 2342 SET_BufferSubDataARB(disp, _mesa_BufferSubDataARB); 2343 SET_DeleteBuffersARB(disp, _mesa_DeleteBuffersARB); 2344 SET_GenBuffersARB(disp, _mesa_GenBuffersARB); 2345 SET_GetBufferParameterivARB(disp, _mesa_GetBufferParameterivARB); 2346 SET_GetBufferPointervARB(disp, _mesa_GetBufferPointervARB); 2347 if (ctx->API != API_OPENGLES2) { 2348 SET_GetBufferSubDataARB(disp, _mesa_GetBufferSubDataARB); 2349 } 2350 SET_IsBufferARB(disp, _mesa_IsBufferARB); 2351 SET_MapBufferARB(disp, _mesa_MapBufferARB); 2352 SET_UnmapBufferARB(disp, _mesa_UnmapBufferARB); 2353 2354 if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) { 2355 SET_BindBufferRangeEXT(disp, _mesa_BindBufferRange); 2356 SET_BindBufferBaseEXT(disp, _mesa_BindBufferBase); 2357 } 2358 2359 if (_mesa_is_desktop_gl(ctx)) { 2360 SET_InvalidateBufferData(disp, _mesa_InvalidateBufferData); 2361 SET_InvalidateBufferSubData(disp, _mesa_InvalidateBufferSubData); 2362 } 2363 } 2364