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