bufferobj.c 151 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 "externalobjects.h"
43
#include "mtypes.h"
44 45 46
#include "teximage.h"
#include "glformats.h"
#include "texstore.h"
47
#include "transformfeedback.h"
48
#include "varray.h"
49
#include "util/u_atomic.h"
50

51

52 53 54 55 56
/* Debug flags */
/*#define VBO_DEBUG*/
/*#define BOUNDS_CHECK*/


57 58 59 60 61 62 63 64 65 66
/**
 * 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
67 68
 * updating a buffer created with GL_STATIC_DRAW.  Called via the macro
 * below.
69 70
 */
static void
71
buffer_usage_warning(struct gl_context *ctx, GLuint *id, const char *fmt, ...)
72 73 74 75
{
   va_list args;

   va_start(args, fmt);
76 77 78 79 80
   _mesa_gl_vdebugf(ctx, id,
                    MESA_DEBUG_SOURCE_API,
                    MESA_DEBUG_TYPE_PERFORMANCE,
                    MESA_DEBUG_SEVERITY_MEDIUM,
                    fmt, args);
81 82 83
   va_end(args);
}

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

90

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


98
/**
99 100 101 102
 * 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
103
 *           specified context or \c NULL if \c target is invalid.
104
 */
Brian Paul's avatar
Brian Paul committed
105
static inline struct gl_buffer_object **
106
get_buffer_target(struct gl_context *ctx, GLenum target)
107
{
108 109 110 111 112 113
   /* 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;

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


190 191 192 193
/**
 * 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.
194
 * \param error  the GL error to record if target is illegal.
195 196 197
 * \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
198
static inline struct gl_buffer_object *
199 200
get_buffer(struct gl_context *ctx, const char *func, GLenum target,
           GLenum error)
201 202
{
   struct gl_buffer_object **bufObj = get_buffer_target(ctx, target);
203 204 205 206 207 208 209

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

   if (!_mesa_is_bufferobj(*bufObj)) {
210
      _mesa_error(ctx, error, "%s(no buffer bound)", func);
211 212 213 214
      return NULL;
   }

   return *bufObj;
215 216 217
}


218 219 220 221 222 223
/**
 * 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)
224
{
225 226 227 228 229 230 231 232 233 234 235
   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:
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
    *
    * 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.
    */
251
   assert(access == 0);
252

253
   return _mesa_is_gles(ctx) ? GL_WRITE_ONLY : GL_READ_WRITE;
254 255 256
}


257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
/**
 * 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)
{
274
   if (_mesa_bufferobj_mapped(obj, MAP_USER)) {
275
      const GLintptr end = offset + size;
276 277
      const GLintptr mapEnd = obj->Mappings[MAP_USER].Offset +
                              obj->Mappings[MAP_USER].Length;
278

279
      if (!(end <= obj->Mappings[MAP_USER].Offset || offset >= mapEnd)) {
280 281 282 283 284 285 286
         return true;
      }
   }
   return false;
}


287 288
/**
 * Tests the subdata range parameters and sets the GL error code for
289 290
 * \c glBufferSubDataARB, \c glGetBufferSubDataARB and
 * \c glClearBufferSubData.
291 292
 *
 * \param ctx     GL context.
293
 * \param bufObj  The buffer object.
294 295
 * \param offset  Offset of the first byte of the subdata range.
 * \param size    Size, in bytes, of the subdata range.
296 297
 * \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
298
 * \param caller  Name of calling function for recording errors.
299
 * \return   false if error, true otherwise
300
 *
301
 * \sa glBufferSubDataARB, glGetBufferSubDataARB, glClearBufferSubData
302
 */
303 304
static bool
buffer_object_subdata_range_good(struct gl_context *ctx,
305
                                 const struct gl_buffer_object *bufObj,
306 307
                                 GLintptr offset, GLsizeiptr size,
                                 bool mappedRange, const char *caller)
308 309
{
   if (size < 0) {
Brian Paul's avatar
Brian Paul committed
310
      _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller);
311
      return false;
312 313 314
   }

   if (offset < 0) {
Brian Paul's avatar
Brian Paul committed
315
      _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller);
316
      return false;
317 318
   }

Brian's avatar
Brian committed
319
   if (offset + size > bufObj->Size) {
320
      _mesa_error(ctx, GL_INVALID_VALUE,
321
                  "%s(offset %lu + size %lu > buffer size %lu)", caller,
322 323 324
                  (unsigned long) offset,
                  (unsigned long) size,
                  (unsigned long) bufObj->Size);
325
      return false;
326
   }
327

328
   if (bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_PERSISTENT_BIT)
329
      return true;
330

331 332
   if (mappedRange) {
      if (bufferobj_range_mapped(bufObj, offset, size)) {
333 334 335
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "%s(range is mapped without persistent bit)",
                     caller);
336
         return false;
337 338 339
      }
   }
   else {
340
      if (_mesa_bufferobj_mapped(bufObj, MAP_USER)) {
341 342 343
         _mesa_error(ctx, GL_INVALID_OPERATION,
                     "%s(buffer is mapped without persistent bit)",
                     caller);
344
         return false;
345
      }
346 347
   }

348
   return true;
349 350 351
}


352 353
/**
 * Test the format and type parameters and set the GL error code for
354 355
 * \c glClearBufferData, \c glClearNamedBufferData, \c glClearBufferSubData
 * and \c glClearNamedBufferSubData.
356 357 358 359 360 361
 *
 * \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.
362
 * \return   If internalformat, format and type are legal the mesa_format
363 364
 *           corresponding to internalformat, otherwise MESA_FORMAT_NONE.
 *
365 366
 * \sa glClearBufferData, glClearNamedBufferData, glClearBufferSubData and
 *     glClearNamedBufferSubData.
367
 */
368
static mesa_format
369 370 371 372 373
validate_clear_buffer_format(struct gl_context *ctx,
                             GLenum internalformat,
                             GLenum format, GLenum type,
                             const char *caller)
{
374
   mesa_format mesaFormat;
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
   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)) {
396
      _mesa_error(ctx, GL_INVALID_VALUE,
397 398 399 400 401 402
                  "%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) {
403
      _mesa_error(ctx, GL_INVALID_VALUE,
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
                  "%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,
428
                          mesa_format internalformat,
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
                          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;
   }
}


446 447
/**
 * Allocate and initialize a new buffer object.
448
 *
Brian Paul's avatar
Brian Paul committed
449
 * Default callback for the \c dd_function_table::NewBufferObject() hook.
450
 */
451
static struct gl_buffer_object *
452
_mesa_new_buffer_object(struct gl_context *ctx, GLuint name)
453
{
454 455 456
   struct gl_buffer_object *obj = MALLOC_STRUCT(gl_buffer_object);
   if (!obj)
      return NULL;
457

458
   _mesa_initialize_buffer_object(ctx, obj, name);
459 460 461 462
   return obj;
}


463 464
/**
 * Delete a buffer object.
465
 *
Brian Paul's avatar
Brian Paul committed
466
 * Default callback for the \c dd_function_table::DeleteBuffer() hook.
467
 */
468
void
Brian Paul's avatar
Brian Paul committed
469 470
_mesa_delete_buffer_object(struct gl_context *ctx,
                           struct gl_buffer_object *bufObj)
471
{
472 473
   (void) ctx;

474
   vbo_delete_minmax_cache(bufObj);
475
   _mesa_align_free(bufObj->Data);
476 477 478 479 480

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

481
   simple_mtx_destroy(&bufObj->MinMaxCacheMutex);
482
   free(bufObj->Label);
483
   free(bufObj);
484 485 486
}


487 488 489

/**
 * Set ptr to bufObj w/ reference counting.
490 491
 * This is normally only called from the _mesa_reference_buffer_object() macro
 * when there's a real pointer change.
492
 */
493
void
494 495 496
_mesa_reference_buffer_object_(struct gl_context *ctx,
                               struct gl_buffer_object **ptr,
                               struct gl_buffer_object *bufObj)
497
{
498
   if (*ptr) {
499
      /* Unreference the old buffer */
500 501
      struct gl_buffer_object *oldObj = *ptr;

502
      if (p_atomic_dec_zero(&oldObj->RefCount)) {
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
      p_atomic_inc(&bufObj->RefCount);
514
      *ptr = bufObj;
515 516 517 518
   }
}


519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536
/**
 * 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;
}


537 538 539 540
/**
 * Initialize a buffer object to default values.
 */
void
541 542 543
_mesa_initialize_buffer_object(struct gl_context *ctx,
                               struct gl_buffer_object *obj,
                               GLuint name)
544
{
545
   memset(obj, 0, sizeof(struct gl_buffer_object));
546 547
   obj->RefCount = 1;
   obj->Name = name;
548
   obj->Usage = GL_STATIC_DRAW_ARB;
549

550
   simple_mtx_init(&obj->MinMaxCacheMutex, mtx_plain);
551 552
   if (get_no_minmax_cache())
      obj->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
553 554 555
}


556 557 558 559 560 561 562 563 564 565 566

/**
 * 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;

567
   (void) key;
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
   *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;
}


587 588 589 590 591
/**
 * 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
592 593
 * This is the default callback for \c dd_function_table::BufferData()
 * Note that all GL error checking will have been done already.
594 595 596 597 598 599 600 601 602
 *
 * \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.
 *
603
 * \return GL_TRUE for success, GL_FALSE for failure
604 605
 * \sa glBufferDataARB, dd_function_table::BufferData.
 */
606
static GLboolean
607
buffer_data_fallback(struct gl_context *ctx, GLenum target, GLsizeiptrARB size,
608 609
                     const GLvoid *data, GLenum usage, GLenum storageFlags,
                     struct gl_buffer_object *bufObj)
610 611 612
{
   void * new_data;

613 614
   (void) target;

615
   _mesa_align_free( bufObj->Data );
616

617
   new_data = _mesa_align_malloc( size, ctx->Const.MinMapBufferAlignment );
618
   if (new_data) {
619
      bufObj->Data = (GLubyte *) new_data;
620 621
      bufObj->Size = size;
      bufObj->Usage = usage;
622
      bufObj->StorageFlags = storageFlags;
623

624
      if (data) {
625
	 memcpy( bufObj->Data, data, size );
626
      }
627 628 629 630 631

      return GL_TRUE;
   }
   else {
      return GL_FALSE;
632 633 634 635 636 637 638 639 640
   }
}


/**
 * 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
641 642
 * This is the default callback for \c dd_function_table::BufferSubData()
 * Note that all GL error checking will have been done already.
643 644 645 646 647 648 649 650 651
 *
 * \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.
 */
652
static void
653 654
buffer_sub_data_fallback(struct gl_context *ctx, GLintptrARB offset,
                         GLsizeiptrARB size, const GLvoid *data,
655
                         struct gl_buffer_object *bufObj)
656
{
657
   (void) ctx;
658

659
   /* this should have been caught in _mesa_BufferSubData() */
660
   assert(size + offset <= bufObj->Size);
661 662

   if (bufObj->Data) {
663
      memcpy( (GLubyte *) bufObj->Data + offset, data, size );
664 665 666 667 668 669 670 671 672
   }
}


/**
 * 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
673 674
 * This is the default callback for \c dd_function_table::GetBufferSubData()
 * Note that all GL error checking will have been done already.
675 676 677
 *
 * \param ctx     GL context.
 * \param target  Buffer object target on which to operate.
Brian Paul's avatar
Brian Paul committed
678
 * \param offset  Offset of the first byte to be fetched.
679
 * \param size    Size, in bytes, of the data range.
Brian Paul's avatar
Brian Paul committed
680
 * \param data    Destination for data
681 682 683 684
 * \param bufObj  Object to be used.
 *
 * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
 */
685
static void
686 687 688
buffer_get_subdata(struct gl_context *ctx, GLintptrARB offset,
                   GLsizeiptrARB size, GLvoid *data,
                   struct gl_buffer_object *bufObj )
689
{
690
   (void) ctx;
691

692
   if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) {
693
      memcpy( data, (GLubyte *) bufObj->Data + offset, size );
694 695 696 697
   }
}


698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
/**
 * 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.
 */
715
void
716 717 718 719 720
_mesa_ClearBufferSubData_sw(struct gl_context *ctx,
                            GLintptr offset, GLsizeiptr size,
                            const GLvoid *clearValue,
                            GLsizeiptr clearValueSize,
                            struct gl_buffer_object *bufObj)
721 722 723 724
{
   GLsizeiptr i;
   GLubyte *dest;

725
   assert(ctx->Driver.MapBufferRange);
726 727 728
   dest = ctx->Driver.MapBufferRange(ctx, offset, size,
                                     GL_MAP_WRITE_BIT |
                                     GL_MAP_INVALIDATE_RANGE_BIT,
729
                                     bufObj, MAP_INTERNAL);
730 731 732 733 734 735 736 737 738

   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);
739
      ctx->Driver.UnmapBuffer(ctx, bufObj, MAP_INTERNAL);
740 741 742 743 744 745 746 747
      return;
   }

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

748
   ctx->Driver.UnmapBuffer(ctx, bufObj, MAP_INTERNAL);
749 750 751
}


752 753 754 755
/**
 * Default fallback for \c dd_function_table::MapBufferRange().
 * Called via glMapBufferRange().
 */
756
static void *
757 758 759 760
map_buffer_range_fallback(struct gl_context *ctx, GLintptr offset,
                          GLsizeiptr length, GLbitfield access,
                          struct gl_buffer_object *bufObj,
                          gl_map_buffer_index index)
761 762
{
   (void) ctx;
763
   assert(!_mesa_bufferobj_mapped(bufObj, index));
764
   /* Just return a direct pointer to the data */
765 766 767 768 769
   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;
770 771 772 773 774 775 776
}


/**
 * Default fallback for \c dd_function_table::FlushMappedBufferRange().
 * Called via glFlushMappedBufferRange().
 */
777
static void
778 779 780 781
flush_mapped_buffer_range_fallback(struct gl_context *ctx,
                                   GLintptr offset, GLsizeiptr length,
                                   struct gl_buffer_object *obj,
                                   gl_map_buffer_index index)
782 783 784 785 786
{
   (void) ctx;
   (void) offset;
   (void) length;
   (void) obj;
787
   (void) index;
788 789 790 791
   /* no-op */
}


792
/**
793
 * Default callback for \c dd_function_table::UnmapBuffer().
794 795 796 797 798
 *
 * The input parameters will have been already tested for errors.
 *
 * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer
 */
799
static GLboolean
800 801
unmap_buffer_fallback(struct gl_context *ctx, struct gl_buffer_object *bufObj,
                      gl_map_buffer_index index)
802 803 804
{
   (void) ctx;
   /* XXX we might assert here that bufObj->Pointer is non-null */
805 806 807 808
   bufObj->Mappings[index].Pointer = NULL;
   bufObj->Mappings[index].Length = 0;
   bufObj->Mappings[index].Offset = 0;
   bufObj->Mappings[index].AccessFlags = 0x0;
809
   return GL_TRUE;
810 811 812
}


813 814
/**
 * Default fallback for \c dd_function_table::CopyBufferSubData().
815
 * Called via glCopyBufferSubData().
816
 */
817
static void
818 819 820 821 822
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)
823
{
824
   GLubyte *srcPtr, *dstPtr;
825

826 827 828
   if (src == dst) {
      srcPtr = dstPtr = ctx->Driver.MapBufferRange(ctx, 0, src->Size,
						   GL_MAP_READ_BIT |
829 830
						   GL_MAP_WRITE_BIT, src,
                                                   MAP_INTERNAL);
831 832 833 834 835 836 837 838

      if (!srcPtr)
	 return;

      srcPtr += readOffset;
      dstPtr += writeOffset;
   } else {
      srcPtr = ctx->Driver.MapBufferRange(ctx, readOffset, size,
839 840
					  GL_MAP_READ_BIT, src,
                                          MAP_INTERNAL);
841 842
      dstPtr = ctx->Driver.MapBufferRange(ctx, writeOffset, size,
					  (GL_MAP_WRITE_BIT |
843 844
					   GL_MAP_INVALIDATE_RANGE_BIT), dst,
                                          MAP_INTERNAL);
845
   }
846

847 848 849
   /* Note: the src and dst regions will never overlap.  Trying to do so
    * would generate GL_INVALID_VALUE earlier.
    */
850
   if (srcPtr && dstPtr)
851
      memcpy(dstPtr, srcPtr, size);
852

853
   ctx->Driver.UnmapBuffer(ctx, src, MAP_INTERNAL);
854
   if (dst != src)
855
      ctx->Driver.UnmapBuffer(ctx, dst, MAP_INTERNAL);
856 857 858 859
}



860 861 862 863
/**
 * Initialize the state associated with buffer objects
 */
void
864
_mesa_init_buffer_objects( struct gl_context *ctx )
865
{
866 867
   GLuint i;

868
   memset(&DummyBufferObject, 0, sizeof(DummyBufferObject));
869
   simple_mtx_init(&DummyBufferObject.MinMaxCacheMutex, mtx_plain);
870 871
   DummyBufferObject.RefCount = 1000*1000*1000; /* never delete */

872 873 874 875 876 877 878
   _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);
879 880 881 882

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

883 884 885
   _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer,
                                 ctx->Shared->NullBufferObj);

886 887 888
   _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer,
				 ctx->Shared->NullBufferObj);

889 890 891
   _mesa_reference_buffer_object(ctx, &ctx->DrawIndirectBuffer,
				 ctx->Shared->NullBufferObj);

892 893 894
   _mesa_reference_buffer_object(ctx, &ctx->ParameterBuffer,
				 ctx->Shared->NullBufferObj);

895 896 897
   _mesa_reference_buffer_object(ctx, &ctx->DispatchIndirectBuffer,
				 ctx->Shared->NullBufferObj);

898 899 900
   _mesa_reference_buffer_object(ctx, &ctx->QueryBuffer,
                                 ctx->Shared->NullBufferObj);

901
   for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) {
902 903 904 905 906 907
      _mesa_reference_buffer_object(ctx,
				    &ctx->UniformBufferBindings[i].BufferObject,
				    ctx->Shared->NullBufferObj);
      ctx->UniformBufferBindings[i].Offset = -1;
      ctx->UniformBufferBindings[i].Size = -1;
   }
908

909 910 911 912 913 914 915 916
   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;
   }

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

Brian Paul's avatar
Brian Paul committed
926

927
void
928
_mesa_free_buffer_objects( struct gl_context *ctx )
929
{
930 931
   GLuint i;

932 933 934 935
   _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);
936 937 938

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

939 940
   _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer, NULL);

941 942
   _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, NULL);

943 944
   _mesa_reference_buffer_object(ctx, &ctx->DrawIndirectBuffer, NULL);

945 946
   _mesa_reference_buffer_object(ctx, &ctx->ParameterBuffer, NULL);

947 948
   _mesa_reference_buffer_object(ctx, &ctx->DispatchIndirectBuffer, NULL);

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

951
   for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) {
952 953 954 955
      _mesa_reference_buffer_object(ctx,
				    &ctx->UniformBufferBindings[i].BufferObject,
				    NULL);
   }
956

957 958 959 960 961 962
   for (i = 0; i < MAX_COMBINED_SHADER_STORAGE_BUFFERS; i++) {
      _mesa_reference_buffer_object(ctx,
                                    &ctx->ShaderStorageBufferBindings[i].BufferObject,
                                    NULL);
   }

963 964 965 966 967 968
   for (i = 0; i < MAX_COMBINED_ATOMIC_BUFFERS; i++) {
      _mesa_reference_buffer_object(ctx,
				    &ctx->AtomicBufferBindings[i].BufferObject,
				    NULL);
   }

969 970
}

971 972 973 974 975
bool
_mesa_handle_bind_buffer_gen(struct gl_context *ctx,
                             GLuint buffer,
                             struct gl_buffer_object **buf_handle,
                             const char *caller)
976 977 978
{
   struct gl_buffer_object *buf = *buf_handle;

979
   if (!buf && (ctx->API == API_OPENGL_CORE)) {
980
      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", caller);
981 982 983
      return false;
   }

984 985 986 987
   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.
       */
988
      buf = ctx->Driver.NewBufferObject(ctx, buffer);
989
      if (!buf) {
990
	 _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller);
991
	 return false;
992 993 994 995
      }
      _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, buf);
      *buf_handle = buf;
   }
996 997

   return true;
998
}
999

1000 1001
/**
 * Bind the specified target to buffer for the specified context.
1002
 * Called by glBindBuffer() and other functions.
1003 1004
 */
static void
1005 1006
bind_buffer_object(struct gl_context *ctx,
                   struct gl_buffer_object **bindTarget, GLuint buffer)
1007 1008 1009 1010
{
   struct gl_buffer_object *oldBufObj;
   struct gl_buffer_object *newBufObj = NULL;

1011
   assert(bindTarget);
1012 1013

   /* Get pointer to old buffer object (to be unbound) */
1014
   oldBufObj = *bindTarget;
1015
   if (oldBufObj && oldBufObj->Name == buffer && !oldBufObj->DeletePending)
1016 1017 1018 1019 1020 1021 1022 1023 1024
      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.
       */
1025
      newBufObj = ctx->Shared->NullBufferObj;
1026 1027 1028 1029
   }
   else {
      /* non-default buffer object */
      newBufObj = _mesa_lookup_bufferobj(ctx, buffer);
1030
      if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
1031
                                        &newBufObj, "glBindBuffer"))
1032
         return;
1033
   }
1034

1035
   /* record usage history */
1036
   if (bindTarget == &ctx->Pack.BufferObj) {
1037 1038 1039
      newBufObj->UsageHistory |= USAGE_PIXEL_PACK_BUFFER;
   }

1040 1041
   /* bind new buffer */
   _mesa_reference_buffer_object(ctx, bindTarget, newBufObj);
1042 1043 1044 1045 1046
}


/**
 * Update the default buffer objects in the given context to reference those
1047
 * specified in the shared state and release those referencing the old
1048 1049 1050
 * shared state.
 */
void
1051
_mesa_update_default_objects_buffer_objects(struct gl_context *ctx)
1052 1053 1054 1055
{
   /* Bind the NullBufferObj to remove references to those
    * in the shared context hash table.
    */
1056 1057 1058 1059
   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);
1060 1061
}

1062

Brian's avatar
Brian committed
1063

1064 1065 1066 1067
/**
 * Return the gl_buffer_object for the given ID.
 * Always return NULL for ID 0.
 */
1068
struct gl_buffer_object *
1069
_mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer)
1070 1071 1072 1073 1074 1075 1076 1077
{
   if (buffer == 0)
      return NULL;
   else
      return (struct gl_buffer_object *)
         _mesa_HashLookup(ctx->Shared->BufferObjects, buffer);
}

1078

1079 1080 1081
struct gl_buffer_object *
_mesa_lookup_bufferobj_locked(struct gl_context *ctx, GLuint buffer)
{
1082 1083 1084 1085 1086
   if (buffer == 0)
      return NULL;
   else
      return (struct gl_buffer_object *)
         _mesa_HashLookupLocked(ctx->Shared->BufferObjects, buffer);
1087 1088
}

1089 1090
/**
 * A convenience function for direct state access functions that throws
1091 1092
 * GL_INVALID_OPERATION if buffer is not the name of an existing
 * buffer object.
1093 1094 1095 1096 1097 1098 1099 1100
 */
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);
1101
   if (!bufObj || bufObj == &DummyBufferObject) {
1102
      _mesa_error(ctx, GL_INVALID_OPERATION,
1103 1104 1105
                  "%s(non-existent buffer object %u)", caller, buffer);
      return NULL;
   }
1106 1107 1108 1109

   return bufObj;
}

1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124

/**
 * 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
1125 1126
 * hash table mutex by calling
 * _mesa_HashLockMutex(ctx->Shared->BufferObjects).
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161
 */
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;
}


1162 1163 1164 1165 1166 1167 1168
/**
 * 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
1169
unbind(struct gl_context *ctx,
1170
       struct gl_vertex_array_object *vao, unsigned index,
1171 1172
       struct gl_buffer_object *obj)
{
1173
   if (vao->BufferBinding[index].BufferObj == obj) {
1174
      _mesa_bind_vertex_buffer(ctx, vao, index, ctx->Shared->NullBufferObj,
1175
                               vao->BufferBinding[index].Offset,
1176
                               vao->BufferBinding[index].Stride);
1177 1178 1179 1180
   }
}


1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
/**
 * 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;
1191
   driver->BufferData = buffer_data_fallback;
1192
   driver->BufferSubData = buffer_sub_data_fallback;
1193
   driver->GetBufferSubData = buffer_get_subdata;
1194
   driver->UnmapBuffer = unmap_buffer_fallback;
1195

1196
   /* GL_ARB_clear_buffer_object */
1197
   driver->ClearBufferSubData = _mesa_ClearBufferSubData_sw;
1198

1199
   /* GL_ARB_map_buffer_range */
1200
   driver->MapBufferRange = map_buffer_range_fallback;
1201
   driver->FlushMappedBufferRange = flush_mapped_buffer_range_fallback;
1202 1203

   /* GL_ARB_copy_buffer */
1204
   driver->CopyBufferSubData = copy_buffer_sub_data_fallback;
1205 1206 1207
}


1208 1209 1210 1211
void
_mesa_buffer_unmap_all_mappings(struct gl_context *ctx,
                                struct gl_buffer_object *bufObj)
{
Timothy Arceri's avatar
Timothy Arceri committed
1212
   for (int i = 0; i < MAP_COUNT; i++) {
1213 1214
      if (_mesa_bufferobj_mapped(bufObj, i)) {
         ctx->Driver.UnmapBuffer(ctx, bufObj, i);
1215
         assert(bufObj->Mappings[i].Pointer == NULL);
1216 1217 1218 1219 1220
         bufObj->Mappings[i].AccessFlags = 0;
      }
   }
}

1221 1222 1223 1224 1225

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

1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
void GLAPIENTRY
_mesa_BindBuffer_no_error(GLenum target, GLuint buffer)
{
   GET_CURRENT_CONTEXT(ctx);

   struct gl_buffer_object **bindTarget = get_buffer_target(ctx, target);
   bind_buffer_object(ctx, bindTarget, buffer);
}


1236
void GLAPIENTRY
1237
_mesa_BindBuffer(GLenum target, GLuint buffer)
1238
{
1239 1240
   GET_CURRENT_CONTEXT(ctx);

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

1246 1247 1248 1249 1250 1251 1252 1253
   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);
1254 1255
}

1256
/**
1257
 * Binds a buffer object to a binding point.
1258 1259 1260 1261 1262
 *
 * The caller is responsible for validating the offset,
 * flushing the vertices and updating NewDriverState.
 */
static void
1263 1264 1265 1266 1267 1268
set_buffer_binding(struct gl_context *ctx,
                   struct gl_buffer_binding *binding,
                   struct gl_buffer_object *bufObj,
                   GLintptr offset,
                   GLsizeiptr size,
                   bool autoSize, gl_buffer_usage usage)
1269 1270 1271
{
   _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj);

1272 1273 1274 1275 1276 1277 1278 1279
   binding->Offset = offset;
   binding->Size = size;
   binding->AutomaticSize = autoSize;

   /* If this is a real buffer object, mark it has having been used
    * at some point as an atomic counter buffer.
    */
   if (size >= 0)
1280
      bufObj->UsageHistory |= usage;
1281 1282 1283
}

static void
1284 1285 1286 1287 1288 1289 1290 1291 1292
set_buffer_multi_binding(struct gl_context *ctx,
                         const GLuint *buffers,
                         int idx,
                         const char *caller,
                         struct gl_buffer_binding *binding,
                         GLintptr offset,
                         GLsizeiptr size,
                         bool range,
                         gl_buffer_usage usage)
1293
{
1294 1295 1296 1297 1298
   struct gl_buffer_object *bufObj;
   if (binding->BufferObject && binding->BufferObject->Name == buffers[idx])
      bufObj = binding->BufferObject;
   else
      bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, idx, caller);
1299

1300 1301 1302 1303 1304 1305
   if (bufObj) {
      if (bufObj == ctx->Shared->NullBufferObj)
         set_buffer_binding(ctx, binding, bufObj, -1, -1, !range, usage);
      else
         set_buffer_binding(ctx, binding, bufObj, offset, size, !range, usage);
   }
1306 1307
}

1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330
static void
bind_buffer(struct gl_context *ctx,
            struct gl_buffer_binding *binding,
            struct gl_buffer_object *bufObj,
            GLintptr offset,
            GLsizeiptr size,
            GLboolean autoSize,
            uint64_t driver_state,
            gl_buffer_usage usage)
{
   if (binding->BufferObject == bufObj &&
       binding->Offset == offset &&
       binding->Size == size &&
       binding->AutomaticSize == autoSize) {
      return;
   }

   FLUSH_VERTICES(ctx, 0);
   ctx->NewDriverState |= driver_state;

   set_buffer_binding(ctx, binding, bufObj, offset, size, autoSize, usage);
}

1331 1332 1333
/**
 * Binds a buffer object to a uniform buffer binding point.
 *
1334
 * Unlike set_buffer_binding(), this function also flushes vertices
1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345
 * and updates NewDriverState.  It also checks if the binding
 * has actually changed before updating it.
 */
static void
bind_uniform_buffer(struct gl_context *ctx,
                    GLuint index,
                    struct gl_buffer_object *bufObj,
                    GLintptr offset,
                    GLsizeiptr size,
                    GLboolean autoSize)
{
1346 1347 1348 1349
   bind_buffer(ctx, &ctx->UniformBufferBindings[index],
               bufObj, offset, size, autoSize,
               ctx->DriverFlags.NewUniformBuffer,
               USAGE_UNIFORM_BUFFER);
1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366
}

/**
 * Binds a buffer object to a shader storage buffer binding point.
 *
 * Unlike set_ssbo_binding(), this function also flushes vertices
 * and updates NewDriverState.  It also checks if the binding
 * has actually changed before updating it.
 */
static void
bind_shader_storage_buffer(struct gl_context *ctx,
                           GLuint index,
                           struct gl_buffer_object *bufObj,
                           GLintptr offset,
                           GLsizeiptr size,
                           GLboolean autoSize)
{
1367 1368 1369 1370
   bind_buffer(ctx, &ctx->ShaderStorageBufferBindings[index],
               bufObj, offset, size, autoSize,
               ctx->DriverFlags.NewShaderStorageBuffer,
               USAGE_SHADER_STORAGE_BUFFER);
1371 1372
}

1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384
/**
 * Binds a buffer object to an atomic buffer binding point.
 *
 * Unlike set_atomic_binding(), this function also flushes vertices
 * and updates NewDriverState.  It also checks if the binding
 * has actually changed before updating it.
 */
static void
bind_atomic_buffer(struct gl_context *ctx, unsigned index,
                   struct gl_buffer_object *bufObj, GLintptr offset,
                   GLsizeiptr size, GLboolean autoSize)
{
1385 1386 1387 1388
   bind_buffer(ctx, &ctx->AtomicBufferBindings[index],
               bufObj, offset, size, autoSize,
               ctx->DriverFlags.NewAtomicBuffer,
               USAGE_ATOMIC_COUNTER_BUFFER);
1389 1390
}

1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434
/**
 * Bind a buffer object to a uniform block binding point.
 * As above, but offset = 0.
 */
static void
bind_buffer_base_uniform_buffer(struct gl_context *ctx,
				GLuint index,
				struct gl_buffer_object *bufObj)
{
   if (index >= ctx->Const.MaxUniformBufferBindings) {
      _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index);
      return;
   }

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

   if (bufObj == ctx->Shared->NullBufferObj)
      bind_uniform_buffer(ctx, index, bufObj, -1, -1, GL_TRUE);
   else
      bind_uniform_buffer(ctx, index, bufObj, 0, 0, GL_TRUE);
}

/**
 * Bind a buffer object to a shader storage block binding point.
 * As above, but offset = 0.
 */
static void
bind_buffer_base_shader_storage_buffer(struct gl_context *ctx,
                                       GLuint index,
                                       struct gl_buffer_object *bufObj)
{
   if (index >= ctx->Const.MaxShaderStorageBufferBindings) {
      _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index);
      return;
   }

   _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer, bufObj);

   if (bufObj == ctx->Shared->NullBufferObj)
      bind_shader_storage_buffer(ctx, index, bufObj, -1, -1, GL_TRUE);
   else
      bind_shader_storage_buffer(ctx, index, bufObj, 0, 0, GL_TRUE);
}

1435 1436 1437 1438
/**
 * Bind a buffer object to a shader storage block binding point.
 * As above, but offset = 0.
 */
1439
static void
1440 1441 1442
bind_buffer_base_atomic_buffer(struct gl_context *ctx,
                               GLuint index,
                               struct gl_buffer_object *bufObj)
1443
{
1444 1445
   if (index >= ctx->Const.MaxAtomicBufferBindings) {
      _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index);