bufferobj.c 131 KB
Newer Older
1 2 3
/*
 * Mesa 3-D graphics library
 *
4
 * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5
 * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 21 22 23
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
24 25 26 27 28
 */


/**
 * \file bufferobj.c
Brian Paul's avatar
Brian Paul committed
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 <inttypes.h>  /* for PRId64 macro */
35
#include "util/debug.h"
36
#include "glheader.h"
37
#include "enums.h"
38
#include "hash.h"
39
#include "imports.h"
40
#include "context.h"
41
#include "bufferobj.h"
42
#include "mtypes.h"
43 44 45
#include "teximage.h"
#include "glformats.h"
#include "texstore.h"
46
#include "transformfeedback.h"
47
#include "varray.h"
48

49

50 51 52 53 54
/* Debug flags */
/*#define VBO_DEBUG*/
/*#define BOUNDS_CHECK*/


55 56 57 58 59 60 61 62 63 64
/**
 * We count the number of buffer modification calls to check for
 * inefficient buffer use.  This is the number of such calls before we
 * issue a warning.
 */
#define BUFFER_WARNING_CALL_COUNT 4


/**
 * Helper to warn of possible performance issues, such as frequently
65 66
 * updating a buffer created with GL_STATIC_DRAW.  Called via the macro
 * below.
67 68
 */
static void
69
buffer_usage_warning(struct gl_context *ctx, GLuint *id, const char *fmt, ...)
70 71 72 73
{
   va_list args;

   va_start(args, fmt);
74
   _mesa_gl_vdebug(ctx, id,
75 76 77 78 79 80 81
                   MESA_DEBUG_SOURCE_API,
                   MESA_DEBUG_TYPE_PERFORMANCE,
                   MESA_DEBUG_SEVERITY_MEDIUM,
                   fmt, args);
   va_end(args);
}

82 83 84 85 86 87
#define BUFFER_USAGE_WARNING(CTX, FMT, ...) \
   do { \
      static GLuint id = 0; \
      buffer_usage_warning(CTX, &id, FMT, ##__VA_ARGS__); \
   } while (0)

88

89 90 91 92 93 94 95
/**
 * Used as a placeholder for buffer objects between glGenBuffers() and
 * glBindBuffer() so that glIsBuffer() can work correctly.
 */
static struct gl_buffer_object DummyBufferObject;


96
/**
97 98 99 100
 * Return pointer to address of a buffer object target.
 * \param ctx  the GL context
 * \param target  the buffer object target to be retrieved.
 * \return   pointer to pointer to the buffer object bound to \c target in the
101
 *           specified context or \c NULL if \c target is invalid.
102
 */
Brian Paul's avatar
Brian Paul committed
103
static inline struct gl_buffer_object **
104
get_buffer_target(struct gl_context *ctx, GLenum target)
105
{
106 107 108 109 110 111
   /* Other targets are only supported in desktop OpenGL and OpenGL ES 3.0.
    */
   if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx)
       && target != GL_ARRAY_BUFFER && target != GL_ELEMENT_ARRAY_BUFFER)
      return NULL;

112
   switch (target) {
113 114 115
   case GL_ARRAY_BUFFER_ARB:
      return &ctx->Array.ArrayBufferObj;
   case GL_ELEMENT_ARRAY_BUFFER_ARB:
116
      return &ctx->Array.VAO->IndexBufferObj;
117 118 119 120 121
   case GL_PIXEL_PACK_BUFFER_EXT:
      return &ctx->Pack.BufferObj;
   case GL_PIXEL_UNPACK_BUFFER_EXT:
      return &ctx->Unpack.BufferObj;
   case GL_COPY_READ_BUFFER:
122
      return &ctx->CopyReadBuffer;
123
   case GL_COPY_WRITE_BUFFER:
124
      return &ctx->CopyWriteBuffer;
125 126 127 128
   case GL_QUERY_BUFFER:
      if (_mesa_has_ARB_query_buffer_object(ctx))
         return &ctx->QueryBuffer;
      break;
129
   case GL_DRAW_INDIRECT_BUFFER:
130 131 132
      if ((ctx->API == API_OPENGL_CORE &&
           ctx->Extensions.ARB_draw_indirect) ||
           _mesa_is_gles31(ctx)) {
133 134 135
         return &ctx->DrawIndirectBuffer;
      }
      break;
136 137 138 139 140
   case GL_PARAMETER_BUFFER_ARB:
      if (_mesa_has_ARB_indirect_parameters(ctx)) {
         return &ctx->ParameterBuffer;
      }
      break;
141 142 143 144 145
   case GL_DISPATCH_INDIRECT_BUFFER:
      if (_mesa_has_compute_shaders(ctx)) {
         return &ctx->DispatchIndirectBuffer;
      }
      break;
146 147 148 149 150
   case GL_TRANSFORM_FEEDBACK_BUFFER:
      if (ctx->Extensions.EXT_transform_feedback) {
         return &ctx->TransformFeedback.CurrentBuffer;
      }
      break;
151
   case GL_TEXTURE_BUFFER:
152 153
      if (_mesa_has_ARB_texture_buffer_object(ctx) ||
          _mesa_has_OES_texture_buffer(ctx)) {
154 155 156
         return &ctx->Texture.BufferObject;
      }
      break;
157 158 159 160 161
   case GL_UNIFORM_BUFFER:
      if (ctx->Extensions.ARB_uniform_buffer_object) {
         return &ctx->UniformBuffer;
      }
      break;
162 163 164 165 166
   case GL_SHADER_STORAGE_BUFFER:
      if (ctx->Extensions.ARB_shader_storage_buffer_object) {
         return &ctx->ShaderStorageBuffer;
      }
      break;
167 168 169 170 171
   case GL_ATOMIC_COUNTER_BUFFER:
      if (ctx->Extensions.ARB_shader_atomic_counters) {
         return &ctx->AtomicBuffer;
      }
      break;
172 173 174 175 176
   case GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD:
      if (ctx->Extensions.AMD_pinned_memory) {
         return &ctx->ExternalVirtualMemoryBuffer;
      }
      break;
177 178
   default:
      return NULL;
179
   }
180 181
   return NULL;
}
182 183


184 185 186 187
/**
 * Get the buffer object bound to the specified target in a GL context.
 * \param ctx  the GL context
 * \param target  the buffer object target to be retrieved.
188
 * \param error  the GL error to record if target is illegal.
189 190 191
 * \return   pointer to the buffer object bound to \c target in the
 *           specified context or \c NULL if \c target is invalid.
 */
Brian Paul's avatar
Brian Paul committed
192
static inline struct gl_buffer_object *
193 194
get_buffer(struct gl_context *ctx, const char *func, GLenum target,
           GLenum error)
195 196
{
   struct gl_buffer_object **bufObj = get_buffer_target(ctx, target);
197 198 199 200 201 202 203

   if (!bufObj) {
      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
      return NULL;
   }

   if (!_mesa_is_bufferobj(*bufObj)) {
204
      _mesa_error(ctx, error, "%s(no buffer bound)", func);
205 206 207 208
      return NULL;
   }

   return *bufObj;
209 210 211
}


212 213 214 215 216 217
/**
 * Convert a GLbitfield describing the mapped buffer access flags
 * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY.
 */
static GLenum
simplified_access_mode(struct gl_context *ctx, GLbitfield access)
218
{
219 220 221 222 223 224 225 226 227 228 229
   const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
   if ((access & rwFlags) == rwFlags)
      return GL_READ_WRITE;
   if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT)
      return GL_READ_ONLY;
   if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT)
      return GL_WRITE_ONLY;

   /* Otherwise, AccessFlags is zero (the default state).
    *
    * Table 2.6 on page 31 (page 44 of the PDF) of the OpenGL 1.5 spec says:
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
    *
    * Name           Type  Initial Value  Legal Values
    * ...            ...   ...            ...
    * BUFFER_ACCESS  enum  READ_WRITE     READ_ONLY, WRITE_ONLY
    *                                     READ_WRITE
    *
    * However, table 6.8 in the GL_OES_mapbuffer extension says:
    *
    * Get Value         Type Get Command          Value          Description
    * ---------         ---- -----------          -----          -----------
    * BUFFER_ACCESS_OES Z1   GetBufferParameteriv WRITE_ONLY_OES buffer map flag
    *
    * The difference is because GL_OES_mapbuffer only supports mapping buffers
    * write-only.
    */
245
   assert(access == 0);
246

247
   return _mesa_is_gles(ctx) ? GL_WRITE_ONLY : GL_READ_WRITE;
248 249 250
}


251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
/**
 * Test if the buffer is mapped, and if so, if the mapped range overlaps the
 * given range.
 * The regions do not overlap if and only if the end of the given
 * region is before the mapped region or the start of the given region
 * is after the mapped region.
 *
 * \param obj     Buffer object target on which to operate.
 * \param offset  Offset of the first byte of the subdata range.
 * \param size    Size, in bytes, of the subdata range.
 * \return   true if ranges overlap, false otherwise
 *
 */
static bool
bufferobj_range_mapped(const struct gl_buffer_object *obj,
                       GLintptr offset, GLsizeiptr size)
{
268
   if (_mesa_bufferobj_mapped(obj, MAP_USER)) {
269
      const GLintptr end = offset + size;
270 271
      const GLintptr mapEnd = obj->Mappings[MAP_USER].Offset +
                              obj->Mappings[MAP_USER].Length;
272

273
      if (!(end <= obj->Mappings[MAP_USER].Offset || offset >= mapEnd)) {
274 275 276 277 278 279 280
         return true;
      }
   }
   return false;
}


281 282
/**
 * Tests the subdata range parameters and sets the GL error code for
283 284
 * \c glBufferSubDataARB, \c glGetBufferSubDataARB and
 * \c glClearBufferSubData.
285 286
 *
 * \param ctx     GL context.
287
 * \param bufObj  The buffer object.
288 289
 * \param offset  Offset of the first byte of the subdata range.
 * \param size    Size, in bytes, of the subdata range.
290 291
 * \param mappedRange  If true, checks if an overlapping range is mapped.
 *                     If false, checks if buffer is mapped.
Brian Paul's avatar
Brian Paul committed
292
 * \param caller  Name of calling function for recording errors.
293
 * \return   false if error, true otherwise
294
 *
295
 * \sa glBufferSubDataARB, glGetBufferSubDataARB, glClearBufferSubData
296
 */
297 298
static bool
buffer_object_subdata_range_good(struct gl_context *ctx,
299
                                 const struct gl_buffer_object *bufObj,
300 301
                                 GLintptr offset, GLsizeiptr size,
                                 bool mappedRange, const char *caller)
302 303
{
   if (size < 0) {
Brian Paul's avatar
Brian Paul committed
304
      _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller);
305
      return false;
306 307 308
   }

   if (offset < 0) {
Brian Paul's avatar
Brian Paul committed
309
      _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller);
310
      return false;
311 312
   }

Brian's avatar
Brian committed
313
   if (offset + size > bufObj->Size) {
314
      _mesa_error(ctx, GL_INVALID_VALUE,
315
                  "%s(offset %lu + size %lu > buffer size %lu)", caller,
316 317 318
                  (unsigned long) offset,
                  (unsigned long) size,
                  (unsigned long) bufObj->Size);
319
      return false;
320
   }
321

322
   if (bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_PERSISTENT_BIT)
323
      return true;
324

325 326
   if (mappedRange) {
      if (bufferobj_range_mapped(bufObj, offset, size)) {
327 328 329
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "%s(range is mapped without persistent bit)",
                     caller);
330
         return false;
331 332 333
      }
   }
   else {
334
      if (_mesa_bufferobj_mapped(bufObj, MAP_USER)) {
335 336 337
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "%s(buffer is mapped without persistent bit)",
                     caller);
338
         return false;
339
      }
340 341
   }

342
   return true;
343 344 345
}


346 347 348 349 350 351 352 353 354
/**
 * Test the format and type parameters and set the GL error code for
 * \c glClearBufferData and \c glClearBufferSubData.
 *
 * \param ctx             GL context.
 * \param internalformat  Format to which the data is to be converted.
 * \param format          Format of the supplied data.
 * \param type            Type of the supplied data.
 * \param caller          Name of calling function for recording errors.
355
 * \return   If internalformat, format and type are legal the mesa_format
356 357 358 359
 *           corresponding to internalformat, otherwise MESA_FORMAT_NONE.
 *
 * \sa glClearBufferData and glClearBufferSubData
 */
360
static mesa_format
361 362 363 364 365
validate_clear_buffer_format(struct gl_context *ctx,
                             GLenum internalformat,
                             GLenum format, GLenum type,
                             const char *caller)
{
366
   mesa_format mesaFormat;
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
   GLenum errorFormatType;

   mesaFormat = _mesa_validate_texbuffer_format(ctx, internalformat);
   if (mesaFormat == MESA_FORMAT_NONE) {
      _mesa_error(ctx, GL_INVALID_ENUM,
                  "%s(invalid internalformat)", caller);
      return MESA_FORMAT_NONE;
   }

   /* NOTE: not mentioned in ARB_clear_buffer_object but according to
    * EXT_texture_integer there is no conversion between integer and
    * non-integer formats
   */
   if (_mesa_is_enum_format_signed_int(format) !=
       _mesa_is_format_integer_color(mesaFormat)) {
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "%s(integer vs non-integer)", caller);
      return MESA_FORMAT_NONE;
   }

   if (!_mesa_is_color_format(format)) {
      _mesa_error(ctx, GL_INVALID_ENUM,
                  "%s(format is not a color format)", caller);
      return MESA_FORMAT_NONE;
   }

   errorFormatType = _mesa_error_check_format_and_type(ctx, format, type);
   if (errorFormatType != GL_NO_ERROR) {
      _mesa_error(ctx, GL_INVALID_ENUM,
                  "%s(invalid format or type)", caller);
      return MESA_FORMAT_NONE;
   }

   return mesaFormat;
}


/**
 * Convert user-specified clear value to the specified internal format.
 *
 * \param ctx             GL context.
 * \param internalformat  Format to which the data is converted.
 * \param clearValue      Points to the converted clear value.
 * \param format          Format of the supplied data.
 * \param type            Type of the supplied data.
 * \param data            Data which is to be converted to internalformat.
 * \param caller          Name of calling function for recording errors.
 * \return   true if data could be converted, false otherwise.
 *
 * \sa glClearBufferData, glClearBufferSubData
 */
static bool
convert_clear_buffer_data(struct gl_context *ctx,
420
                          mesa_format internalformat,
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
                          GLubyte *clearValue, GLenum format, GLenum type,
                          const GLvoid *data, const char *caller)
{
   GLenum internalformatBase = _mesa_get_format_base_format(internalformat);

   if (_mesa_texstore(ctx, 1, internalformatBase, internalformat,
                      0, &clearValue, 1, 1, 1,
                      format, type, data, &ctx->Unpack)) {
      return true;
   }
   else {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller);
      return false;
   }
}


438 439
/**
 * Allocate and initialize a new buffer object.
440
 *
Brian Paul's avatar
Brian Paul committed
441
 * Default callback for the \c dd_function_table::NewBufferObject() hook.
442
 */
443
static struct gl_buffer_object *
444
_mesa_new_buffer_object(struct gl_context *ctx, GLuint name)
445 446
{
   struct gl_buffer_object *obj;
447 448 449

   (void) ctx;

450
   obj = MALLOC_STRUCT(gl_buffer_object);
451
   _mesa_initialize_buffer_object(ctx, obj, name);
452 453 454 455
   return obj;
}


456 457
/**
 * Delete a buffer object.
458
 *
Brian Paul's avatar
Brian Paul committed
459
 * Default callback for the \c dd_function_table::DeleteBuffer() hook.
460
 */
461
void
Brian Paul's avatar
Brian Paul committed
462 463
_mesa_delete_buffer_object(struct gl_context *ctx,
                           struct gl_buffer_object *bufObj)
464
{
465 466
   (void) ctx;

467
   vbo_delete_minmax_cache(bufObj);
468
   _mesa_align_free(bufObj->Data);
469 470 471 472 473

   /* assign strange values here to help w/ debugging */
   bufObj->RefCount = -1000;
   bufObj->Name = ~0;

474
   mtx_destroy(&bufObj->Mutex);
475
   free(bufObj->Label);
476
   free(bufObj);
477 478 479
}


480 481 482

/**
 * Set ptr to bufObj w/ reference counting.
483 484
 * This is normally only called from the _mesa_reference_buffer_object() macro
 * when there's a real pointer change.
485
 */
486
void
487 488 489
_mesa_reference_buffer_object_(struct gl_context *ctx,
                               struct gl_buffer_object **ptr,
                               struct gl_buffer_object *bufObj)
490
{
491
   if (*ptr) {
492
      /* Unreference the old buffer */
493 494 495
      GLboolean deleteFlag = GL_FALSE;
      struct gl_buffer_object *oldObj = *ptr;

496
      mtx_lock(&oldObj->Mutex);
497
      assert(oldObj->RefCount > 0);
498 499
      oldObj->RefCount--;
      deleteFlag = (oldObj->RefCount == 0);
500
      mtx_unlock(&oldObj->Mutex);
501 502

      if (deleteFlag) {
503
	 assert(ctx->Driver.DeleteBuffer);
504
         ctx->Driver.DeleteBuffer(ctx, oldObj);
505
      }
506 507 508

      *ptr = NULL;
   }
509
   assert(!*ptr);
510 511

   if (bufObj) {
512
      /* reference new buffer */
513
      mtx_lock(&bufObj->Mutex);
514 515 516 517 518 519 520 521 522 523
      if (bufObj->RefCount == 0) {
         /* this buffer's being deleted (look just above) */
         /* Not sure this can every really happen.  Warn if it does. */
         _mesa_problem(NULL, "referencing deleted buffer object");
         *ptr = NULL;
      }
      else {
         bufObj->RefCount++;
         *ptr = bufObj;
      }
524
      mtx_unlock(&bufObj->Mutex);
525 526 527 528
   }
}


529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
/**
 * Get the value of MESA_NO_MINMAX_CACHE.
 */
static bool
get_no_minmax_cache()
{
   static bool read = false;
   static bool disable = false;

   if (!read) {
      disable = env_var_as_boolean("MESA_NO_MINMAX_CACHE", false);
      read = true;
   }

   return disable;
}


547 548 549 550
/**
 * Initialize a buffer object to default values.
 */
void
551 552 553
_mesa_initialize_buffer_object(struct gl_context *ctx,
                               struct gl_buffer_object *obj,
                               GLuint name)
554
{
555
   memset(obj, 0, sizeof(struct gl_buffer_object));
556
   mtx_init(&obj->Mutex, mtx_plain);
557 558
   obj->RefCount = 1;
   obj->Name = name;
559
   obj->Usage = GL_STATIC_DRAW_ARB;
560 561 562

   if (get_no_minmax_cache())
      obj->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
563 564 565
}


566 567 568 569 570 571 572 573 574 575 576

/**
 * Callback called from _mesa_HashWalk()
 */
static void
count_buffer_size(GLuint key, void *data, void *userData)
{
   const struct gl_buffer_object *bufObj =
      (const struct gl_buffer_object *) data;
   GLuint *total = (GLuint *) userData;

577
   (void) key;
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
   *total = *total + bufObj->Size;
}


/**
 * Compute total size (in bytes) of all buffer objects for the given context.
 * For debugging purposes.
 */
GLuint
_mesa_total_buffer_object_memory(struct gl_context *ctx)
{
   GLuint total = 0;

   _mesa_HashWalk(ctx->Shared->BufferObjects, count_buffer_size, &total);

   return total;
}


597 598 599 600 601
/**
 * Allocate space for and store data in a buffer object.  Any data that was
 * previously stored in the buffer object is lost.  If \c data is \c NULL,
 * memory will be allocated, but no copy will occur.
 *
Brian Paul's avatar
Brian Paul committed
602 603
 * This is the default callback for \c dd_function_table::BufferData()
 * Note that all GL error checking will have been done already.
604 605 606 607 608 609 610 611 612
 *
 * \param ctx     GL context.
 * \param target  Buffer object target on which to operate.
 * \param size    Size, in bytes, of the new data store.
 * \param data    Pointer to the data to store in the buffer object.  This
 *                pointer may be \c NULL.
 * \param usage   Hints about how the data will be used.
 * \param bufObj  Object to be used.
 *
613
 * \return GL_TRUE for success, GL_FALSE for failure
614 615
 * \sa glBufferDataARB, dd_function_table::BufferData.
 */
616
static GLboolean
617 618 619
buffer_data_fallback(struct gl_context *ctx, GLenum target, GLsizeiptr size,
                     const GLvoid *data, GLenum usage, GLenum storageFlags,
                     struct gl_buffer_object *bufObj)
620 621 622
{
   void * new_data;

623 624
   (void) target;

625
   _mesa_align_free( bufObj->Data );
626

627
   new_data = _mesa_align_malloc( size, ctx->Const.MinMapBufferAlignment );
628
   if (new_data) {
629
      bufObj->Data = (GLubyte *) new_data;
630 631
      bufObj->Size = size;
      bufObj->Usage = usage;
632
      bufObj->StorageFlags = storageFlags;
633

634
      if (data) {
635
	 memcpy( bufObj->Data, data, size );
636
      }
637 638 639 640 641

      return GL_TRUE;
   }
   else {
      return GL_FALSE;
642 643 644 645 646 647 648 649 650
   }
}


/**
 * Replace data in a subrange of buffer object.  If the data range
 * specified by \c size + \c offset extends beyond the end of the buffer or
 * if \c data is \c NULL, no copy is performed.
 *
Brian Paul's avatar
Brian Paul committed
651 652
 * This is the default callback for \c dd_function_table::BufferSubData()
 * Note that all GL error checking will have been done already.
653 654 655 656 657 658 659 660 661
 *
 * \param ctx     GL context.
 * \param offset  Offset of the first byte to be modified.
 * \param size    Size, in bytes, of the data range.
 * \param data    Pointer to the data to store in the buffer object.
 * \param bufObj  Object to be used.
 *
 * \sa glBufferSubDataARB, dd_function_table::BufferSubData.
 */
662
static void
663 664 665
buffer_sub_data_fallback(struct gl_context *ctx, GLintptr offset,
                         GLsizeiptr size, const GLvoid *data,
                         struct gl_buffer_object *bufObj)
666
{
667
   (void) ctx;
668

669
   /* this should have been caught in _mesa_BufferSubData() */
670
   assert(size + offset <= bufObj->Size);
671 672

   if (bufObj->Data) {
673
      memcpy( (GLubyte *) bufObj->Data + offset, data, size );
674 675 676 677 678 679 680 681 682
   }
}


/**
 * Retrieve data from a subrange of buffer object.  If the data range
 * specified by \c size + \c offset extends beyond the end of the buffer or
 * if \c data is \c NULL, no copy is performed.
 *
Brian Paul's avatar
Brian Paul committed
683 684
 * This is the default callback for \c dd_function_table::GetBufferSubData()
 * Note that all GL error checking will have been done already.
685 686 687
 *
 * \param ctx     GL context.
 * \param target  Buffer object target on which to operate.
Brian Paul's avatar
Brian Paul committed
688
 * \param offset  Offset of the first byte to be fetched.
689
 * \param size    Size, in bytes, of the data range.
Brian Paul's avatar
Brian Paul committed
690
 * \param data    Destination for data
691 692 693 694
 * \param bufObj  Object to be used.
 *
 * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
 */
695
static void
696
_mesa_buffer_get_subdata( struct gl_context *ctx, GLintptrARB offset,
697 698 699
			  GLsizeiptrARB size, GLvoid * data,
			  struct gl_buffer_object * bufObj )
{
700
   (void) ctx;
701

702
   if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) {
703
      memcpy( data, (GLubyte *) bufObj->Data + offset, size );
704 705 706 707
   }
}


708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
/**
 * Clear a subrange of the buffer object with copies of the supplied data.
 * If data is NULL the buffer is filled with zeros.
 *
 * This is the default callback for \c dd_function_table::ClearBufferSubData()
 * Note that all GL error checking will have been done already.
 *
 * \param ctx             GL context.
 * \param offset          Offset of the first byte to be cleared.
 * \param size            Size, in bytes, of the to be cleared range.
 * \param clearValue      Source of the data.
 * \param clearValueSize  Size, in bytes, of the supplied data.
 * \param bufObj          Object to be cleared.
 *
 * \sa glClearBufferSubData, glClearBufferData and
 * dd_function_table::ClearBufferSubData.
 */
725
void
726 727 728 729 730
_mesa_ClearBufferSubData_sw(struct gl_context *ctx,
                            GLintptr offset, GLsizeiptr size,
                            const GLvoid *clearValue,
                            GLsizeiptr clearValueSize,
                            struct gl_buffer_object *bufObj)
731 732 733 734
{
   GLsizeiptr i;
   GLubyte *dest;

735
   assert(ctx->Driver.MapBufferRange);
736 737 738
   dest = ctx->Driver.MapBufferRange(ctx, offset, size,
                                     GL_MAP_WRITE_BIT |
                                     GL_MAP_INVALIDATE_RANGE_BIT,
739
                                     bufObj, MAP_INTERNAL);
740 741 742 743 744 745 746 747 748

   if (!dest) {
      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClearBuffer[Sub]Data");
      return;
   }

   if (clearValue == NULL) {
      /* Clear with zeros, per the spec */
      memset(dest, 0, size);
749
      ctx->Driver.UnmapBuffer(ctx, bufObj, MAP_INTERNAL);
750 751 752 753 754 755 756 757
      return;
   }

   for (i = 0; i < size/clearValueSize; ++i) {
      memcpy(dest, clearValue, clearValueSize);
      dest += clearValueSize;
   }

758
   ctx->Driver.UnmapBuffer(ctx, bufObj, MAP_INTERNAL);
759 760 761
}


762 763 764 765
/**
 * Default fallback for \c dd_function_table::MapBufferRange().
 * Called via glMapBufferRange().
 */
766
static void *
767 768 769 770
map_buffer_range_fallback(struct gl_context *ctx, GLintptr offset,
                          GLsizeiptr length, GLbitfield access,
                          struct gl_buffer_object *bufObj,
                          gl_map_buffer_index index)
771 772
{
   (void) ctx;
773
   assert(!_mesa_bufferobj_mapped(bufObj, index));
774
   /* Just return a direct pointer to the data */
775 776 777 778 779
   bufObj->Mappings[index].Pointer = bufObj->Data + offset;
   bufObj->Mappings[index].Length = length;
   bufObj->Mappings[index].Offset = offset;
   bufObj->Mappings[index].AccessFlags = access;
   return bufObj->Mappings[index].Pointer;
780 781 782 783 784 785 786
}


/**
 * Default fallback for \c dd_function_table::FlushMappedBufferRange().
 * Called via glFlushMappedBufferRange().
 */
787
static void
788 789 790 791
flush_mapped_buffer_range_fallback(struct gl_context *ctx,
                                   GLintptr offset, GLsizeiptr length,
                                   struct gl_buffer_object *obj,
                                   gl_map_buffer_index index)
792 793 794 795 796
{
   (void) ctx;
   (void) offset;
   (void) length;
   (void) obj;
797
   (void) index;
798 799 800 801
   /* no-op */
}


802
/**
803
 * Default callback for \c dd_function_table::UnmapBuffer().
804 805 806 807 808
 *
 * The input parameters will have been already tested for errors.
 *
 * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer
 */
809
static GLboolean
810 811
unmap_buffer_fallback(struct gl_context *ctx, struct gl_buffer_object *bufObj,
                      gl_map_buffer_index index)
812 813 814
{
   (void) ctx;
   /* XXX we might assert here that bufObj->Pointer is non-null */
815 816 817 818
   bufObj->Mappings[index].Pointer = NULL;
   bufObj->Mappings[index].Length = 0;
   bufObj->Mappings[index].Offset = 0;
   bufObj->Mappings[index].AccessFlags = 0x0;
819
   return GL_TRUE;
820 821 822
}


823 824
/**
 * Default fallback for \c dd_function_table::CopyBufferSubData().
825
 * Called via glCopyBufferSubData().
826
 */
827
static void
828 829 830 831 832
copy_buffer_sub_data_fallback(struct gl_context *ctx,
                              struct gl_buffer_object *src,
                              struct gl_buffer_object *dst,
                              GLintptr readOffset, GLintptr writeOffset,
                              GLsizeiptr size)
833
{
834
   GLubyte *srcPtr, *dstPtr;
835

836 837 838
   if (src == dst) {
      srcPtr = dstPtr = ctx->Driver.MapBufferRange(ctx, 0, src->Size,
						   GL_MAP_READ_BIT |
839 840
						   GL_MAP_WRITE_BIT, src,
                                                   MAP_INTERNAL);
841 842 843 844 845 846 847 848

      if (!srcPtr)
	 return;

      srcPtr += readOffset;
      dstPtr += writeOffset;
   } else {
      srcPtr = ctx->Driver.MapBufferRange(ctx, readOffset, size,
849 850
					  GL_MAP_READ_BIT, src,
                                          MAP_INTERNAL);
851 852
      dstPtr = ctx->Driver.MapBufferRange(ctx, writeOffset, size,
					  (GL_MAP_WRITE_BIT |
853 854
					   GL_MAP_INVALIDATE_RANGE_BIT), dst,
                                          MAP_INTERNAL);
855
   }
856

857 858 859
   /* Note: the src and dst regions will never overlap.  Trying to do so
    * would generate GL_INVALID_VALUE earlier.
    */
860
   if (srcPtr && dstPtr)
861
      memcpy(dstPtr, srcPtr, size);
862

863
   ctx->Driver.UnmapBuffer(ctx, src, MAP_INTERNAL);
864
   if (dst != src)
865
      ctx->Driver.UnmapBuffer(ctx, dst, MAP_INTERNAL);
866 867 868 869
}



870 871 872 873
/**
 * Initialize the state associated with buffer objects
 */
void
874
_mesa_init_buffer_objects( struct gl_context *ctx )
875
{
876 877
   GLuint i;

878
   memset(&DummyBufferObject, 0, sizeof(DummyBufferObject));
879
   mtx_init(&DummyBufferObject.Mutex, mtx_plain);
880 881
   DummyBufferObject.RefCount = 1000*1000*1000; /* never delete */

882 883 884 885 886 887 888
   _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj,
                                 ctx->Shared->NullBufferObj);

   _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer,
                                 ctx->Shared->NullBufferObj);
   _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer,
                                 ctx->Shared->NullBufferObj);
889 890 891 892

   _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer,
				 ctx->Shared->NullBufferObj);

893 894 895
   _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer,
                                 ctx->Shared->NullBufferObj);

896 897 898
   _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer,
				 ctx->Shared->NullBufferObj);

899 900 901
   _mesa_reference_buffer_object(ctx, &ctx->DrawIndirectBuffer,
				 ctx->Shared->NullBufferObj);

902 903 904
   _mesa_reference_buffer_object(ctx, &ctx->ParameterBuffer,
				 ctx->Shared->NullBufferObj);

905 906 907
   _mesa_reference_buffer_object(ctx, &ctx->DispatchIndirectBuffer,
				 ctx->Shared->NullBufferObj);

908 909 910
   _mesa_reference_buffer_object(ctx, &ctx->QueryBuffer,
                                 ctx->Shared->NullBufferObj);

911
   for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) {
912 913 914 915 916 917
      _mesa_reference_buffer_object(ctx,
				    &ctx->UniformBufferBindings[i].BufferObject,
				    ctx->Shared->NullBufferObj);
      ctx->UniformBufferBindings[i].Offset = -1;
      ctx->UniformBufferBindings[i].Size = -1;
   }
918

919 920 921 922 923 924 925 926
   for (i = 0; i < MAX_COMBINED_SHADER_STORAGE_BUFFERS; i++) {
      _mesa_reference_buffer_object(ctx,
                                    &ctx->ShaderStorageBufferBindings[i].BufferObject,
                                    ctx->Shared->NullBufferObj);
      ctx->ShaderStorageBufferBindings[i].Offset = -1;
      ctx->ShaderStorageBufferBindings[i].Size = -1;
   }

927 928 929 930
   for (i = 0; i < MAX_COMBINED_ATOMIC_BUFFERS; i++) {
      _mesa_reference_buffer_object(ctx,
				    &ctx->AtomicBufferBindings[i].BufferObject,
				    ctx->Shared->NullBufferObj);
931 932
      ctx->AtomicBufferBindings[i].Offset = 0;
      ctx->AtomicBufferBindings[i].Size = 0;
933
   }
934 935
}

Brian Paul's avatar
Brian Paul committed
936

937
void
938
_mesa_free_buffer_objects( struct gl_context *ctx )
939
{
940 941
   GLuint i;

942 943 944 945
   _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL);

   _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, NULL);
   _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, NULL);
946 947 948

   _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, NULL);

949 950
   _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer, NULL);

951 952
   _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, NULL);

953 954
   _mesa_reference_buffer_object(ctx, &ctx->DrawIndirectBuffer, NULL);

955 956
   _mesa_reference_buffer_object(ctx, &ctx->ParameterBuffer, NULL);

957 958
   _mesa_reference_buffer_object(ctx, &ctx->DispatchIndirectBuffer, NULL);

959 960
   _mesa_reference_buffer_object(ctx, &ctx->QueryBuffer, NULL);

961
   for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) {
962 963 964 965
      _mesa_reference_buffer_object(ctx,
				    &ctx->UniformBufferBindings[i].BufferObject,
				    NULL);
   }
966

967 968 969 970 971 972
   for (i = 0; i < MAX_COMBINED_SHADER_STORAGE_BUFFERS; i++) {
      _mesa_reference_buffer_object(ctx,
                                    &ctx->ShaderStorageBufferBindings[i].BufferObject,
                                    NULL);
   }

973 974 975 976 977 978
   for (i = 0; i < MAX_COMBINED_ATOMIC_BUFFERS; i++) {
      _mesa_reference_buffer_object(ctx,
				    &ctx->AtomicBufferBindings[i].BufferObject,
				    NULL);
   }

979 980
}

981 982 983 984 985
bool
_mesa_handle_bind_buffer_gen(struct gl_context *ctx,
                             GLuint buffer,
                             struct gl_buffer_object **buf_handle,
                             const char *caller)
986 987 988
{
   struct gl_buffer_object *buf = *buf_handle;

989
   if (!buf && (ctx->API == API_OPENGL_CORE)) {
990
      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", caller);
991 992 993
      return false;
   }

994 995 996 997
   if (!buf || buf == &DummyBufferObject) {
      /* If this is a new buffer object id, or one which was generated but
       * never used before, allocate a buffer object now.
       */
998
      assert(ctx->Driver.NewBufferObject);
999
      buf = ctx->Driver.NewBufferObject(ctx, buffer);
1000
      if (!buf) {
1001
	 _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller);
1002
	 return false;
1003 1004 1005 1006
      }
      _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, buf);
      *buf_handle = buf;
   }
1007 1008

   return true;
1009
}
1010

1011 1012
/**
 * Bind the specified target to buffer for the specified context.
1013
 * Called by glBindBuffer() and other functions.
1014 1015
 */
static void
1016 1017
bind_buffer_object(struct gl_context *ctx,
                   struct gl_buffer_object **bindTarget, GLuint buffer)
1018 1019 1020 1021
{
   struct gl_buffer_object *oldBufObj;
   struct gl_buffer_object *newBufObj = NULL;

1022
   assert(bindTarget);
1023 1024

   /* Get pointer to old buffer object (to be unbound) */
1025
   oldBufObj = *bindTarget;
1026
   if (oldBufObj && oldBufObj->Name == buffer && !oldBufObj->DeletePending)
1027 1028 1029 1030 1031 1032 1033 1034 1035
      return;   /* rebinding the same buffer object- no change */

   /*
    * Get pointer to new buffer object (newBufObj)
    */
   if (buffer == 0) {
      /* The spec says there's not a buffer object named 0, but we use
       * one internally because it simplifies things.
       */
1036
      newBufObj = ctx->Shared->NullBufferObj;
1037 1038 1039 1040
   }
   else {
      /* non-default buffer object */
      newBufObj = _mesa_lookup_bufferobj(ctx, buffer);
1041
      if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
1042
                                        &newBufObj, "glBindBuffer"))
1043
         return;
1044
   }
1045

1046
   /* record usage history */
1047
   if (bindTarget == &ctx->Pack.BufferObj) {
1048 1049 1050
      newBufObj->UsageHistory |= USAGE_PIXEL_PACK_BUFFER;
   }

1051 1052
   /* bind new buffer */
   _mesa_reference_buffer_object(ctx, bindTarget, newBufObj);
1053 1054 1055 1056 1057
}


/**
 * Update the default buffer objects in the given context to reference those
1058
 * specified in the shared state and release those referencing the old
1059 1060 1061
 * shared state.
 */
void
1062
_mesa_update_default_objects_buffer_objects(struct gl_context *ctx)
1063 1064 1065 1066
{
   /* Bind the NullBufferObj to remove references to those
    * in the shared context hash table.
    */
1067 1068 1069 1070
   bind_buffer_object(ctx, &ctx->Array.ArrayBufferObj, 0);
   bind_buffer_object(ctx, &ctx->Array.VAO->IndexBufferObj, 0);
   bind_buffer_object(ctx, &ctx->Pack.BufferObj, 0);
   bind_buffer_object(ctx, &ctx->Unpack.BufferObj, 0);
1071 1072
}

1073

Brian's avatar
Brian committed
1074

1075 1076 1077 1078
/**
 * Return the gl_buffer_object for the given ID.
 * Always return NULL for ID 0.
 */
1079
struct gl_buffer_object *
1080
_mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer)
1081 1082 1083 1084 1085 1086 1087 1088
{
   if (buffer == 0)
      return NULL;
   else
      return (struct gl_buffer_object *)
         _mesa_HashLookup(ctx->Shared->BufferObjects, buffer);
}

1089

1090 1091 1092
struct gl_buffer_object *
_mesa_lookup_bufferobj_locked(struct gl_context *ctx, GLuint buffer)
{
1093 1094 1095 1096 1097
   if (buffer == 0)
      return NULL;
   else
      return (struct gl_buffer_object *)
         _mesa_HashLookupLocked(ctx->Shared->BufferObjects, buffer);
1098 1099
}

1100 1101
/**
 * A convenience function for direct state access functions that throws
1102 1103
 * GL_INVALID_OPERATION if buffer is not the name of an existing
 * buffer object.
1104 1105 1106 1107 1108 1109 1110 1111
 */
struct gl_buffer_object *
_mesa_lookup_bufferobj_err(struct gl_context *ctx, GLuint buffer,
                           const char *caller)
{
   struct gl_buffer_object *bufObj;

   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
1112
   if (!bufObj || bufObj == &DummyBufferObject) {
1113
      _mesa_error(ctx, GL_INVALID_OPERATION,
1114 1115 1116
                  "%s(non-existent buffer object %u)", caller, buffer);
      return NULL;
   }
1117 1118 1119 1120

   return bufObj;
}

1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135

/**
 * Look up a buffer object for a multi-bind function.
 *
 * Unlike _mesa_lookup_bufferobj(), this function also takes care
 * of generating an error if the buffer ID is not zero or the name
 * of an existing buffer object.
 *
 * If the buffer ID refers to an existing buffer object, a pointer
 * to the buffer object is returned.  If the ID is zero, a pointer
 * to the shared NullBufferObj is returned.  If the ID is not zero
 * and does not refer to a valid buffer object, this function
 * returns NULL.
 *
 * This function assumes that the caller has already locked the
1136 1137
 * hash table mutex by calling
 * _mesa_HashLockMutex(ctx->Shared->BufferObjects).
1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172
 */
struct gl_buffer_object *
_mesa_multi_bind_lookup_bufferobj(struct gl_context *ctx,
                                  const GLuint *buffers,
                                  GLuint index, const char *caller)
{
   struct gl_buffer_object *bufObj;

   if (buffers[index] != 0) {
      bufObj = _mesa_lookup_bufferobj_locked(ctx, buffers[index]);

      /* The multi-bind functions don't create the buffer objects
         when they don't exist. */
      if (bufObj == &DummyBufferObject)
         bufObj = NULL;
   } else
      bufObj = ctx->Shared->NullBufferObj;

   if (!bufObj) {
      /* The ARB_multi_bind spec says:
       *
       *    "An INVALID_OPERATION error is generated if any value
       *     in <buffers> is not zero or the name of an existing
       *     buffer object (per binding)."
       */
      _mesa_error(ctx, GL_INVALID_OPERATION,
                  "%s(buffers[%u]=%u is not zero or the name "
                  "of an existing buffer object)",
                  caller, index, buffers[index]);
   }

   return bufObj;
}


1173 1174 1175 1176 1177 1178 1179
/**
 * If *ptr points to obj, set ptr = the Null/default buffer object.
 * This is a helper for buffer object deletion.
 * The GL spec says that deleting a buffer object causes it to get
 * unbound from all arrays in the current context.
 */
static void
1180
unbind(struct gl_context *ctx,
1181
       struct gl_vertex_array_object *vao, unsigned index,
1182 1183
       struct gl_buffer_object *obj)
{
1184
   if (vao->BufferBinding[index].BufferObj == obj) {
1185
      _mesa_bind_vertex_buffer(ctx, vao, index, ctx->Shared->NullBufferObj,
1186 1187
                               vao->BufferBinding[index].Offset,
                               vao->BufferBinding[index].Stride);
1188 1189 1190 1191
   }
}


1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
/**
 * Plug default/fallback buffer object functions into the device
 * driver hooks.
 */
void
_mesa_init_buffer_object_functions(struct dd_function_table *driver)
{
   /* GL_ARB_vertex/pixel_buffer_object */
   driver->NewBufferObject = _mesa_new_buffer_object;
   driver->DeleteBuffer = _mesa_delete_buffer_object;
1202
   driver->BufferData = buffer_data_fallback;
1203
   driver->BufferSubData = buffer_sub_data_fallback;
1204
   driver->GetBufferSubData = _mesa_buffer_get_subdata;
1205
   driver->UnmapBuffer = unmap_buffer_fallback;
1206

1207
   /* GL_ARB_clear_buffer_object */
1208
   driver->ClearBufferSubData = _mesa_ClearBufferSubData_sw;
1209

1210
   /* GL_ARB_map_buffer_range */
1211
   driver->MapBufferRange = map_buffer_range_fallback;
1212
   driver->FlushMappedBufferRange = flush_mapped_buffer_range_fallback;
1213 1214

   /* GL_ARB_copy_buffer */
1215
   driver->CopyBufferSubData = copy_buffer_sub_data_fallback;
1216 1217 1218
}


1219 1220 1221 1222 1223 1224 1225 1226 1227
void
_mesa_buffer_unmap_all_mappings(struct gl_context *ctx,
                                struct gl_buffer_object *bufObj)
{
   int i;

   for (i = 0; i < MAP_COUNT; i++) {
      if (_mesa_bufferobj_mapped(bufObj, i)) {
         ctx->Driver.UnmapBuffer(ctx, bufObj, i);
1228
         assert(bufObj->Mappings[i].Pointer == NULL);
1229 1230 1231 1232 1233
         bufObj->Mappings[i].AccessFlags = 0;
      }
   }
}

1234 1235 1236 1237 1238

/**********************************************************************/
/* API Functions                                                      */
/**********************************************************************/

1239
void GLAPIENTRY
1240
_mesa_BindBuffer(GLenum target, GLuint buffer)
1241
{
1242 1243
   GET_CURRENT_CONTEXT(ctx);

1244
   if (MESA_VERBOSE & VERBOSE_API) {
1245
      _mesa_debug(ctx, "glBindBuffer(%s, %u)\n",
1246
                  _mesa_enum_to_string(target), buffer);
1247
   }
1248

1249 1250 1251 1252 1253 1254 1255 1256
   struct gl_buffer_object **bindTarget = get_buffer_target(ctx, target);
   if (!bindTarget) {
      _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target %s)",
                  _mesa_enum_to_string(target));
      return;
   }

   bind_buffer_object(ctx, bindTarget, buffer);
1257 1258
}

1259 1260 1261

/**
 * Delete a set of buffer objects.
1262
 *
1263
 * \param n      Number of buffer objects to delete.
1264
 * \param ids    Array of \c n buffer object IDs.
1265
 */
1266
void GLAPIENTRY
1267
_mesa_DeleteBuffers(GLsizei n, const GLuint *ids)
1268
{
1269
   GET_CURRENT_CONTEXT(ctx);
1270
   GLsizei i;
1271
   FLUSH_VERTICES(ctx, 0);
1272 1273 1274 1275 1276 1277

   if (n < 0) {
      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)");
      return;
   }

1278
   _mesa_HashLockMutex(ctx->Shared->BufferObjects);
1279 1280

   for (i = 0; i < n; i++) {
1281 1282
      struct gl_buffer_object *bufObj =
         _mesa_lookup_bufferobj_locked(ctx, ids[i]);
1283
      if (bufObj) {
1284
         struct gl_vertex_array_object *vao = ctx->Array.VAO;
1285
         GLuint j;
1286

1287
         assert(bufObj->Name == ids[i] || bufObj == &DummyBufferObject);
1288

1289
         _mesa_buffer_unmap_all_mappings(ctx, bufObj);
1290

Brian Paul's avatar
Brian Paul committed
1291
         /* unbind any vertex pointers bound to this buffer */
1292
         for (j = 0; j < ARRAY_SIZE(vao->BufferBinding); j++) {
1293
            unbind(ctx, vao, j, bufObj);
1294
         }
1295

1296
         if (ctx->Array.ArrayBufferObj == bufObj) {
1297
            bind_buffer_object(ctx, &ctx->Array.ArrayBufferObj, 0);
1298
         }
1299
         if (vao->IndexBufferObj == bufObj) {
1300
            bind_buffer_object(ctx, &vao->IndexBufferObj, 0);
1301
         }
1302

1303 1304
         /* unbind ARB_draw_indirect binding point */
         if (ctx->DrawIndirectBuffer == bufObj) {
1305
            bind_buffer_object(ctx, &ctx->DrawIndirectBuffer, 0);
1306 1307
         }

1308 1309
         /* unbind ARB_indirect_parameters binding point */
         if (ctx->ParameterBuffer == bufObj) {
1310
            bind_buffer_object(ctx, &ctx->ParameterBuffer, 0);
1311 1312
         }

1313 1314
         /* unbind ARB_compute_shader binding point */
         if (ctx->DispatchIndirectBuffer == bufObj) {
1315
            bind_buffer_object(ctx, &ctx->DispatchIndirectBuffer, 0);
1316 1317
         }

1318 1319
         /* unbind ARB_copy_buffer binding points */
         if (ctx->CopyReadBuffer == bufObj) {
1320
            bind_buffer_object(ctx, &ctx->CopyReadBuffer, 0);
1321 1322
         }
         if (ctx->CopyWriteBuffer == bufObj) {
1323
            bind_buffer_object(ctx, &ctx->CopyWriteBuffer, 0);
1324 1325
         }

1326
         /* unbind transform feedback binding points */
1327
         if (ctx->TransformFeedback.CurrentBuffer == bufObj) {
1328
            bind_buffer_object(ctx, &ctx->TransformFeedback.CurrentBuffer, 0);
1329
         }
1330
         for (j = 0; j < MAX_FEEDBACK_BUFFERS; j++) {
1331 1332 1333 1334
            if (ctx->TransformFeedback.CurrentObject->Buffers[j] == bufObj) {
               _mesa_BindBufferBase( GL_TRANSFORM_FEEDBACK_BUFFER, j, 0 );
            }
         }
1335

1336 1337 1338 1339 1340 1341 1342
         /* unbind UBO binding points */
         for (j = 0; j < ctx->Const.MaxUniformBufferBindings; j++) {
            if (ctx->UniformBufferBindings[j].BufferObject == bufObj) {
               _mesa_BindBufferBase( GL_UNIFORM_BUFFER, j, 0 );
            }
         }

1343
         if (ctx->UniformBuffer == bufObj) {
1344
            bind_buffer_object(ctx, &ctx->UniformBuffer, 0);
1345 1346
         }

1347 1348 1349 1350 1351 1352 1353 1354
         /* unbind SSBO binding points */
         for (j = 0; j < ctx->Const.MaxShaderStorageBufferBindings; j++) {
            if (ctx->ShaderStorageBufferBindings[j].BufferObject == bufObj) {
               _mesa_BindBufferBase(GL_SHADER_STORAGE_BUFFER, j, 0);
            }
         }

         if (ctx->ShaderStorageBuffer == bufObj) {
1355
            bind_buffer_object(ctx, &ctx->ShaderStorageBuffer, 0);
1356 1357
         }

1358 1359 1360 1361 1362 1363 1364
         /* unbind Atomci Buffer binding points */
         for (j = 0; j < ctx->Const.MaxAtomicBufferBindings; j++) {
            if (ctx->AtomicBufferBindings[j].BufferObject == bufObj) {
               _mesa_BindBufferBase( GL_ATOMIC_COUNTER_BUFFER, j, 0 );
            }
         }

1365
         if (ctx->AtomicBuffer == bufObj) {