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