bufferobj.c revision bd4e5dd3553c5d7152af419f8b12ce228aba2dd2
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 */ 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 bool valid_usage; 1013 ASSERT_OUTSIDE_BEGIN_END(ctx); 1014 1015 if (MESA_VERBOSE & VERBOSE_API) 1016 _mesa_debug(ctx, "glBufferData(%s, %ld, %p, %s)\n", 1017 _mesa_lookup_enum_by_nr(target), 1018 (long int) size, data, 1019 _mesa_lookup_enum_by_nr(usage)); 1020 1021 if (size < 0) { 1022 _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)"); 1023 return; 1024 } 1025 1026 switch (usage) { 1027 case GL_STREAM_DRAW_ARB: 1028 valid_usage = (ctx->API != API_OPENGLES); 1029 break; 1030 1031 case GL_STATIC_DRAW_ARB: 1032 case GL_DYNAMIC_DRAW_ARB: 1033 valid_usage = true; 1034 break; 1035 1036 case GL_STREAM_READ_ARB: 1037 case GL_STREAM_COPY_ARB: 1038 case GL_STATIC_READ_ARB: 1039 case GL_STATIC_COPY_ARB: 1040 case GL_DYNAMIC_READ_ARB: 1041 case GL_DYNAMIC_COPY_ARB: 1042 valid_usage = _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx); 1043 break; 1044 1045 default: 1046 valid_usage = false; 1047 break; 1048 } 1049 1050 if (!valid_usage) { 1051 _mesa_error(ctx, GL_INVALID_ENUM, "glBufferData(usage)"); 1052 return; 1053 } 1054 1055 bufObj = get_buffer(ctx, "glBufferDataARB", target); 1056 if (!bufObj) 1057 return; 1058 1059 if (_mesa_bufferobj_mapped(bufObj)) { 1060 /* Unmap the existing buffer. We'll replace it now. Not an error. */ 1061 ctx->Driver.UnmapBuffer(ctx, bufObj); 1062 bufObj->AccessFlags = default_access_mode(ctx); 1063 ASSERT(bufObj->Pointer == NULL); 1064 } 1065 1066 FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT); 1067 1068 bufObj->Written = GL_TRUE; 1069 1070#ifdef VBO_DEBUG 1071 printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n", 1072 bufObj->Name, size, data, usage); 1073#endif 1074 1075#ifdef BOUNDS_CHECK 1076 size += 100; 1077#endif 1078 1079 ASSERT(ctx->Driver.BufferData); 1080 if (!ctx->Driver.BufferData( ctx, target, size, data, usage, bufObj )) { 1081 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferDataARB()"); 1082 } 1083} 1084 1085 1086void GLAPIENTRY 1087_mesa_BufferSubDataARB(GLenum target, GLintptrARB offset, 1088 GLsizeiptrARB size, const GLvoid * data) 1089{ 1090 GET_CURRENT_CONTEXT(ctx); 1091 struct gl_buffer_object *bufObj; 1092 ASSERT_OUTSIDE_BEGIN_END(ctx); 1093 1094 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, 1095 "glBufferSubDataARB" ); 1096 if (!bufObj) { 1097 /* error already recorded */ 1098 return; 1099 } 1100 1101 if (size == 0) 1102 return; 1103 1104 bufObj->Written = GL_TRUE; 1105 1106 ASSERT(ctx->Driver.BufferSubData); 1107 ctx->Driver.BufferSubData( ctx, offset, size, data, bufObj ); 1108} 1109 1110 1111void GLAPIENTRY 1112_mesa_GetBufferSubDataARB(GLenum target, GLintptrARB offset, 1113 GLsizeiptrARB size, void * data) 1114{ 1115 GET_CURRENT_CONTEXT(ctx); 1116 struct gl_buffer_object *bufObj; 1117 ASSERT_OUTSIDE_BEGIN_END(ctx); 1118 1119 bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, 1120 "glGetBufferSubDataARB" ); 1121 if (!bufObj) { 1122 /* error already recorded */ 1123 return; 1124 } 1125 1126 ASSERT(ctx->Driver.GetBufferSubData); 1127 ctx->Driver.GetBufferSubData( ctx, offset, size, data, bufObj ); 1128} 1129 1130 1131void * GLAPIENTRY 1132_mesa_MapBufferARB(GLenum target, GLenum access) 1133{ 1134 GET_CURRENT_CONTEXT(ctx); 1135 struct gl_buffer_object * bufObj; 1136 GLbitfield accessFlags; 1137 void *map; 1138 1139 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); 1140 1141 switch (access) { 1142 case GL_READ_ONLY_ARB: 1143 accessFlags = GL_MAP_READ_BIT; 1144 break; 1145 case GL_WRITE_ONLY_ARB: 1146 accessFlags = GL_MAP_WRITE_BIT; 1147 break; 1148 case GL_READ_WRITE_ARB: 1149 accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; 1150 break; 1151 default: 1152 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)"); 1153 return NULL; 1154 } 1155 1156 bufObj = get_buffer(ctx, "glMapBufferARB", target); 1157 if (!bufObj) 1158 return NULL; 1159 1160 if (_mesa_bufferobj_mapped(bufObj)) { 1161 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)"); 1162 return NULL; 1163 } 1164 1165 if (!bufObj->Size) { 1166 _mesa_error(ctx, GL_OUT_OF_MEMORY, 1167 "glMapBuffer(buffer size = 0)"); 1168 return NULL; 1169 } 1170 1171 ASSERT(ctx->Driver.MapBufferRange); 1172 map = ctx->Driver.MapBufferRange(ctx, 0, bufObj->Size, accessFlags, bufObj); 1173 if (!map) { 1174 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); 1175 return NULL; 1176 } 1177 else { 1178 /* The driver callback should have set these fields. 1179 * This is important because other modules (like VBO) might call 1180 * the driver function directly. 1181 */ 1182 ASSERT(bufObj->Pointer == map); 1183 ASSERT(bufObj->Length == bufObj->Size); 1184 ASSERT(bufObj->Offset == 0); 1185 bufObj->AccessFlags = accessFlags; 1186 } 1187 1188 if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB) 1189 bufObj->Written = GL_TRUE; 1190 1191#ifdef VBO_DEBUG 1192 printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n", 1193 bufObj->Name, bufObj->Size, access); 1194 if (access == GL_WRITE_ONLY_ARB) { 1195 GLuint i; 1196 GLubyte *b = (GLubyte *) bufObj->Pointer; 1197 for (i = 0; i < bufObj->Size; i++) 1198 b[i] = i & 0xff; 1199 } 1200#endif 1201 1202#ifdef BOUNDS_CHECK 1203 { 1204 GLubyte *buf = (GLubyte *) bufObj->Pointer; 1205 GLuint i; 1206 /* buffer is 100 bytes larger than requested, fill with magic value */ 1207 for (i = 0; i < 100; i++) { 1208 buf[bufObj->Size - i - 1] = 123; 1209 } 1210 } 1211#endif 1212 1213 return bufObj->Pointer; 1214} 1215 1216 1217GLboolean GLAPIENTRY 1218_mesa_UnmapBufferARB(GLenum target) 1219{ 1220 GET_CURRENT_CONTEXT(ctx); 1221 struct gl_buffer_object *bufObj; 1222 GLboolean status = GL_TRUE; 1223 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 1224 1225 bufObj = get_buffer(ctx, "glUnmapBufferARB", target); 1226 if (!bufObj) 1227 return GL_FALSE; 1228 1229 if (!_mesa_bufferobj_mapped(bufObj)) { 1230 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB"); 1231 return GL_FALSE; 1232 } 1233 1234#ifdef BOUNDS_CHECK 1235 if (bufObj->Access != GL_READ_ONLY_ARB) { 1236 GLubyte *buf = (GLubyte *) bufObj->Pointer; 1237 GLuint i; 1238 /* check that last 100 bytes are still = magic value */ 1239 for (i = 0; i < 100; i++) { 1240 GLuint pos = bufObj->Size - i - 1; 1241 if (buf[pos] != 123) { 1242 _mesa_warning(ctx, "Out of bounds buffer object write detected" 1243 " at position %d (value = %u)\n", 1244 pos, buf[pos]); 1245 } 1246 } 1247 } 1248#endif 1249 1250#ifdef VBO_DEBUG 1251 if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) { 1252 GLuint i, unchanged = 0; 1253 GLubyte *b = (GLubyte *) bufObj->Pointer; 1254 GLint pos = -1; 1255 /* check which bytes changed */ 1256 for (i = 0; i < bufObj->Size - 1; i++) { 1257 if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) { 1258 unchanged++; 1259 if (pos == -1) 1260 pos = i; 1261 } 1262 } 1263 if (unchanged) { 1264 printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n", 1265 bufObj->Name, unchanged, bufObj->Size, pos); 1266 } 1267 } 1268#endif 1269 1270 status = ctx->Driver.UnmapBuffer( ctx, bufObj ); 1271 bufObj->AccessFlags = default_access_mode(ctx); 1272 ASSERT(bufObj->Pointer == NULL); 1273 ASSERT(bufObj->Offset == 0); 1274 ASSERT(bufObj->Length == 0); 1275 1276 return status; 1277} 1278 1279 1280void GLAPIENTRY 1281_mesa_GetBufferParameterivARB(GLenum target, GLenum pname, GLint *params) 1282{ 1283 GET_CURRENT_CONTEXT(ctx); 1284 struct gl_buffer_object *bufObj; 1285 ASSERT_OUTSIDE_BEGIN_END(ctx); 1286 1287 bufObj = get_buffer(ctx, "glGetBufferParameterivARB", target); 1288 if (!bufObj) 1289 return; 1290 1291 switch (pname) { 1292 case GL_BUFFER_SIZE_ARB: 1293 *params = (GLint) bufObj->Size; 1294 return; 1295 case GL_BUFFER_USAGE_ARB: 1296 *params = bufObj->Usage; 1297 return; 1298 case GL_BUFFER_ACCESS_ARB: 1299 *params = simplified_access_mode(bufObj->AccessFlags); 1300 return; 1301 case GL_BUFFER_MAPPED_ARB: 1302 *params = _mesa_bufferobj_mapped(bufObj); 1303 return; 1304 case GL_BUFFER_ACCESS_FLAGS: 1305 if (!ctx->Extensions.ARB_map_buffer_range) 1306 goto invalid_pname; 1307 *params = bufObj->AccessFlags; 1308 return; 1309 case GL_BUFFER_MAP_OFFSET: 1310 if (!ctx->Extensions.ARB_map_buffer_range) 1311 goto invalid_pname; 1312 *params = (GLint) bufObj->Offset; 1313 return; 1314 case GL_BUFFER_MAP_LENGTH: 1315 if (!ctx->Extensions.ARB_map_buffer_range) 1316 goto invalid_pname; 1317 *params = (GLint) bufObj->Length; 1318 return; 1319 default: 1320 ; /* fall-through */ 1321 } 1322 1323invalid_pname: 1324 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname=%s)", 1325 _mesa_lookup_enum_by_nr(pname)); 1326} 1327 1328 1329/** 1330 * New in GL 3.2 1331 * This is pretty much a duplicate of GetBufferParameteriv() but the 1332 * GL_BUFFER_SIZE_ARB attribute will be 64-bits on a 64-bit system. 1333 */ 1334void GLAPIENTRY 1335_mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params) 1336{ 1337 GET_CURRENT_CONTEXT(ctx); 1338 struct gl_buffer_object *bufObj; 1339 ASSERT_OUTSIDE_BEGIN_END(ctx); 1340 1341 bufObj = get_buffer(ctx, "glGetBufferParameteri64v", target); 1342 if (!bufObj) 1343 return; 1344 1345 switch (pname) { 1346 case GL_BUFFER_SIZE_ARB: 1347 *params = bufObj->Size; 1348 return; 1349 case GL_BUFFER_USAGE_ARB: 1350 *params = bufObj->Usage; 1351 return; 1352 case GL_BUFFER_ACCESS_ARB: 1353 *params = simplified_access_mode(bufObj->AccessFlags); 1354 return; 1355 case GL_BUFFER_ACCESS_FLAGS: 1356 if (!ctx->Extensions.ARB_map_buffer_range) 1357 goto invalid_pname; 1358 *params = bufObj->AccessFlags; 1359 return; 1360 case GL_BUFFER_MAPPED_ARB: 1361 *params = _mesa_bufferobj_mapped(bufObj); 1362 return; 1363 case GL_BUFFER_MAP_OFFSET: 1364 if (!ctx->Extensions.ARB_map_buffer_range) 1365 goto invalid_pname; 1366 *params = bufObj->Offset; 1367 return; 1368 case GL_BUFFER_MAP_LENGTH: 1369 if (!ctx->Extensions.ARB_map_buffer_range) 1370 goto invalid_pname; 1371 *params = bufObj->Length; 1372 return; 1373 default: 1374 ; /* fall-through */ 1375 } 1376 1377invalid_pname: 1378 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(pname=%s)", 1379 _mesa_lookup_enum_by_nr(pname)); 1380} 1381 1382 1383void GLAPIENTRY 1384_mesa_GetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params) 1385{ 1386 GET_CURRENT_CONTEXT(ctx); 1387 struct gl_buffer_object * bufObj; 1388 ASSERT_OUTSIDE_BEGIN_END(ctx); 1389 1390 if (pname != GL_BUFFER_MAP_POINTER_ARB) { 1391 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)"); 1392 return; 1393 } 1394 1395 bufObj = get_buffer(ctx, "glGetBufferPointervARB", target); 1396 if (!bufObj) 1397 return; 1398 1399 *params = bufObj->Pointer; 1400} 1401 1402 1403void GLAPIENTRY 1404_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, 1405 GLintptr readOffset, GLintptr writeOffset, 1406 GLsizeiptr size) 1407{ 1408 GET_CURRENT_CONTEXT(ctx); 1409 struct gl_buffer_object *src, *dst; 1410 ASSERT_OUTSIDE_BEGIN_END(ctx); 1411 1412 src = get_buffer(ctx, "glCopyBufferSubData", readTarget); 1413 if (!src) 1414 return; 1415 1416 dst = get_buffer(ctx, "glCopyBufferSubData", writeTarget); 1417 if (!dst) 1418 return; 1419 1420 if (_mesa_bufferobj_mapped(src)) { 1421 _mesa_error(ctx, GL_INVALID_OPERATION, 1422 "glCopyBufferSubData(readBuffer is mapped)"); 1423 return; 1424 } 1425 1426 if (_mesa_bufferobj_mapped(dst)) { 1427 _mesa_error(ctx, GL_INVALID_OPERATION, 1428 "glCopyBufferSubData(writeBuffer is mapped)"); 1429 return; 1430 } 1431 1432 if (readOffset < 0) { 1433 _mesa_error(ctx, GL_INVALID_VALUE, 1434 "glCopyBufferSubData(readOffset = %d)", (int) readOffset); 1435 return; 1436 } 1437 1438 if (writeOffset < 0) { 1439 _mesa_error(ctx, GL_INVALID_VALUE, 1440 "glCopyBufferSubData(writeOffset = %d)", (int) writeOffset); 1441 return; 1442 } 1443 1444 if (size < 0) { 1445 _mesa_error(ctx, GL_INVALID_VALUE, 1446 "glCopyBufferSubData(writeOffset = %d)", (int) size); 1447 return; 1448 } 1449 1450 if (readOffset + size > src->Size) { 1451 _mesa_error(ctx, GL_INVALID_VALUE, 1452 "glCopyBufferSubData(readOffset + size = %d)", 1453 (int) (readOffset + size)); 1454 return; 1455 } 1456 1457 if (writeOffset + size > dst->Size) { 1458 _mesa_error(ctx, GL_INVALID_VALUE, 1459 "glCopyBufferSubData(writeOffset + size = %d)", 1460 (int) (writeOffset + size)); 1461 return; 1462 } 1463 1464 if (src == dst) { 1465 if (readOffset + size <= writeOffset) { 1466 /* OK */ 1467 } 1468 else if (writeOffset + size <= readOffset) { 1469 /* OK */ 1470 } 1471 else { 1472 /* overlapping src/dst is illegal */ 1473 _mesa_error(ctx, GL_INVALID_VALUE, 1474 "glCopyBufferSubData(overlapping src/dst)"); 1475 return; 1476 } 1477 } 1478 1479 ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size); 1480} 1481 1482 1483/** 1484 * See GL_ARB_map_buffer_range spec 1485 */ 1486void * GLAPIENTRY 1487_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, 1488 GLbitfield access) 1489{ 1490 GET_CURRENT_CONTEXT(ctx); 1491 struct gl_buffer_object *bufObj; 1492 void *map; 1493 1494 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); 1495 1496 if (!ctx->Extensions.ARB_map_buffer_range) { 1497 _mesa_error(ctx, GL_INVALID_OPERATION, 1498 "glMapBufferRange(extension not supported)"); 1499 return NULL; 1500 } 1501 1502 if (offset < 0) { 1503 _mesa_error(ctx, GL_INVALID_VALUE, 1504 "glMapBufferRange(offset = %ld)", (long)offset); 1505 return NULL; 1506 } 1507 1508 if (length < 0) { 1509 _mesa_error(ctx, GL_INVALID_VALUE, 1510 "glMapBufferRange(length = %ld)", (long)length); 1511 return NULL; 1512 } 1513 1514 if (access & ~(GL_MAP_READ_BIT | 1515 GL_MAP_WRITE_BIT | 1516 GL_MAP_INVALIDATE_RANGE_BIT | 1517 GL_MAP_INVALIDATE_BUFFER_BIT | 1518 GL_MAP_FLUSH_EXPLICIT_BIT | 1519 GL_MAP_UNSYNCHRONIZED_BIT)) { 1520 /* generate an error if any undefind bit is set */ 1521 _mesa_error(ctx, GL_INVALID_VALUE, "glMapBufferRange(access)"); 1522 return NULL; 1523 } 1524 1525 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) { 1526 _mesa_error(ctx, GL_INVALID_OPERATION, 1527 "glMapBufferRange(access indicates neither read or write)"); 1528 return NULL; 1529 } 1530 1531 if ((access & GL_MAP_READ_BIT) && 1532 (access & (GL_MAP_INVALIDATE_RANGE_BIT | 1533 GL_MAP_INVALIDATE_BUFFER_BIT | 1534 GL_MAP_UNSYNCHRONIZED_BIT))) { 1535 _mesa_error(ctx, GL_INVALID_OPERATION, 1536 "glMapBufferRange(invalid access flags)"); 1537 return NULL; 1538 } 1539 1540 if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) && 1541 ((access & GL_MAP_WRITE_BIT) == 0)) { 1542 _mesa_error(ctx, GL_INVALID_OPERATION, 1543 "glMapBufferRange(invalid access flags)"); 1544 return NULL; 1545 } 1546 1547 bufObj = get_buffer(ctx, "glMapBufferRange", target); 1548 if (!bufObj) 1549 return NULL; 1550 1551 if (offset + length > bufObj->Size) { 1552 _mesa_error(ctx, GL_INVALID_VALUE, 1553 "glMapBufferRange(offset + length > size)"); 1554 return NULL; 1555 } 1556 1557 if (_mesa_bufferobj_mapped(bufObj)) { 1558 _mesa_error(ctx, GL_INVALID_OPERATION, 1559 "glMapBufferRange(buffer already mapped)"); 1560 return NULL; 1561 } 1562 1563 if (!bufObj->Size) { 1564 _mesa_error(ctx, GL_OUT_OF_MEMORY, 1565 "glMapBufferRange(buffer size = 0)"); 1566 return NULL; 1567 } 1568 1569 /* Mapping zero bytes should return a non-null pointer. */ 1570 if (!length) { 1571 static long dummy = 0; 1572 bufObj->Pointer = &dummy; 1573 bufObj->Length = length; 1574 bufObj->Offset = offset; 1575 bufObj->AccessFlags = access; 1576 return bufObj->Pointer; 1577 } 1578 1579 ASSERT(ctx->Driver.MapBufferRange); 1580 map = ctx->Driver.MapBufferRange(ctx, offset, length, access, bufObj); 1581 if (!map) { 1582 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); 1583 } 1584 else { 1585 /* The driver callback should have set all these fields. 1586 * This is important because other modules (like VBO) might call 1587 * the driver function directly. 1588 */ 1589 ASSERT(bufObj->Pointer == map); 1590 ASSERT(bufObj->Length == length); 1591 ASSERT(bufObj->Offset == offset); 1592 ASSERT(bufObj->AccessFlags == access); 1593 } 1594 1595 return map; 1596} 1597 1598 1599/** 1600 * See GL_ARB_map_buffer_range spec 1601 */ 1602void GLAPIENTRY 1603_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) 1604{ 1605 GET_CURRENT_CONTEXT(ctx); 1606 struct gl_buffer_object *bufObj; 1607 ASSERT_OUTSIDE_BEGIN_END(ctx); 1608 1609 if (!ctx->Extensions.ARB_map_buffer_range) { 1610 _mesa_error(ctx, GL_INVALID_OPERATION, 1611 "glFlushMappedBufferRange(extension not supported)"); 1612 return; 1613 } 1614 1615 if (offset < 0) { 1616 _mesa_error(ctx, GL_INVALID_VALUE, 1617 "glFlushMappedBufferRange(offset = %ld)", (long)offset); 1618 return; 1619 } 1620 1621 if (length < 0) { 1622 _mesa_error(ctx, GL_INVALID_VALUE, 1623 "glFlushMappedBufferRange(length = %ld)", (long)length); 1624 return; 1625 } 1626 1627 bufObj = get_buffer(ctx, "glFlushMappedBufferRange", target); 1628 if (!bufObj) 1629 return; 1630 1631 if (!_mesa_bufferobj_mapped(bufObj)) { 1632 /* buffer is not mapped */ 1633 _mesa_error(ctx, GL_INVALID_OPERATION, 1634 "glFlushMappedBufferRange(buffer is not mapped)"); 1635 return; 1636 } 1637 1638 if ((bufObj->AccessFlags & GL_MAP_FLUSH_EXPLICIT_BIT) == 0) { 1639 _mesa_error(ctx, GL_INVALID_OPERATION, 1640 "glFlushMappedBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)"); 1641 return; 1642 } 1643 1644 if (offset + length > bufObj->Length) { 1645 _mesa_error(ctx, GL_INVALID_VALUE, 1646 "glFlushMappedBufferRange(offset %ld + length %ld > mapped length %ld)", 1647 (long)offset, (long)length, (long)bufObj->Length); 1648 return; 1649 } 1650 1651 ASSERT(bufObj->AccessFlags & GL_MAP_WRITE_BIT); 1652 1653 if (ctx->Driver.FlushMappedBufferRange) 1654 ctx->Driver.FlushMappedBufferRange(ctx, offset, length, bufObj); 1655} 1656 1657 1658#if FEATURE_APPLE_object_purgeable 1659static GLenum 1660buffer_object_purgeable(struct gl_context *ctx, GLuint name, GLenum option) 1661{ 1662 struct gl_buffer_object *bufObj; 1663 GLenum retval; 1664 1665 bufObj = _mesa_lookup_bufferobj(ctx, name); 1666 if (!bufObj) { 1667 _mesa_error(ctx, GL_INVALID_VALUE, 1668 "glObjectPurgeable(name = 0x%x)", name); 1669 return 0; 1670 } 1671 if (!_mesa_is_bufferobj(bufObj)) { 1672 _mesa_error(ctx, GL_INVALID_OPERATION, "glObjectPurgeable(buffer 0)" ); 1673 return 0; 1674 } 1675 1676 if (bufObj->Purgeable) { 1677 _mesa_error(ctx, GL_INVALID_OPERATION, 1678 "glObjectPurgeable(name = 0x%x) is already purgeable", name); 1679 return GL_VOLATILE_APPLE; 1680 } 1681 1682 bufObj->Purgeable = GL_TRUE; 1683 1684 retval = GL_VOLATILE_APPLE; 1685 if (ctx->Driver.BufferObjectPurgeable) 1686 retval = ctx->Driver.BufferObjectPurgeable(ctx, bufObj, option); 1687 1688 return retval; 1689} 1690 1691 1692static GLenum 1693renderbuffer_purgeable(struct gl_context *ctx, GLuint name, GLenum option) 1694{ 1695 struct gl_renderbuffer *bufObj; 1696 GLenum retval; 1697 1698 bufObj = _mesa_lookup_renderbuffer(ctx, name); 1699 if (!bufObj) { 1700 _mesa_error(ctx, GL_INVALID_VALUE, 1701 "glObjectUnpurgeable(name = 0x%x)", name); 1702 return 0; 1703 } 1704 1705 if (bufObj->Purgeable) { 1706 _mesa_error(ctx, GL_INVALID_OPERATION, 1707 "glObjectPurgeable(name = 0x%x) is already purgeable", name); 1708 return GL_VOLATILE_APPLE; 1709 } 1710 1711 bufObj->Purgeable = GL_TRUE; 1712 1713 retval = GL_VOLATILE_APPLE; 1714 if (ctx->Driver.RenderObjectPurgeable) 1715 retval = ctx->Driver.RenderObjectPurgeable(ctx, bufObj, option); 1716 1717 return retval; 1718} 1719 1720 1721static GLenum 1722texture_object_purgeable(struct gl_context *ctx, GLuint name, GLenum option) 1723{ 1724 struct gl_texture_object *bufObj; 1725 GLenum retval; 1726 1727 bufObj = _mesa_lookup_texture(ctx, name); 1728 if (!bufObj) { 1729 _mesa_error(ctx, GL_INVALID_VALUE, 1730 "glObjectPurgeable(name = 0x%x)", name); 1731 return 0; 1732 } 1733 1734 if (bufObj->Purgeable) { 1735 _mesa_error(ctx, GL_INVALID_OPERATION, 1736 "glObjectPurgeable(name = 0x%x) is already purgeable", name); 1737 return GL_VOLATILE_APPLE; 1738 } 1739 1740 bufObj->Purgeable = GL_TRUE; 1741 1742 retval = GL_VOLATILE_APPLE; 1743 if (ctx->Driver.TextureObjectPurgeable) 1744 retval = ctx->Driver.TextureObjectPurgeable(ctx, bufObj, option); 1745 1746 return retval; 1747} 1748 1749 1750GLenum GLAPIENTRY 1751_mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option) 1752{ 1753 GLenum retval; 1754 1755 GET_CURRENT_CONTEXT(ctx); 1756 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 1757 1758 if (name == 0) { 1759 _mesa_error(ctx, GL_INVALID_VALUE, 1760 "glObjectPurgeable(name = 0x%x)", name); 1761 return 0; 1762 } 1763 1764 switch (option) { 1765 case GL_VOLATILE_APPLE: 1766 case GL_RELEASED_APPLE: 1767 /* legal */ 1768 break; 1769 default: 1770 _mesa_error(ctx, GL_INVALID_ENUM, 1771 "glObjectPurgeable(name = 0x%x) invalid option: %d", 1772 name, option); 1773 return 0; 1774 } 1775 1776 switch (objectType) { 1777 case GL_TEXTURE: 1778 retval = texture_object_purgeable(ctx, name, option); 1779 break; 1780 case GL_RENDERBUFFER_EXT: 1781 retval = renderbuffer_purgeable(ctx, name, option); 1782 break; 1783 case GL_BUFFER_OBJECT_APPLE: 1784 retval = buffer_object_purgeable(ctx, name, option); 1785 break; 1786 default: 1787 _mesa_error(ctx, GL_INVALID_ENUM, 1788 "glObjectPurgeable(name = 0x%x) invalid type: %d", 1789 name, objectType); 1790 return 0; 1791 } 1792 1793 /* In strict conformance to the spec, we must only return VOLATILE when 1794 * when passed the VOLATILE option. Madness. 1795 * 1796 * XXX First fix the spec, then fix me. 1797 */ 1798 return option == GL_VOLATILE_APPLE ? GL_VOLATILE_APPLE : retval; 1799} 1800 1801 1802static GLenum 1803buffer_object_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option) 1804{ 1805 struct gl_buffer_object *bufObj; 1806 GLenum retval; 1807 1808 bufObj = _mesa_lookup_bufferobj(ctx, name); 1809 if (!bufObj) { 1810 _mesa_error(ctx, GL_INVALID_VALUE, 1811 "glObjectUnpurgeable(name = 0x%x)", name); 1812 return 0; 1813 } 1814 1815 if (! bufObj->Purgeable) { 1816 _mesa_error(ctx, GL_INVALID_OPERATION, 1817 "glObjectUnpurgeable(name = 0x%x) object is " 1818 " already \"unpurged\"", name); 1819 return 0; 1820 } 1821 1822 bufObj->Purgeable = GL_FALSE; 1823 1824 retval = option; 1825 if (ctx->Driver.BufferObjectUnpurgeable) 1826 retval = ctx->Driver.BufferObjectUnpurgeable(ctx, bufObj, option); 1827 1828 return retval; 1829} 1830 1831 1832static GLenum 1833renderbuffer_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option) 1834{ 1835 struct gl_renderbuffer *bufObj; 1836 GLenum retval; 1837 1838 bufObj = _mesa_lookup_renderbuffer(ctx, name); 1839 if (!bufObj) { 1840 _mesa_error(ctx, GL_INVALID_VALUE, 1841 "glObjectUnpurgeable(name = 0x%x)", name); 1842 return 0; 1843 } 1844 1845 if (! bufObj->Purgeable) { 1846 _mesa_error(ctx, GL_INVALID_OPERATION, 1847 "glObjectUnpurgeable(name = 0x%x) object is " 1848 " already \"unpurged\"", name); 1849 return 0; 1850 } 1851 1852 bufObj->Purgeable = GL_FALSE; 1853 1854 retval = option; 1855 if (ctx->Driver.RenderObjectUnpurgeable) 1856 retval = ctx->Driver.RenderObjectUnpurgeable(ctx, bufObj, option); 1857 1858 return retval; 1859} 1860 1861 1862static GLenum 1863texture_object_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option) 1864{ 1865 struct gl_texture_object *bufObj; 1866 GLenum retval; 1867 1868 bufObj = _mesa_lookup_texture(ctx, name); 1869 if (!bufObj) { 1870 _mesa_error(ctx, GL_INVALID_VALUE, 1871 "glObjectUnpurgeable(name = 0x%x)", name); 1872 return 0; 1873 } 1874 1875 if (! bufObj->Purgeable) { 1876 _mesa_error(ctx, GL_INVALID_OPERATION, 1877 "glObjectUnpurgeable(name = 0x%x) object is" 1878 " already \"unpurged\"", name); 1879 return 0; 1880 } 1881 1882 bufObj->Purgeable = GL_FALSE; 1883 1884 retval = option; 1885 if (ctx->Driver.TextureObjectUnpurgeable) 1886 retval = ctx->Driver.TextureObjectUnpurgeable(ctx, bufObj, option); 1887 1888 return retval; 1889} 1890 1891 1892GLenum GLAPIENTRY 1893_mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option) 1894{ 1895 GET_CURRENT_CONTEXT(ctx); 1896 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 1897 1898 if (name == 0) { 1899 _mesa_error(ctx, GL_INVALID_VALUE, 1900 "glObjectUnpurgeable(name = 0x%x)", name); 1901 return 0; 1902 } 1903 1904 switch (option) { 1905 case GL_RETAINED_APPLE: 1906 case GL_UNDEFINED_APPLE: 1907 /* legal */ 1908 break; 1909 default: 1910 _mesa_error(ctx, GL_INVALID_ENUM, 1911 "glObjectUnpurgeable(name = 0x%x) invalid option: %d", 1912 name, option); 1913 return 0; 1914 } 1915 1916 switch (objectType) { 1917 case GL_BUFFER_OBJECT_APPLE: 1918 return buffer_object_unpurgeable(ctx, name, option); 1919 case GL_TEXTURE: 1920 return texture_object_unpurgeable(ctx, name, option); 1921 case GL_RENDERBUFFER_EXT: 1922 return renderbuffer_unpurgeable(ctx, name, option); 1923 default: 1924 _mesa_error(ctx, GL_INVALID_ENUM, 1925 "glObjectUnpurgeable(name = 0x%x) invalid type: %d", 1926 name, objectType); 1927 return 0; 1928 } 1929} 1930 1931 1932static void 1933get_buffer_object_parameteriv(struct gl_context *ctx, GLuint name, 1934 GLenum pname, GLint *params) 1935{ 1936 struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, name); 1937 if (!bufObj) { 1938 _mesa_error(ctx, GL_INVALID_VALUE, 1939 "glGetObjectParameteriv(name = 0x%x) invalid object", name); 1940 return; 1941 } 1942 1943 switch (pname) { 1944 case GL_PURGEABLE_APPLE: 1945 *params = bufObj->Purgeable; 1946 break; 1947 default: 1948 _mesa_error(ctx, GL_INVALID_ENUM, 1949 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", 1950 name, pname); 1951 break; 1952 } 1953} 1954 1955 1956static void 1957get_renderbuffer_parameteriv(struct gl_context *ctx, GLuint name, 1958 GLenum pname, GLint *params) 1959{ 1960 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name); 1961 if (!rb) { 1962 _mesa_error(ctx, GL_INVALID_VALUE, 1963 "glObjectUnpurgeable(name = 0x%x)", name); 1964 return; 1965 } 1966 1967 switch (pname) { 1968 case GL_PURGEABLE_APPLE: 1969 *params = rb->Purgeable; 1970 break; 1971 default: 1972 _mesa_error(ctx, GL_INVALID_ENUM, 1973 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", 1974 name, pname); 1975 break; 1976 } 1977} 1978 1979 1980static void 1981get_texture_object_parameteriv(struct gl_context *ctx, GLuint name, 1982 GLenum pname, GLint *params) 1983{ 1984 struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name); 1985 if (!texObj) { 1986 _mesa_error(ctx, GL_INVALID_VALUE, 1987 "glObjectUnpurgeable(name = 0x%x)", name); 1988 return; 1989 } 1990 1991 switch (pname) { 1992 case GL_PURGEABLE_APPLE: 1993 *params = texObj->Purgeable; 1994 break; 1995 default: 1996 _mesa_error(ctx, GL_INVALID_ENUM, 1997 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", 1998 name, pname); 1999 break; 2000 } 2001} 2002 2003 2004void GLAPIENTRY 2005_mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname, 2006 GLint *params) 2007{ 2008 GET_CURRENT_CONTEXT(ctx); 2009 2010 if (name == 0) { 2011 _mesa_error(ctx, GL_INVALID_VALUE, 2012 "glGetObjectParameteriv(name = 0x%x)", name); 2013 return; 2014 } 2015 2016 switch (objectType) { 2017 case GL_TEXTURE: 2018 get_texture_object_parameteriv(ctx, name, pname, params); 2019 break; 2020 case GL_BUFFER_OBJECT_APPLE: 2021 get_buffer_object_parameteriv(ctx, name, pname, params); 2022 break; 2023 case GL_RENDERBUFFER_EXT: 2024 get_renderbuffer_parameteriv(ctx, name, pname, params); 2025 break; 2026 default: 2027 _mesa_error(ctx, GL_INVALID_ENUM, 2028 "glGetObjectParameteriv(name = 0x%x) invalid type: %d", 2029 name, objectType); 2030 } 2031} 2032 2033#endif /* FEATURE_APPLE_object_purgeable */ 2034 2035static void 2036set_ubo_binding(struct gl_context *ctx, 2037 int index, 2038 struct gl_buffer_object *bufObj, 2039 GLintptr offset, 2040 GLsizeiptr size, 2041 GLboolean autoSize) 2042{ 2043 struct gl_uniform_buffer_binding *binding; 2044 2045 binding = &ctx->UniformBufferBindings[index]; 2046 if (binding->BufferObject == bufObj && 2047 binding->Offset == offset && 2048 binding->Size == size && 2049 binding->AutomaticSize == autoSize) { 2050 return; 2051 } 2052 2053 FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT); 2054 2055 _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj); 2056 binding->Offset = offset; 2057 binding->Size = size; 2058 binding->AutomaticSize = autoSize; 2059} 2060 2061/** 2062 * Bind a region of a buffer object to a uniform block binding point. 2063 * \param index the uniform buffer binding point index 2064 * \param bufObj the buffer object 2065 * \param offset offset to the start of buffer object region 2066 * \param size size of the buffer object region 2067 */ 2068static void 2069bind_buffer_range_uniform_buffer(struct gl_context *ctx, 2070 GLuint index, 2071 struct gl_buffer_object *bufObj, 2072 GLintptr offset, 2073 GLsizeiptr size) 2074{ 2075 if (index >= ctx->Const.MaxUniformBufferBindings) { 2076 _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index); 2077 return; 2078 } 2079 2080 if (offset & (ctx->Const.UniformBufferOffsetAlignment - 1)) { 2081 _mesa_error(ctx, GL_INVALID_VALUE, 2082 "glBindBufferRange(offset misalgned %d/%d)", (int) offset, 2083 ctx->Const.UniformBufferOffsetAlignment); 2084 return; 2085 } 2086 2087 if (bufObj == ctx->Shared->NullBufferObj) { 2088 offset = -1; 2089 size = -1; 2090 } 2091 2092 _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj); 2093 set_ubo_binding(ctx, index, bufObj, offset, size, GL_FALSE); 2094} 2095 2096 2097/** 2098 * Bind a buffer object to a uniform block binding point. 2099 * As above, but offset = 0. 2100 */ 2101static void 2102bind_buffer_base_uniform_buffer(struct gl_context *ctx, 2103 GLuint index, 2104 struct gl_buffer_object *bufObj) 2105{ 2106 if (index >= ctx->Const.MaxUniformBufferBindings) { 2107 _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index); 2108 return; 2109 } 2110 2111 _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj); 2112 if (bufObj == ctx->Shared->NullBufferObj) 2113 set_ubo_binding(ctx, index, bufObj, -1, -1, GL_TRUE); 2114 else 2115 set_ubo_binding(ctx, index, bufObj, 0, 0, GL_TRUE); 2116} 2117 2118void GLAPIENTRY 2119_mesa_BindBufferRange(GLenum target, GLuint index, 2120 GLuint buffer, GLintptr offset, GLsizeiptr size) 2121{ 2122 GET_CURRENT_CONTEXT(ctx); 2123 struct gl_buffer_object *bufObj; 2124 2125 if (buffer == 0) { 2126 bufObj = ctx->Shared->NullBufferObj; 2127 } else { 2128 bufObj = _mesa_lookup_bufferobj(ctx, buffer); 2129 } 2130 handle_bind_buffer_gen(ctx, target, buffer, &bufObj); 2131 2132 if (!bufObj) { 2133 _mesa_error(ctx, GL_INVALID_OPERATION, 2134 "glBindBufferRange(invalid buffer=%u)", buffer); 2135 return; 2136 } 2137 2138 if (size <= 0) { 2139 _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(size=%d)", 2140 (int) size); 2141 return; 2142 } 2143 2144 if (offset + size > bufObj->Size) { 2145 _mesa_error(ctx, GL_INVALID_VALUE, 2146 "glBindBufferRange(offset + size %d > buffer size %d)", 2147 (int) (offset + size), (int) (bufObj->Size)); 2148 return; 2149 } 2150 2151 switch (target) { 2152 case GL_TRANSFORM_FEEDBACK_BUFFER: 2153 _mesa_bind_buffer_range_transform_feedback(ctx, index, bufObj, 2154 offset, size); 2155 return; 2156 case GL_UNIFORM_BUFFER: 2157 bind_buffer_range_uniform_buffer(ctx, index, bufObj, offset, size); 2158 return; 2159 default: 2160 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferRange(target)"); 2161 return; 2162 } 2163} 2164 2165void GLAPIENTRY 2166_mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer) 2167{ 2168 GET_CURRENT_CONTEXT(ctx); 2169 struct gl_buffer_object *bufObj; 2170 2171 if (buffer == 0) { 2172 bufObj = ctx->Shared->NullBufferObj; 2173 } else { 2174 bufObj = _mesa_lookup_bufferobj(ctx, buffer); 2175 } 2176 handle_bind_buffer_gen(ctx, target, buffer, &bufObj); 2177 2178 if (!bufObj) { 2179 _mesa_error(ctx, GL_INVALID_OPERATION, 2180 "glBindBufferBase(invalid buffer=%u)", buffer); 2181 return; 2182 } 2183 2184 /* Note that there's some oddness in the GL 3.1-GL 3.3 specifications with 2185 * regards to BindBufferBase. It says (GL 3.1 core spec, page 63): 2186 * 2187 * "BindBufferBase is equivalent to calling BindBufferRange with offset 2188 * zero and size equal to the size of buffer." 2189 * 2190 * but it says for glGetIntegeri_v (GL 3.1 core spec, page 230): 2191 * 2192 * "If the parameter (starting offset or size) was not specified when the 2193 * buffer object was bound, zero is returned." 2194 * 2195 * What happens if the size of the buffer changes? Does the size of the 2196 * buffer at the moment glBindBufferBase was called still play a role, like 2197 * the first quote would imply, or is the size meaningless in the 2198 * glBindBufferBase case like the second quote would suggest? The GL 4.1 2199 * core spec page 45 says: 2200 * 2201 * "It is equivalent to calling BindBufferRange with offset zero, while 2202 * size is determined by the size of the bound buffer at the time the 2203 * binding is used." 2204 * 2205 * My interpretation is that the GL 4.1 spec was a clarification of the 2206 * behavior, not a change. In particular, this choice will only make 2207 * rendering work in cases where it would have had undefined results. 2208 */ 2209 2210 switch (target) { 2211 case GL_TRANSFORM_FEEDBACK_BUFFER: 2212 _mesa_bind_buffer_base_transform_feedback(ctx, index, bufObj); 2213 return; 2214 case GL_UNIFORM_BUFFER: 2215 bind_buffer_base_uniform_buffer(ctx, index, bufObj); 2216 return; 2217 default: 2218 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)"); 2219 return; 2220 } 2221} 2222 2223static void GLAPIENTRY 2224_mesa_InvalidateBufferSubData(GLuint buffer, GLintptr offset, 2225 GLsizeiptr length) 2226{ 2227 GET_CURRENT_CONTEXT(ctx); 2228 struct gl_buffer_object *bufObj; 2229 const GLintptr end = offset + length; 2230 2231 bufObj = _mesa_lookup_bufferobj(ctx, buffer); 2232 if (!bufObj) { 2233 _mesa_error(ctx, GL_INVALID_VALUE, 2234 "glInvalidateBufferSubData(name = 0x%x) invalid object", 2235 buffer); 2236 return; 2237 } 2238 2239 /* The GL_ARB_invalidate_subdata spec says: 2240 * 2241 * "An INVALID_VALUE error is generated if <offset> or <length> is 2242 * negative, or if <offset> + <length> is greater than the value of 2243 * BUFFER_SIZE." 2244 */ 2245 if (end < 0 || end > bufObj->Size) { 2246 _mesa_error(ctx, GL_INVALID_VALUE, 2247 "glInvalidateBufferSubData(invalid offset or length)"); 2248 return; 2249 } 2250 2251 /* The GL_ARB_invalidate_subdata spec says: 2252 * 2253 * "An INVALID_OPERATION error is generated if the buffer is currently 2254 * mapped by MapBuffer, or if the invalidate range intersects the range 2255 * currently mapped by MapBufferRange." 2256 */ 2257 if (_mesa_bufferobj_mapped(bufObj)) { 2258 const GLintptr mapEnd = bufObj->Offset + bufObj->Length; 2259 2260 /* The regions do not overlap if and only if the end of the discard 2261 * region is before the mapped region or the start of the discard region 2262 * is after the mapped region. 2263 * 2264 * Note that 'end' and 'mapEnd' are the first byte *after* the discard 2265 * region and the mapped region, repsectively. It is okay for that byte 2266 * to be mapped (for 'end') or discarded (for 'mapEnd'). 2267 */ 2268 if (!(end <= bufObj->Offset || offset >= mapEnd)) { 2269 _mesa_error(ctx, GL_INVALID_OPERATION, 2270 "glInvalidateBufferSubData(intersection with mapped " 2271 "range)"); 2272 return; 2273 } 2274 } 2275 2276 /* We don't actually do anything for this yet. Just return after 2277 * validating the parameters and generating the required errors. 2278 */ 2279 return; 2280} 2281 2282static void GLAPIENTRY 2283_mesa_InvalidateBufferData(GLuint buffer) 2284{ 2285 GET_CURRENT_CONTEXT(ctx); 2286 struct gl_buffer_object *bufObj; 2287 2288 bufObj = _mesa_lookup_bufferobj(ctx, buffer); 2289 if (!bufObj) { 2290 _mesa_error(ctx, GL_INVALID_VALUE, 2291 "glInvalidateBufferData(name = 0x%x) invalid object", 2292 buffer); 2293 return; 2294 } 2295 2296 /* The GL_ARB_invalidate_subdata spec says: 2297 * 2298 * "An INVALID_OPERATION error is generated if the buffer is currently 2299 * mapped by MapBuffer, or if the invalidate range intersects the range 2300 * currently mapped by MapBufferRange." 2301 */ 2302 if (_mesa_bufferobj_mapped(bufObj)) { 2303 _mesa_error(ctx, GL_INVALID_OPERATION, 2304 "glInvalidateBufferData(intersection with mapped " 2305 "range)"); 2306 return; 2307 } 2308 2309 /* We don't actually do anything for this yet. Just return after 2310 * validating the parameters and generating the required errors. 2311 */ 2312 return; 2313} 2314 2315void 2316_mesa_init_bufferobj_dispatch(struct gl_context *ctx, struct _glapi_table *disp) 2317{ 2318 SET_BindBufferARB(disp, _mesa_BindBufferARB); 2319 SET_BufferDataARB(disp, _mesa_BufferDataARB); 2320 SET_BufferSubDataARB(disp, _mesa_BufferSubDataARB); 2321 SET_DeleteBuffersARB(disp, _mesa_DeleteBuffersARB); 2322 SET_GenBuffersARB(disp, _mesa_GenBuffersARB); 2323 SET_GetBufferParameterivARB(disp, _mesa_GetBufferParameterivARB); 2324 SET_GetBufferPointervARB(disp, _mesa_GetBufferPointervARB); 2325 SET_GetBufferSubDataARB(disp, _mesa_GetBufferSubDataARB); 2326 SET_IsBufferARB(disp, _mesa_IsBufferARB); 2327 SET_MapBufferARB(disp, _mesa_MapBufferARB); 2328 SET_UnmapBufferARB(disp, _mesa_UnmapBufferARB); 2329 2330 if (_mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx)) { 2331 SET_BindBufferRangeEXT(disp, _mesa_BindBufferRange); 2332 SET_BindBufferBaseEXT(disp, _mesa_BindBufferBase); 2333 } 2334 2335 if (_mesa_is_desktop_gl(ctx)) { 2336 SET_InvalidateBufferData(disp, _mesa_InvalidateBufferData); 2337 SET_InvalidateBufferSubData(disp, _mesa_InvalidateBufferSubData); 2338 } 2339} 2340