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