17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
37117f1b4Smrg *
4c1f859d4Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
54a49301eSmrg * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
67117f1b4Smrg *
77117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
87117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
97117f1b4Smrg * to deal in the Software without restriction, including without limitation
107117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
117117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
127117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
137117f1b4Smrg *
147117f1b4Smrg * The above copyright notice and this permission notice shall be included
157117f1b4Smrg * in all copies or substantial portions of the Software.
167117f1b4Smrg *
177117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
187117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
247117f1b4Smrg */
257117f1b4Smrg
267117f1b4Smrg
277117f1b4Smrg/**
287117f1b4Smrg * \file bufferobj.c
294a49301eSmrg * \brief Functions for the GL_ARB_vertex/pixel_buffer_object extensions.
307117f1b4Smrg * \author Brian Paul, Ian Romanick
317117f1b4Smrg */
327117f1b4Smrg
33af69d88dSmrg#include <stdbool.h>
34af69d88dSmrg#include <inttypes.h>  /* for PRId64 macro */
3501e04c3fSmrg#include "util/debug.h"
367117f1b4Smrg#include "glheader.h"
373464ebd5Sriastradh#include "enums.h"
387117f1b4Smrg#include "hash.h"
397117f1b4Smrg#include "context.h"
407117f1b4Smrg#include "bufferobj.h"
4101e04c3fSmrg#include "externalobjects.h"
423464ebd5Sriastradh#include "mtypes.h"
43af69d88dSmrg#include "teximage.h"
44af69d88dSmrg#include "glformats.h"
45af69d88dSmrg#include "texstore.h"
46af69d88dSmrg#include "transformfeedback.h"
4701e04c3fSmrg#include "varray.h"
4801e04c3fSmrg#include "util/u_atomic.h"
497ec681f3Smrg#include "util/u_memory.h"
507ec681f3Smrg#include "util/set.h"
517117f1b4Smrg
527117f1b4Smrg
534a49301eSmrg/* Debug flags */
544a49301eSmrg/*#define VBO_DEBUG*/
554a49301eSmrg/*#define BOUNDS_CHECK*/
564a49301eSmrg
574a49301eSmrg
5801e04c3fSmrg/**
5901e04c3fSmrg * We count the number of buffer modification calls to check for
6001e04c3fSmrg * inefficient buffer use.  This is the number of such calls before we
6101e04c3fSmrg * issue a warning.
6201e04c3fSmrg */
6301e04c3fSmrg#define BUFFER_WARNING_CALL_COUNT 4
6401e04c3fSmrg
6501e04c3fSmrg
6601e04c3fSmrg/**
6701e04c3fSmrg * Helper to warn of possible performance issues, such as frequently
6801e04c3fSmrg * updating a buffer created with GL_STATIC_DRAW.  Called via the macro
6901e04c3fSmrg * below.
7001e04c3fSmrg */
7101e04c3fSmrgstatic void
7201e04c3fSmrgbuffer_usage_warning(struct gl_context *ctx, GLuint *id, const char *fmt, ...)
7301e04c3fSmrg{
7401e04c3fSmrg   va_list args;
7501e04c3fSmrg
7601e04c3fSmrg   va_start(args, fmt);
77a8bb7a65Smaya   _mesa_gl_vdebugf(ctx, id,
78a8bb7a65Smaya                    MESA_DEBUG_SOURCE_API,
79a8bb7a65Smaya                    MESA_DEBUG_TYPE_PERFORMANCE,
80a8bb7a65Smaya                    MESA_DEBUG_SEVERITY_MEDIUM,
81a8bb7a65Smaya                    fmt, args);
8201e04c3fSmrg   va_end(args);
8301e04c3fSmrg}
8401e04c3fSmrg
8501e04c3fSmrg#define BUFFER_USAGE_WARNING(CTX, FMT, ...) \
8601e04c3fSmrg   do { \
8701e04c3fSmrg      static GLuint id = 0; \
8801e04c3fSmrg      buffer_usage_warning(CTX, &id, FMT, ##__VA_ARGS__); \
8901e04c3fSmrg   } while (0)
9001e04c3fSmrg
9101e04c3fSmrg
923464ebd5Sriastradh/**
933464ebd5Sriastradh * Used as a placeholder for buffer objects between glGenBuffers() and
943464ebd5Sriastradh * glBindBuffer() so that glIsBuffer() can work correctly.
953464ebd5Sriastradh */
967ec681f3Smrgstatic struct gl_buffer_object DummyBufferObject = {
977ec681f3Smrg   .MinMaxCacheMutex = _SIMPLE_MTX_INITIALIZER_NP,
987ec681f3Smrg   .RefCount = 1000*1000*1000,  /* never delete */
997ec681f3Smrg};
1003464ebd5Sriastradh
1013464ebd5Sriastradh
1024a49301eSmrg/**
1034a49301eSmrg * Return pointer to address of a buffer object target.
1044a49301eSmrg * \param ctx  the GL context
1054a49301eSmrg * \param target  the buffer object target to be retrieved.
1064a49301eSmrg * \return   pointer to pointer to the buffer object bound to \c target in the
1074a49301eSmrg *           specified context or \c NULL if \c target is invalid.
1084a49301eSmrg */
109af69d88dSmrgstatic inline struct gl_buffer_object **
1103464ebd5Sriastradhget_buffer_target(struct gl_context *ctx, GLenum target)
1114a49301eSmrg{
1127ec681f3Smrg   /* Other targets are only supported in desktop OpenGL and OpenGL ES 3.0. */
1137ec681f3Smrg   if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx)) {
1147ec681f3Smrg      switch (target) {
1157ec681f3Smrg      case GL_ARRAY_BUFFER:
1167ec681f3Smrg      case GL_ELEMENT_ARRAY_BUFFER:
1177ec681f3Smrg         break;
1187ec681f3Smrg      case GL_PIXEL_PACK_BUFFER:
1197ec681f3Smrg      case GL_PIXEL_UNPACK_BUFFER:
1207ec681f3Smrg         if (!ctx->Extensions.EXT_pixel_buffer_object)
1217ec681f3Smrg            return NULL;
1227ec681f3Smrg         break;
1237ec681f3Smrg      default:
1247ec681f3Smrg         return NULL;
1257ec681f3Smrg      }
1267ec681f3Smrg   }
127af69d88dSmrg
1284a49301eSmrg   switch (target) {
1294a49301eSmrg   case GL_ARRAY_BUFFER_ARB:
130a8bb7a65Smaya      if (ctx->Array.ArrayBufferObj)
131a8bb7a65Smaya         ctx->Array.ArrayBufferObj->UsageHistory |= USAGE_ARRAY_BUFFER;
1324a49301eSmrg      return &ctx->Array.ArrayBufferObj;
1334a49301eSmrg   case GL_ELEMENT_ARRAY_BUFFER_ARB:
134a8bb7a65Smaya      if (ctx->Array.VAO->IndexBufferObj)
135a8bb7a65Smaya         ctx->Array.VAO->IndexBufferObj->UsageHistory
136a8bb7a65Smaya            |= USAGE_ELEMENT_ARRAY_BUFFER;
137af69d88dSmrg      return &ctx->Array.VAO->IndexBufferObj;
1384a49301eSmrg   case GL_PIXEL_PACK_BUFFER_EXT:
1394a49301eSmrg      return &ctx->Pack.BufferObj;
1404a49301eSmrg   case GL_PIXEL_UNPACK_BUFFER_EXT:
1414a49301eSmrg      return &ctx->Unpack.BufferObj;
1424a49301eSmrg   case GL_COPY_READ_BUFFER:
1433464ebd5Sriastradh      return &ctx->CopyReadBuffer;
1443464ebd5Sriastradh   case GL_COPY_WRITE_BUFFER:
1453464ebd5Sriastradh      return &ctx->CopyWriteBuffer;
14601e04c3fSmrg   case GL_QUERY_BUFFER:
14701e04c3fSmrg      if (_mesa_has_ARB_query_buffer_object(ctx))
14801e04c3fSmrg         return &ctx->QueryBuffer;
14901e04c3fSmrg      break;
150af69d88dSmrg   case GL_DRAW_INDIRECT_BUFFER:
15101e04c3fSmrg      if ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_draw_indirect) ||
15201e04c3fSmrg           _mesa_is_gles31(ctx)) {
153af69d88dSmrg         return &ctx->DrawIndirectBuffer;
154af69d88dSmrg      }
155af69d88dSmrg      break;
15601e04c3fSmrg   case GL_PARAMETER_BUFFER_ARB:
15701e04c3fSmrg      if (_mesa_has_ARB_indirect_parameters(ctx)) {
15801e04c3fSmrg         return &ctx->ParameterBuffer;
15901e04c3fSmrg      }
16001e04c3fSmrg      break;
16101e04c3fSmrg   case GL_DISPATCH_INDIRECT_BUFFER:
16201e04c3fSmrg      if (_mesa_has_compute_shaders(ctx)) {
16301e04c3fSmrg         return &ctx->DispatchIndirectBuffer;
16401e04c3fSmrg      }
16501e04c3fSmrg      break;
1663464ebd5Sriastradh   case GL_TRANSFORM_FEEDBACK_BUFFER:
1673464ebd5Sriastradh      if (ctx->Extensions.EXT_transform_feedback) {
1683464ebd5Sriastradh         return &ctx->TransformFeedback.CurrentBuffer;
1694a49301eSmrg      }
1704a49301eSmrg      break;
1713464ebd5Sriastradh   case GL_TEXTURE_BUFFER:
17201e04c3fSmrg      if (_mesa_has_ARB_texture_buffer_object(ctx) ||
17301e04c3fSmrg          _mesa_has_OES_texture_buffer(ctx)) {
1743464ebd5Sriastradh         return &ctx->Texture.BufferObject;
1754a49301eSmrg      }
1764a49301eSmrg      break;
177af69d88dSmrg   case GL_UNIFORM_BUFFER:
178af69d88dSmrg      if (ctx->Extensions.ARB_uniform_buffer_object) {
179af69d88dSmrg         return &ctx->UniformBuffer;
180af69d88dSmrg      }
181af69d88dSmrg      break;
18201e04c3fSmrg   case GL_SHADER_STORAGE_BUFFER:
1837ec681f3Smrg      if (ctx->Extensions.ARB_shader_storage_buffer_object || _mesa_is_gles31(ctx)) {
18401e04c3fSmrg         return &ctx->ShaderStorageBuffer;
18501e04c3fSmrg      }
18601e04c3fSmrg      break;
187af69d88dSmrg   case GL_ATOMIC_COUNTER_BUFFER:
1887ec681f3Smrg      if (ctx->Extensions.ARB_shader_atomic_counters || _mesa_is_gles31(ctx)) {
189af69d88dSmrg         return &ctx->AtomicBuffer;
190af69d88dSmrg      }
191af69d88dSmrg      break;
19201e04c3fSmrg   case GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD:
19301e04c3fSmrg      if (ctx->Extensions.AMD_pinned_memory) {
19401e04c3fSmrg         return &ctx->ExternalVirtualMemoryBuffer;
19501e04c3fSmrg      }
19601e04c3fSmrg      break;
1974a49301eSmrg   default:
1984a49301eSmrg      return NULL;
1994a49301eSmrg   }
2004a49301eSmrg   return NULL;
2014a49301eSmrg}
2024a49301eSmrg
2034a49301eSmrg
2047117f1b4Smrg/**
2057117f1b4Smrg * Get the buffer object bound to the specified target in a GL context.
2064a49301eSmrg * \param ctx  the GL context
2074a49301eSmrg * \param target  the buffer object target to be retrieved.
208af69d88dSmrg * \param error  the GL error to record if target is illegal.
2094a49301eSmrg * \return   pointer to the buffer object bound to \c target in the
2107117f1b4Smrg *           specified context or \c NULL if \c target is invalid.
2117117f1b4Smrg */
212af69d88dSmrgstatic inline struct gl_buffer_object *
213af69d88dSmrgget_buffer(struct gl_context *ctx, const char *func, GLenum target,
214af69d88dSmrg           GLenum error)
2157117f1b4Smrg{
2164a49301eSmrg   struct gl_buffer_object **bufObj = get_buffer_target(ctx, target);
217af69d88dSmrg
218af69d88dSmrg   if (!bufObj) {
219af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
220af69d88dSmrg      return NULL;
221af69d88dSmrg   }
222af69d88dSmrg
2237ec681f3Smrg   if (!*bufObj) {
224af69d88dSmrg      _mesa_error(ctx, error, "%s(no buffer bound)", func);
225af69d88dSmrg      return NULL;
226af69d88dSmrg   }
227af69d88dSmrg
228af69d88dSmrg   return *bufObj;
2294a49301eSmrg}
2307117f1b4Smrg
2317117f1b4Smrg
2324a49301eSmrg/**
2334a49301eSmrg * Convert a GLbitfield describing the mapped buffer access flags
2344a49301eSmrg * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY.
2354a49301eSmrg */
2364a49301eSmrgstatic GLenum
237af69d88dSmrgsimplified_access_mode(struct gl_context *ctx, GLbitfield access)
2384a49301eSmrg{
2394a49301eSmrg   const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
2404a49301eSmrg   if ((access & rwFlags) == rwFlags)
2414a49301eSmrg      return GL_READ_WRITE;
2424a49301eSmrg   if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT)
2434a49301eSmrg      return GL_READ_ONLY;
2444a49301eSmrg   if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT)
2454a49301eSmrg      return GL_WRITE_ONLY;
246af69d88dSmrg
247af69d88dSmrg   /* Otherwise, AccessFlags is zero (the default state).
248af69d88dSmrg    *
249af69d88dSmrg    * Table 2.6 on page 31 (page 44 of the PDF) of the OpenGL 1.5 spec says:
250af69d88dSmrg    *
251af69d88dSmrg    * Name           Type  Initial Value  Legal Values
252af69d88dSmrg    * ...            ...   ...            ...
253af69d88dSmrg    * BUFFER_ACCESS  enum  READ_WRITE     READ_ONLY, WRITE_ONLY
254af69d88dSmrg    *                                     READ_WRITE
255af69d88dSmrg    *
256af69d88dSmrg    * However, table 6.8 in the GL_OES_mapbuffer extension says:
257af69d88dSmrg    *
258af69d88dSmrg    * Get Value         Type Get Command          Value          Description
259af69d88dSmrg    * ---------         ---- -----------          -----          -----------
260af69d88dSmrg    * BUFFER_ACCESS_OES Z1   GetBufferParameteriv WRITE_ONLY_OES buffer map flag
261af69d88dSmrg    *
262af69d88dSmrg    * The difference is because GL_OES_mapbuffer only supports mapping buffers
263af69d88dSmrg    * write-only.
264af69d88dSmrg    */
265af69d88dSmrg   assert(access == 0);
266af69d88dSmrg
267af69d88dSmrg   return _mesa_is_gles(ctx) ? GL_WRITE_ONLY : GL_READ_WRITE;
268af69d88dSmrg}
269af69d88dSmrg
270af69d88dSmrg
271af69d88dSmrg/**
272af69d88dSmrg * Test if the buffer is mapped, and if so, if the mapped range overlaps the
273af69d88dSmrg * given range.
274af69d88dSmrg * The regions do not overlap if and only if the end of the given
275af69d88dSmrg * region is before the mapped region or the start of the given region
276af69d88dSmrg * is after the mapped region.
277af69d88dSmrg *
278af69d88dSmrg * \param obj     Buffer object target on which to operate.
279af69d88dSmrg * \param offset  Offset of the first byte of the subdata range.
280af69d88dSmrg * \param size    Size, in bytes, of the subdata range.
281af69d88dSmrg * \return   true if ranges overlap, false otherwise
282af69d88dSmrg *
283af69d88dSmrg */
284af69d88dSmrgstatic bool
285af69d88dSmrgbufferobj_range_mapped(const struct gl_buffer_object *obj,
286af69d88dSmrg                       GLintptr offset, GLsizeiptr size)
287af69d88dSmrg{
288af69d88dSmrg   if (_mesa_bufferobj_mapped(obj, MAP_USER)) {
289af69d88dSmrg      const GLintptr end = offset + size;
290af69d88dSmrg      const GLintptr mapEnd = obj->Mappings[MAP_USER].Offset +
291af69d88dSmrg                              obj->Mappings[MAP_USER].Length;
292af69d88dSmrg
293af69d88dSmrg      if (!(end <= obj->Mappings[MAP_USER].Offset || offset >= mapEnd)) {
294af69d88dSmrg         return true;
295af69d88dSmrg      }
296af69d88dSmrg   }
297af69d88dSmrg   return false;
2987117f1b4Smrg}
2997117f1b4Smrg
3007117f1b4Smrg
3017117f1b4Smrg/**
3027117f1b4Smrg * Tests the subdata range parameters and sets the GL error code for
303af69d88dSmrg * \c glBufferSubDataARB, \c glGetBufferSubDataARB and
304af69d88dSmrg * \c glClearBufferSubData.
3057117f1b4Smrg *
3067117f1b4Smrg * \param ctx     GL context.
30701e04c3fSmrg * \param bufObj  The buffer object.
3087117f1b4Smrg * \param offset  Offset of the first byte of the subdata range.
3097117f1b4Smrg * \param size    Size, in bytes, of the subdata range.
310af69d88dSmrg * \param mappedRange  If true, checks if an overlapping range is mapped.
311af69d88dSmrg *                     If false, checks if buffer is mapped.
3127117f1b4Smrg * \param caller  Name of calling function for recording errors.
31301e04c3fSmrg * \return   false if error, true otherwise
3147117f1b4Smrg *
315af69d88dSmrg * \sa glBufferSubDataARB, glGetBufferSubDataARB, glClearBufferSubData
3167117f1b4Smrg */
31701e04c3fSmrgstatic bool
31801e04c3fSmrgbuffer_object_subdata_range_good(struct gl_context *ctx,
31901e04c3fSmrg                                 const struct gl_buffer_object *bufObj,
32001e04c3fSmrg                                 GLintptr offset, GLsizeiptr size,
32101e04c3fSmrg                                 bool mappedRange, const char *caller)
3227117f1b4Smrg{
3237117f1b4Smrg   if (size < 0) {
3247117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller);
32501e04c3fSmrg      return false;
3267117f1b4Smrg   }
3277117f1b4Smrg
3287117f1b4Smrg   if (offset < 0) {
3297117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller);
33001e04c3fSmrg      return false;
3317117f1b4Smrg   }
3327117f1b4Smrg
3337117f1b4Smrg   if (offset + size > bufObj->Size) {
3347117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
335af69d88dSmrg                  "%s(offset %lu + size %lu > buffer size %lu)", caller,
336af69d88dSmrg                  (unsigned long) offset,
337af69d88dSmrg                  (unsigned long) size,
338af69d88dSmrg                  (unsigned long) bufObj->Size);
33901e04c3fSmrg      return false;
3407117f1b4Smrg   }
341af69d88dSmrg
342af69d88dSmrg   if (bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_PERSISTENT_BIT)
34301e04c3fSmrg      return true;
344af69d88dSmrg
345af69d88dSmrg   if (mappedRange) {
346af69d88dSmrg      if (bufferobj_range_mapped(bufObj, offset, size)) {
34701e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
34801e04c3fSmrg                     "%s(range is mapped without persistent bit)",
34901e04c3fSmrg                     caller);
35001e04c3fSmrg         return false;
351af69d88dSmrg      }
352af69d88dSmrg   }
353af69d88dSmrg   else {
354af69d88dSmrg      if (_mesa_bufferobj_mapped(bufObj, MAP_USER)) {
35501e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
35601e04c3fSmrg                     "%s(buffer is mapped without persistent bit)",
35701e04c3fSmrg                     caller);
35801e04c3fSmrg         return false;
359af69d88dSmrg      }
3607117f1b4Smrg   }
3617117f1b4Smrg
36201e04c3fSmrg   return true;
3637117f1b4Smrg}
3647117f1b4Smrg
3657117f1b4Smrg
366af69d88dSmrg/**
367af69d88dSmrg * Test the format and type parameters and set the GL error code for
368a8bb7a65Smaya * \c glClearBufferData, \c glClearNamedBufferData, \c glClearBufferSubData
369a8bb7a65Smaya * and \c glClearNamedBufferSubData.
370af69d88dSmrg *
371af69d88dSmrg * \param ctx             GL context.
372af69d88dSmrg * \param internalformat  Format to which the data is to be converted.
373af69d88dSmrg * \param format          Format of the supplied data.
374af69d88dSmrg * \param type            Type of the supplied data.
375af69d88dSmrg * \param caller          Name of calling function for recording errors.
376af69d88dSmrg * \return   If internalformat, format and type are legal the mesa_format
377af69d88dSmrg *           corresponding to internalformat, otherwise MESA_FORMAT_NONE.
378af69d88dSmrg *
379a8bb7a65Smaya * \sa glClearBufferData, glClearNamedBufferData, glClearBufferSubData and
380a8bb7a65Smaya *     glClearNamedBufferSubData.
381af69d88dSmrg */
382af69d88dSmrgstatic mesa_format
383af69d88dSmrgvalidate_clear_buffer_format(struct gl_context *ctx,
384af69d88dSmrg                             GLenum internalformat,
385af69d88dSmrg                             GLenum format, GLenum type,
386af69d88dSmrg                             const char *caller)
387af69d88dSmrg{
388af69d88dSmrg   mesa_format mesaFormat;
389af69d88dSmrg   GLenum errorFormatType;
390af69d88dSmrg
391af69d88dSmrg   mesaFormat = _mesa_validate_texbuffer_format(ctx, internalformat);
392af69d88dSmrg   if (mesaFormat == MESA_FORMAT_NONE) {
393af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
394af69d88dSmrg                  "%s(invalid internalformat)", caller);
395af69d88dSmrg      return MESA_FORMAT_NONE;
396af69d88dSmrg   }
397af69d88dSmrg
398af69d88dSmrg   /* NOTE: not mentioned in ARB_clear_buffer_object but according to
399af69d88dSmrg    * EXT_texture_integer there is no conversion between integer and
400af69d88dSmrg    * non-integer formats
401af69d88dSmrg   */
402af69d88dSmrg   if (_mesa_is_enum_format_signed_int(format) !=
403af69d88dSmrg       _mesa_is_format_integer_color(mesaFormat)) {
404af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
405af69d88dSmrg                  "%s(integer vs non-integer)", caller);
406af69d88dSmrg      return MESA_FORMAT_NONE;
407af69d88dSmrg   }
408af69d88dSmrg
409af69d88dSmrg   if (!_mesa_is_color_format(format)) {
410a8bb7a65Smaya      _mesa_error(ctx, GL_INVALID_VALUE,
411af69d88dSmrg                  "%s(format is not a color format)", caller);
412af69d88dSmrg      return MESA_FORMAT_NONE;
413af69d88dSmrg   }
414af69d88dSmrg
415af69d88dSmrg   errorFormatType = _mesa_error_check_format_and_type(ctx, format, type);
416af69d88dSmrg   if (errorFormatType != GL_NO_ERROR) {
417a8bb7a65Smaya      _mesa_error(ctx, GL_INVALID_VALUE,
418af69d88dSmrg                  "%s(invalid format or type)", caller);
419af69d88dSmrg      return MESA_FORMAT_NONE;
420af69d88dSmrg   }
421af69d88dSmrg
422af69d88dSmrg   return mesaFormat;
423af69d88dSmrg}
424af69d88dSmrg
425af69d88dSmrg
426af69d88dSmrg/**
427af69d88dSmrg * Convert user-specified clear value to the specified internal format.
428af69d88dSmrg *
429af69d88dSmrg * \param ctx             GL context.
430af69d88dSmrg * \param internalformat  Format to which the data is converted.
431af69d88dSmrg * \param clearValue      Points to the converted clear value.
432af69d88dSmrg * \param format          Format of the supplied data.
433af69d88dSmrg * \param type            Type of the supplied data.
434af69d88dSmrg * \param data            Data which is to be converted to internalformat.
435af69d88dSmrg * \param caller          Name of calling function for recording errors.
436af69d88dSmrg * \return   true if data could be converted, false otherwise.
437af69d88dSmrg *
438af69d88dSmrg * \sa glClearBufferData, glClearBufferSubData
439af69d88dSmrg */
440af69d88dSmrgstatic bool
441af69d88dSmrgconvert_clear_buffer_data(struct gl_context *ctx,
442af69d88dSmrg                          mesa_format internalformat,
443af69d88dSmrg                          GLubyte *clearValue, GLenum format, GLenum type,
444af69d88dSmrg                          const GLvoid *data, const char *caller)
445af69d88dSmrg{
446af69d88dSmrg   GLenum internalformatBase = _mesa_get_format_base_format(internalformat);
447af69d88dSmrg
448af69d88dSmrg   if (_mesa_texstore(ctx, 1, internalformatBase, internalformat,
449af69d88dSmrg                      0, &clearValue, 1, 1, 1,
450af69d88dSmrg                      format, type, data, &ctx->Unpack)) {
451af69d88dSmrg      return true;
452af69d88dSmrg   }
453af69d88dSmrg   else {
454af69d88dSmrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller);
455af69d88dSmrg      return false;
456af69d88dSmrg   }
457af69d88dSmrg}
458af69d88dSmrg
459af69d88dSmrg
4607117f1b4Smrg/**
4617117f1b4Smrg * Allocate and initialize a new buffer object.
46201e04c3fSmrg *
4634a49301eSmrg * Default callback for the \c dd_function_table::NewBufferObject() hook.
4647117f1b4Smrg */
4654a49301eSmrgstatic struct gl_buffer_object *
46601e04c3fSmrg_mesa_new_buffer_object(struct gl_context *ctx, GLuint name)
4677117f1b4Smrg{
46801e04c3fSmrg   struct gl_buffer_object *obj = MALLOC_STRUCT(gl_buffer_object);
46901e04c3fSmrg   if (!obj)
47001e04c3fSmrg      return NULL;
4717117f1b4Smrg
47201e04c3fSmrg   _mesa_initialize_buffer_object(ctx, obj, name);
4737117f1b4Smrg   return obj;
4747117f1b4Smrg}
4757117f1b4Smrg
4767117f1b4Smrg
4777117f1b4Smrg/**
4787117f1b4Smrg * Delete a buffer object.
47901e04c3fSmrg *
4804a49301eSmrg * Default callback for the \c dd_function_table::DeleteBuffer() hook.
4817117f1b4Smrg */
48201e04c3fSmrgvoid
4833464ebd5Sriastradh_mesa_delete_buffer_object(struct gl_context *ctx,
4843464ebd5Sriastradh                           struct gl_buffer_object *bufObj)
4857117f1b4Smrg{
4867117f1b4Smrg   (void) ctx;
4877117f1b4Smrg
48801e04c3fSmrg   vbo_delete_minmax_cache(bufObj);
4897ec681f3Smrg   align_free(bufObj->Data);
490c1f859d4Smrg
491c1f859d4Smrg   /* assign strange values here to help w/ debugging */
492c1f859d4Smrg   bufObj->RefCount = -1000;
493c1f859d4Smrg   bufObj->Name = ~0;
494c1f859d4Smrg
49501e04c3fSmrg   simple_mtx_destroy(&bufObj->MinMaxCacheMutex);
496af69d88dSmrg   free(bufObj->Label);
497cdc920a0Smrg   free(bufObj);
4987117f1b4Smrg}
4997117f1b4Smrg
5007117f1b4Smrg
501c1f859d4Smrg
502c1f859d4Smrg/**
503c1f859d4Smrg * Set ptr to bufObj w/ reference counting.
504af69d88dSmrg * This is normally only called from the _mesa_reference_buffer_object() macro
505af69d88dSmrg * when there's a real pointer change.
506c1f859d4Smrg */
5077117f1b4Smrgvoid
508af69d88dSmrg_mesa_reference_buffer_object_(struct gl_context *ctx,
509af69d88dSmrg                               struct gl_buffer_object **ptr,
5107ec681f3Smrg                               struct gl_buffer_object *bufObj,
5117ec681f3Smrg                               bool shared_binding)
5127117f1b4Smrg{
513c1f859d4Smrg   if (*ptr) {
5144a49301eSmrg      /* Unreference the old buffer */
515c1f859d4Smrg      struct gl_buffer_object *oldObj = *ptr;
516c1f859d4Smrg
5177ec681f3Smrg      assert(oldObj->RefCount >= 1);
5187ec681f3Smrg
5197ec681f3Smrg      /* Count references only if the context doesn't own the buffer or if
5207ec681f3Smrg       * ptr is a binding point shared by multiple contexts (such as a texture
5217ec681f3Smrg       * buffer object being a buffer bound within a texture object).
5227ec681f3Smrg       */
5237ec681f3Smrg      if (shared_binding || ctx != oldObj->Ctx) {
5247ec681f3Smrg         if (p_atomic_dec_zero(&oldObj->RefCount)) {
5257ec681f3Smrg            assert(ctx->Driver.DeleteBuffer);
5267ec681f3Smrg            ctx->Driver.DeleteBuffer(ctx, oldObj);
5277ec681f3Smrg         }
5287ec681f3Smrg      } else if (ctx == oldObj->Ctx) {
5297ec681f3Smrg         /* Update the private ref count. */
5307ec681f3Smrg         assert(oldObj->CtxRefCount >= 1);
5317ec681f3Smrg         oldObj->CtxRefCount--;
5327117f1b4Smrg      }
533c1f859d4Smrg
534c1f859d4Smrg      *ptr = NULL;
535c1f859d4Smrg   }
53601e04c3fSmrg   assert(!*ptr);
537c1f859d4Smrg
538c1f859d4Smrg   if (bufObj) {
5394a49301eSmrg      /* reference new buffer */
5407ec681f3Smrg      if (shared_binding || ctx != bufObj->Ctx)
5417ec681f3Smrg         p_atomic_inc(&bufObj->RefCount);
5427ec681f3Smrg      else if (ctx == bufObj->Ctx)
5437ec681f3Smrg         bufObj->CtxRefCount++;
5447ec681f3Smrg
54501e04c3fSmrg      *ptr = bufObj;
54601e04c3fSmrg   }
54701e04c3fSmrg}
54801e04c3fSmrg
54901e04c3fSmrg
55001e04c3fSmrg/**
55101e04c3fSmrg * Get the value of MESA_NO_MINMAX_CACHE.
55201e04c3fSmrg */
55301e04c3fSmrgstatic bool
55401e04c3fSmrgget_no_minmax_cache()
55501e04c3fSmrg{
55601e04c3fSmrg   static bool read = false;
55701e04c3fSmrg   static bool disable = false;
55801e04c3fSmrg
55901e04c3fSmrg   if (!read) {
56001e04c3fSmrg      disable = env_var_as_boolean("MESA_NO_MINMAX_CACHE", false);
56101e04c3fSmrg      read = true;
5627117f1b4Smrg   }
56301e04c3fSmrg
56401e04c3fSmrg   return disable;
5657117f1b4Smrg}
5667117f1b4Smrg
5677117f1b4Smrg
5687117f1b4Smrg/**
5697117f1b4Smrg * Initialize a buffer object to default values.
5707117f1b4Smrg */
5717117f1b4Smrgvoid
57201e04c3fSmrg_mesa_initialize_buffer_object(struct gl_context *ctx,
57301e04c3fSmrg                               struct gl_buffer_object *obj,
57401e04c3fSmrg                               GLuint name)
5757117f1b4Smrg{
576cdc920a0Smrg   memset(obj, 0, sizeof(struct gl_buffer_object));
5777117f1b4Smrg   obj->RefCount = 1;
5787117f1b4Smrg   obj->Name = name;
5797117f1b4Smrg   obj->Usage = GL_STATIC_DRAW_ARB;
58001e04c3fSmrg
58101e04c3fSmrg   simple_mtx_init(&obj->MinMaxCacheMutex, mtx_plain);
58201e04c3fSmrg   if (get_no_minmax_cache())
58301e04c3fSmrg      obj->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
584af69d88dSmrg}
585af69d88dSmrg
586af69d88dSmrg
587af69d88dSmrg
588af69d88dSmrg/**
589af69d88dSmrg * Callback called from _mesa_HashWalk()
590af69d88dSmrg */
591af69d88dSmrgstatic void
5927ec681f3Smrgcount_buffer_size(void *data, void *userData)
593af69d88dSmrg{
594af69d88dSmrg   const struct gl_buffer_object *bufObj =
595af69d88dSmrg      (const struct gl_buffer_object *) data;
596af69d88dSmrg   GLuint *total = (GLuint *) userData;
597af69d88dSmrg
598af69d88dSmrg   *total = *total + bufObj->Size;
599af69d88dSmrg}
600af69d88dSmrg
601af69d88dSmrg
602af69d88dSmrg/**
603af69d88dSmrg * Compute total size (in bytes) of all buffer objects for the given context.
604af69d88dSmrg * For debugging purposes.
605af69d88dSmrg */
606af69d88dSmrgGLuint
607af69d88dSmrg_mesa_total_buffer_object_memory(struct gl_context *ctx)
608af69d88dSmrg{
609af69d88dSmrg   GLuint total = 0;
610af69d88dSmrg
6117ec681f3Smrg   _mesa_HashWalkMaybeLocked(ctx->Shared->BufferObjects, count_buffer_size,
6127ec681f3Smrg                             &total, ctx->BufferObjectsLocked);
613af69d88dSmrg
614af69d88dSmrg   return total;
6157117f1b4Smrg}
6167117f1b4Smrg
6177117f1b4Smrg
6187117f1b4Smrg/**
6197117f1b4Smrg * Allocate space for and store data in a buffer object.  Any data that was
6207117f1b4Smrg * previously stored in the buffer object is lost.  If \c data is \c NULL,
6217117f1b4Smrg * memory will be allocated, but no copy will occur.
6227117f1b4Smrg *
6234a49301eSmrg * This is the default callback for \c dd_function_table::BufferData()
6244a49301eSmrg * Note that all GL error checking will have been done already.
6257117f1b4Smrg *
6267117f1b4Smrg * \param ctx     GL context.
6277117f1b4Smrg * \param target  Buffer object target on which to operate.
6287117f1b4Smrg * \param size    Size, in bytes, of the new data store.
6297117f1b4Smrg * \param data    Pointer to the data to store in the buffer object.  This
6307117f1b4Smrg *                pointer may be \c NULL.
6317117f1b4Smrg * \param usage   Hints about how the data will be used.
6327117f1b4Smrg * \param bufObj  Object to be used.
6337117f1b4Smrg *
6344a49301eSmrg * \return GL_TRUE for success, GL_FALSE for failure
6357117f1b4Smrg * \sa glBufferDataARB, dd_function_table::BufferData.
6367117f1b4Smrg */
6374a49301eSmrgstatic GLboolean
63801e04c3fSmrgbuffer_data_fallback(struct gl_context *ctx, GLenum target, GLsizeiptrARB size,
63901e04c3fSmrg                     const GLvoid *data, GLenum usage, GLenum storageFlags,
64001e04c3fSmrg                     struct gl_buffer_object *bufObj)
6417117f1b4Smrg{
6427117f1b4Smrg   void * new_data;
6437117f1b4Smrg
644af69d88dSmrg   (void) target;
645af69d88dSmrg
6467ec681f3Smrg   align_free( bufObj->Data );
6477117f1b4Smrg
6487ec681f3Smrg   new_data = align_malloc( size, ctx->Const.MinMapBufferAlignment );
6497117f1b4Smrg   if (new_data) {
6507117f1b4Smrg      bufObj->Data = (GLubyte *) new_data;
6517117f1b4Smrg      bufObj->Size = size;
6527117f1b4Smrg      bufObj->Usage = usage;
653af69d88dSmrg      bufObj->StorageFlags = storageFlags;
6547117f1b4Smrg
6557117f1b4Smrg      if (data) {
656cdc920a0Smrg	 memcpy( bufObj->Data, data, size );
6577117f1b4Smrg      }
6584a49301eSmrg
6594a49301eSmrg      return GL_TRUE;
6604a49301eSmrg   }
6614a49301eSmrg   else {
6624a49301eSmrg      return GL_FALSE;
6637117f1b4Smrg   }
6647117f1b4Smrg}
6657117f1b4Smrg
6667117f1b4Smrg
6677117f1b4Smrg/**
6687117f1b4Smrg * Replace data in a subrange of buffer object.  If the data range
6697117f1b4Smrg * specified by \c size + \c offset extends beyond the end of the buffer or
6707117f1b4Smrg * if \c data is \c NULL, no copy is performed.
6717117f1b4Smrg *
6724a49301eSmrg * This is the default callback for \c dd_function_table::BufferSubData()
6734a49301eSmrg * Note that all GL error checking will have been done already.
6747117f1b4Smrg *
6757117f1b4Smrg * \param ctx     GL context.
6767117f1b4Smrg * \param offset  Offset of the first byte to be modified.
6777117f1b4Smrg * \param size    Size, in bytes, of the data range.
6787117f1b4Smrg * \param data    Pointer to the data to store in the buffer object.
6797117f1b4Smrg * \param bufObj  Object to be used.
6807117f1b4Smrg *
6817117f1b4Smrg * \sa glBufferSubDataARB, dd_function_table::BufferSubData.
6827117f1b4Smrg */
6834a49301eSmrgstatic void
68401e04c3fSmrgbuffer_sub_data_fallback(struct gl_context *ctx, GLintptrARB offset,
68501e04c3fSmrg                         GLsizeiptrARB size, const GLvoid *data,
68601e04c3fSmrg                         struct gl_buffer_object *bufObj)
6877117f1b4Smrg{
688af69d88dSmrg   (void) ctx;
6897117f1b4Smrg
6907117f1b4Smrg   /* this should have been caught in _mesa_BufferSubData() */
69101e04c3fSmrg   assert(size + offset <= bufObj->Size);
6927117f1b4Smrg
6937117f1b4Smrg   if (bufObj->Data) {
694cdc920a0Smrg      memcpy( (GLubyte *) bufObj->Data + offset, data, size );
6957117f1b4Smrg   }
6967117f1b4Smrg}
6977117f1b4Smrg
6987117f1b4Smrg
6997117f1b4Smrg/**
7007117f1b4Smrg * Retrieve data from a subrange of buffer object.  If the data range
7017117f1b4Smrg * specified by \c size + \c offset extends beyond the end of the buffer or
7027117f1b4Smrg * if \c data is \c NULL, no copy is performed.
7037117f1b4Smrg *
7044a49301eSmrg * This is the default callback for \c dd_function_table::GetBufferSubData()
7054a49301eSmrg * Note that all GL error checking will have been done already.
7067117f1b4Smrg *
7077117f1b4Smrg * \param ctx     GL context.
7087117f1b4Smrg * \param target  Buffer object target on which to operate.
7094a49301eSmrg * \param offset  Offset of the first byte to be fetched.
7107117f1b4Smrg * \param size    Size, in bytes, of the data range.
7114a49301eSmrg * \param data    Destination for data
7127117f1b4Smrg * \param bufObj  Object to be used.
7137117f1b4Smrg *
7147117f1b4Smrg * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
7157117f1b4Smrg */
7164a49301eSmrgstatic void
71701e04c3fSmrgbuffer_get_subdata(struct gl_context *ctx, GLintptrARB offset,
71801e04c3fSmrg                   GLsizeiptrARB size, GLvoid *data,
71901e04c3fSmrg                   struct gl_buffer_object *bufObj )
7207117f1b4Smrg{
721af69d88dSmrg   (void) ctx;
7227117f1b4Smrg
7237117f1b4Smrg   if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) {
724cdc920a0Smrg      memcpy( data, (GLubyte *) bufObj->Data + offset, size );
7257117f1b4Smrg   }
7267117f1b4Smrg}
7277117f1b4Smrg
7287117f1b4Smrg
7297117f1b4Smrg/**
730af69d88dSmrg * Clear a subrange of the buffer object with copies of the supplied data.
731af69d88dSmrg * If data is NULL the buffer is filled with zeros.
7327117f1b4Smrg *
733af69d88dSmrg * This is the default callback for \c dd_function_table::ClearBufferSubData()
734af69d88dSmrg * Note that all GL error checking will have been done already.
7357117f1b4Smrg *
736af69d88dSmrg * \param ctx             GL context.
737af69d88dSmrg * \param offset          Offset of the first byte to be cleared.
738af69d88dSmrg * \param size            Size, in bytes, of the to be cleared range.
739af69d88dSmrg * \param clearValue      Source of the data.
740af69d88dSmrg * \param clearValueSize  Size, in bytes, of the supplied data.
741af69d88dSmrg * \param bufObj          Object to be cleared.
7427117f1b4Smrg *
743af69d88dSmrg * \sa glClearBufferSubData, glClearBufferData and
744af69d88dSmrg * dd_function_table::ClearBufferSubData.
7457117f1b4Smrg */
746af69d88dSmrgvoid
74701e04c3fSmrg_mesa_ClearBufferSubData_sw(struct gl_context *ctx,
74801e04c3fSmrg                            GLintptr offset, GLsizeiptr size,
74901e04c3fSmrg                            const GLvoid *clearValue,
75001e04c3fSmrg                            GLsizeiptr clearValueSize,
75101e04c3fSmrg                            struct gl_buffer_object *bufObj)
7527117f1b4Smrg{
753af69d88dSmrg   GLsizeiptr i;
754af69d88dSmrg   GLubyte *dest;
755af69d88dSmrg
75601e04c3fSmrg   assert(ctx->Driver.MapBufferRange);
757af69d88dSmrg   dest = ctx->Driver.MapBufferRange(ctx, offset, size,
758af69d88dSmrg                                     GL_MAP_WRITE_BIT |
759af69d88dSmrg                                     GL_MAP_INVALIDATE_RANGE_BIT,
760af69d88dSmrg                                     bufObj, MAP_INTERNAL);
761af69d88dSmrg
762af69d88dSmrg   if (!dest) {
763af69d88dSmrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClearBuffer[Sub]Data");
764af69d88dSmrg      return;
7657117f1b4Smrg   }
766af69d88dSmrg
767af69d88dSmrg   if (clearValue == NULL) {
768af69d88dSmrg      /* Clear with zeros, per the spec */
769af69d88dSmrg      memset(dest, 0, size);
770af69d88dSmrg      ctx->Driver.UnmapBuffer(ctx, bufObj, MAP_INTERNAL);
771af69d88dSmrg      return;
772af69d88dSmrg   }
773af69d88dSmrg
774af69d88dSmrg   for (i = 0; i < size/clearValueSize; ++i) {
775af69d88dSmrg      memcpy(dest, clearValue, clearValueSize);
776af69d88dSmrg      dest += clearValueSize;
777af69d88dSmrg   }
778af69d88dSmrg
779af69d88dSmrg   ctx->Driver.UnmapBuffer(ctx, bufObj, MAP_INTERNAL);
7807117f1b4Smrg}
7817117f1b4Smrg
7827117f1b4Smrg
7837117f1b4Smrg/**
7844a49301eSmrg * Default fallback for \c dd_function_table::MapBufferRange().
7854a49301eSmrg * Called via glMapBufferRange().
7864a49301eSmrg */
7874a49301eSmrgstatic void *
78801e04c3fSmrgmap_buffer_range_fallback(struct gl_context *ctx, GLintptr offset,
78901e04c3fSmrg                          GLsizeiptr length, GLbitfield access,
79001e04c3fSmrg                          struct gl_buffer_object *bufObj,
79101e04c3fSmrg                          gl_map_buffer_index index)
7924a49301eSmrg{
7934a49301eSmrg   (void) ctx;
794af69d88dSmrg   assert(!_mesa_bufferobj_mapped(bufObj, index));
7954a49301eSmrg   /* Just return a direct pointer to the data */
796af69d88dSmrg   bufObj->Mappings[index].Pointer = bufObj->Data + offset;
797af69d88dSmrg   bufObj->Mappings[index].Length = length;
798af69d88dSmrg   bufObj->Mappings[index].Offset = offset;
799af69d88dSmrg   bufObj->Mappings[index].AccessFlags = access;
800af69d88dSmrg   return bufObj->Mappings[index].Pointer;
8014a49301eSmrg}
8024a49301eSmrg
8034a49301eSmrg
8044a49301eSmrg/**
8054a49301eSmrg * Default fallback for \c dd_function_table::FlushMappedBufferRange().
8064a49301eSmrg * Called via glFlushMappedBufferRange().
8074a49301eSmrg */
8084a49301eSmrgstatic void
80901e04c3fSmrgflush_mapped_buffer_range_fallback(struct gl_context *ctx,
81001e04c3fSmrg                                   GLintptr offset, GLsizeiptr length,
81101e04c3fSmrg                                   struct gl_buffer_object *obj,
81201e04c3fSmrg                                   gl_map_buffer_index index)
8134a49301eSmrg{
8144a49301eSmrg   (void) ctx;
8154a49301eSmrg   (void) offset;
8164a49301eSmrg   (void) length;
8174a49301eSmrg   (void) obj;
81801e04c3fSmrg   (void) index;
8194a49301eSmrg   /* no-op */
8204a49301eSmrg}
8214a49301eSmrg
8224a49301eSmrg
8234a49301eSmrg/**
82401e04c3fSmrg * Default callback for \c dd_function_table::UnmapBuffer().
8257117f1b4Smrg *
8267117f1b4Smrg * The input parameters will have been already tested for errors.
8277117f1b4Smrg *
8287117f1b4Smrg * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer
8297117f1b4Smrg */
8304a49301eSmrgstatic GLboolean
83101e04c3fSmrgunmap_buffer_fallback(struct gl_context *ctx, struct gl_buffer_object *bufObj,
83201e04c3fSmrg                      gl_map_buffer_index index)
8337117f1b4Smrg{
8347117f1b4Smrg   (void) ctx;
8357117f1b4Smrg   /* XXX we might assert here that bufObj->Pointer is non-null */
836af69d88dSmrg   bufObj->Mappings[index].Pointer = NULL;
837af69d88dSmrg   bufObj->Mappings[index].Length = 0;
838af69d88dSmrg   bufObj->Mappings[index].Offset = 0;
839af69d88dSmrg   bufObj->Mappings[index].AccessFlags = 0x0;
8407117f1b4Smrg   return GL_TRUE;
8417117f1b4Smrg}
8427117f1b4Smrg
8437117f1b4Smrg
8444a49301eSmrg/**
8454a49301eSmrg * Default fallback for \c dd_function_table::CopyBufferSubData().
846af69d88dSmrg * Called via glCopyBufferSubData().
8474a49301eSmrg */
8484a49301eSmrgstatic void
84901e04c3fSmrgcopy_buffer_sub_data_fallback(struct gl_context *ctx,
85001e04c3fSmrg                              struct gl_buffer_object *src,
85101e04c3fSmrg                              struct gl_buffer_object *dst,
85201e04c3fSmrg                              GLintptr readOffset, GLintptr writeOffset,
85301e04c3fSmrg                              GLsizeiptr size)
8544a49301eSmrg{
8554a49301eSmrg   GLubyte *srcPtr, *dstPtr;
8564a49301eSmrg
857af69d88dSmrg   if (src == dst) {
858af69d88dSmrg      srcPtr = dstPtr = ctx->Driver.MapBufferRange(ctx, 0, src->Size,
859af69d88dSmrg						   GL_MAP_READ_BIT |
860af69d88dSmrg						   GL_MAP_WRITE_BIT, src,
861af69d88dSmrg                                                   MAP_INTERNAL);
862af69d88dSmrg
863af69d88dSmrg      if (!srcPtr)
864af69d88dSmrg	 return;
865af69d88dSmrg
866af69d88dSmrg      srcPtr += readOffset;
867af69d88dSmrg      dstPtr += writeOffset;
868af69d88dSmrg   } else {
869af69d88dSmrg      srcPtr = ctx->Driver.MapBufferRange(ctx, readOffset, size,
870af69d88dSmrg					  GL_MAP_READ_BIT, src,
871af69d88dSmrg                                          MAP_INTERNAL);
872af69d88dSmrg      dstPtr = ctx->Driver.MapBufferRange(ctx, writeOffset, size,
873af69d88dSmrg					  (GL_MAP_WRITE_BIT |
874af69d88dSmrg					   GL_MAP_INVALIDATE_RANGE_BIT), dst,
875af69d88dSmrg                                          MAP_INTERNAL);
876af69d88dSmrg   }
877af69d88dSmrg
878af69d88dSmrg   /* Note: the src and dst regions will never overlap.  Trying to do so
879af69d88dSmrg    * would generate GL_INVALID_VALUE earlier.
880af69d88dSmrg    */
8814a49301eSmrg   if (srcPtr && dstPtr)
882af69d88dSmrg      memcpy(dstPtr, srcPtr, size);
8834a49301eSmrg
884af69d88dSmrg   ctx->Driver.UnmapBuffer(ctx, src, MAP_INTERNAL);
885af69d88dSmrg   if (dst != src)
886af69d88dSmrg      ctx->Driver.UnmapBuffer(ctx, dst, MAP_INTERNAL);
8874a49301eSmrg}
8884a49301eSmrg
8894a49301eSmrg
8904a49301eSmrg
8917117f1b4Smrg/**
8927117f1b4Smrg * Initialize the state associated with buffer objects
8937117f1b4Smrg */
8947117f1b4Smrgvoid
8953464ebd5Sriastradh_mesa_init_buffer_objects( struct gl_context *ctx )
8967117f1b4Smrg{
897af69d88dSmrg   GLuint i;
898af69d88dSmrg
899af69d88dSmrg   for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) {
900af69d88dSmrg      _mesa_reference_buffer_object(ctx,
901af69d88dSmrg				    &ctx->UniformBufferBindings[i].BufferObject,
9027ec681f3Smrg				    NULL);
903af69d88dSmrg      ctx->UniformBufferBindings[i].Offset = -1;
904af69d88dSmrg      ctx->UniformBufferBindings[i].Size = -1;
905af69d88dSmrg   }
906af69d88dSmrg
90701e04c3fSmrg   for (i = 0; i < MAX_COMBINED_SHADER_STORAGE_BUFFERS; i++) {
90801e04c3fSmrg      _mesa_reference_buffer_object(ctx,
90901e04c3fSmrg                                    &ctx->ShaderStorageBufferBindings[i].BufferObject,
9107ec681f3Smrg                                    NULL);
91101e04c3fSmrg      ctx->ShaderStorageBufferBindings[i].Offset = -1;
91201e04c3fSmrg      ctx->ShaderStorageBufferBindings[i].Size = -1;
91301e04c3fSmrg   }
91401e04c3fSmrg
915af69d88dSmrg   for (i = 0; i < MAX_COMBINED_ATOMIC_BUFFERS; i++) {
916af69d88dSmrg      _mesa_reference_buffer_object(ctx,
917af69d88dSmrg				    &ctx->AtomicBufferBindings[i].BufferObject,
9187ec681f3Smrg				    NULL);
91901e04c3fSmrg      ctx->AtomicBufferBindings[i].Offset = 0;
92001e04c3fSmrg      ctx->AtomicBufferBindings[i].Size = 0;
921af69d88dSmrg   }
9224a49301eSmrg}
9234a49301eSmrg
9247ec681f3Smrg/**
9257ec681f3Smrg * Detach the context from the buffer to re-enable buffer reference counting
9267ec681f3Smrg * for this context.
9277ec681f3Smrg */
9287ec681f3Smrgstatic void
9297ec681f3Smrgdetach_ctx_from_buffer(struct gl_context *ctx, struct gl_buffer_object *buf)
9307ec681f3Smrg{
9317ec681f3Smrg   assert(buf->Ctx == ctx);
9327ec681f3Smrg
9337ec681f3Smrg   /* Move private non-atomic context references to the global ref count. */
9347ec681f3Smrg   p_atomic_add(&buf->RefCount, buf->CtxRefCount);
9357ec681f3Smrg   buf->CtxRefCount = 0;
9367ec681f3Smrg   buf->Ctx = NULL;
9377ec681f3Smrg
9387ec681f3Smrg   /* Remove the context reference where the context holds one
9397ec681f3Smrg    * reference for the lifetime of the buffer ID to skip refcount
9407ec681f3Smrg    * atomics instead of each binding point holding the reference.
9417ec681f3Smrg    */
9427ec681f3Smrg   _mesa_reference_buffer_object(ctx, &buf, NULL);
9437ec681f3Smrg}
9447ec681f3Smrg
9457ec681f3Smrg/**
9467ec681f3Smrg * Zombie buffers are buffers that were created by one context and deleted
9477ec681f3Smrg * by another context. The creating context holds a global reference for each
9487ec681f3Smrg * buffer it created that can't be unreferenced when another context deletes
9497ec681f3Smrg * it. Such a buffer becomes a zombie, which means that it's no longer usable
9507ec681f3Smrg * by OpenGL, but the creating context still holds its global reference of
9517ec681f3Smrg * the buffer. Only the creating context can remove the reference, which is
9527ec681f3Smrg * what this function does.
9537ec681f3Smrg *
9547ec681f3Smrg * For all zombie buffers, decrement the reference count if the current
9557ec681f3Smrg * context owns the buffer.
9567ec681f3Smrg */
9577ec681f3Smrgstatic void
9587ec681f3Smrgunreference_zombie_buffers_for_ctx(struct gl_context *ctx)
9597ec681f3Smrg{
9607ec681f3Smrg   /* It's assumed that the mutex of Shared->BufferObjects is locked. */
9617ec681f3Smrg   set_foreach(ctx->Shared->ZombieBufferObjects, entry) {
9627ec681f3Smrg      struct gl_buffer_object *buf = (struct gl_buffer_object *)entry->key;
9637ec681f3Smrg
9647ec681f3Smrg      if (buf->Ctx == ctx) {
9657ec681f3Smrg         _mesa_set_remove(ctx->Shared->ZombieBufferObjects, entry);
9667ec681f3Smrg         detach_ctx_from_buffer(ctx, buf);
9677ec681f3Smrg      }
9687ec681f3Smrg   }
9697ec681f3Smrg}
9707ec681f3Smrg
9717ec681f3Smrg/**
9727ec681f3Smrg * When a context creates buffers, it holds a global buffer reference count
9737ec681f3Smrg * for each buffer and doesn't update their RefCount. When the context is
9747ec681f3Smrg * destroyed before the buffers are destroyed, the context must remove
9757ec681f3Smrg * its global reference from the buffers, so that the buffers can live
9767ec681f3Smrg * on their own.
9777ec681f3Smrg *
9787ec681f3Smrg * At this point, the buffers shouldn't be bound in any bounding point owned
9797ec681f3Smrg * by the context. (it would crash if they did)
9807ec681f3Smrg */
9817ec681f3Smrgstatic void
9827ec681f3Smrgdetach_unrefcounted_buffer_from_ctx(void *data, void *userData)
9837ec681f3Smrg{
9847ec681f3Smrg   struct gl_context *ctx = (struct gl_context *)userData;
9857ec681f3Smrg   struct gl_buffer_object *buf = (struct gl_buffer_object *)data;
9867ec681f3Smrg
9877ec681f3Smrg   if (buf->Ctx == ctx) {
9887ec681f3Smrg      /* Detach the current context from live objects. There should be no
9897ec681f3Smrg       * bound buffer in the context at this point, therefore we can just
9907ec681f3Smrg       * unreference the global reference. Other contexts and texture objects
9917ec681f3Smrg       * might still be using the buffer.
9927ec681f3Smrg       */
9937ec681f3Smrg      assert(buf->CtxRefCount == 0);
9947ec681f3Smrg      buf->Ctx = NULL;
9957ec681f3Smrg      _mesa_reference_buffer_object(ctx, &buf, NULL);
9967ec681f3Smrg   }
9977ec681f3Smrg}
9987117f1b4Smrg
9994a49301eSmrgvoid
10003464ebd5Sriastradh_mesa_free_buffer_objects( struct gl_context *ctx )
10014a49301eSmrg{
1002af69d88dSmrg   GLuint i;
1003af69d88dSmrg
10044a49301eSmrg   _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL);
10054a49301eSmrg
10064a49301eSmrg   _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, NULL);
10074a49301eSmrg   _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, NULL);
1008af69d88dSmrg
1009af69d88dSmrg   _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, NULL);
1010af69d88dSmrg
101101e04c3fSmrg   _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer, NULL);
101201e04c3fSmrg
1013af69d88dSmrg   _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, NULL);
1014af69d88dSmrg
1015af69d88dSmrg   _mesa_reference_buffer_object(ctx, &ctx->DrawIndirectBuffer, NULL);
1016af69d88dSmrg
101701e04c3fSmrg   _mesa_reference_buffer_object(ctx, &ctx->ParameterBuffer, NULL);
101801e04c3fSmrg
101901e04c3fSmrg   _mesa_reference_buffer_object(ctx, &ctx->DispatchIndirectBuffer, NULL);
102001e04c3fSmrg
102101e04c3fSmrg   _mesa_reference_buffer_object(ctx, &ctx->QueryBuffer, NULL);
102201e04c3fSmrg
1023af69d88dSmrg   for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) {
1024af69d88dSmrg      _mesa_reference_buffer_object(ctx,
1025af69d88dSmrg				    &ctx->UniformBufferBindings[i].BufferObject,
1026af69d88dSmrg				    NULL);
1027af69d88dSmrg   }
1028af69d88dSmrg
102901e04c3fSmrg   for (i = 0; i < MAX_COMBINED_SHADER_STORAGE_BUFFERS; i++) {
103001e04c3fSmrg      _mesa_reference_buffer_object(ctx,
103101e04c3fSmrg                                    &ctx->ShaderStorageBufferBindings[i].BufferObject,
103201e04c3fSmrg                                    NULL);
103301e04c3fSmrg   }
103401e04c3fSmrg
1035af69d88dSmrg   for (i = 0; i < MAX_COMBINED_ATOMIC_BUFFERS; i++) {
1036af69d88dSmrg      _mesa_reference_buffer_object(ctx,
1037af69d88dSmrg				    &ctx->AtomicBufferBindings[i].BufferObject,
1038af69d88dSmrg				    NULL);
1039af69d88dSmrg   }
1040af69d88dSmrg
10417ec681f3Smrg   _mesa_HashLockMutex(ctx->Shared->BufferObjects);
10427ec681f3Smrg   unreference_zombie_buffers_for_ctx(ctx);
10437ec681f3Smrg   _mesa_HashWalkLocked(ctx->Shared->BufferObjects,
10447ec681f3Smrg                        detach_unrefcounted_buffer_from_ctx, ctx);
10457ec681f3Smrg   _mesa_HashUnlockMutex(ctx->Shared->BufferObjects);
10467ec681f3Smrg}
10477ec681f3Smrg
10487ec681f3Smrg/**
10497ec681f3Smrg * Create a buffer object that will be backed by an OpenGL buffer ID
10507ec681f3Smrg * where the creating context will hold one global buffer reference instead
10517ec681f3Smrg * of updating buffer RefCount for every binding point.
10527ec681f3Smrg *
10537ec681f3Smrg * This shouldn't be used for internal buffers.
10547ec681f3Smrg */
10557ec681f3Smrgstatic struct gl_buffer_object *
10567ec681f3Smrgnew_gl_buffer_object(struct gl_context *ctx, GLuint id)
10577ec681f3Smrg{
10587ec681f3Smrg   struct gl_buffer_object *buf = ctx->Driver.NewBufferObject(ctx, id);
10597ec681f3Smrg
10607ec681f3Smrg   buf->Ctx = ctx;
10617ec681f3Smrg   buf->RefCount++; /* global buffer reference held by the context */
10627ec681f3Smrg   return buf;
10637117f1b4Smrg}
10647117f1b4Smrg
1065af69d88dSmrgbool
1066af69d88dSmrg_mesa_handle_bind_buffer_gen(struct gl_context *ctx,
1067af69d88dSmrg                             GLuint buffer,
1068af69d88dSmrg                             struct gl_buffer_object **buf_handle,
1069af69d88dSmrg                             const char *caller)
1070af69d88dSmrg{
1071af69d88dSmrg   struct gl_buffer_object *buf = *buf_handle;
1072af69d88dSmrg
107301e04c3fSmrg   if (!buf && (ctx->API == API_OPENGL_CORE)) {
1074af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", caller);
1075af69d88dSmrg      return false;
1076af69d88dSmrg   }
1077af69d88dSmrg
1078af69d88dSmrg   if (!buf || buf == &DummyBufferObject) {
1079af69d88dSmrg      /* If this is a new buffer object id, or one which was generated but
1080af69d88dSmrg       * never used before, allocate a buffer object now.
1081af69d88dSmrg       */
10827ec681f3Smrg      *buf_handle = new_gl_buffer_object(ctx, buffer);
10837ec681f3Smrg      if (!*buf_handle) {
1084af69d88dSmrg	 _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller);
1085af69d88dSmrg	 return false;
1086af69d88dSmrg      }
10877ec681f3Smrg      _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects,
10887ec681f3Smrg                                ctx->BufferObjectsLocked);
10897ec681f3Smrg      _mesa_HashInsertLocked(ctx->Shared->BufferObjects, buffer,
10907ec681f3Smrg                             *buf_handle, buf != NULL);
10917ec681f3Smrg      /* If one context only creates buffers and another context only deletes
10927ec681f3Smrg       * buffers, buffers don't get released because it only produces zombie
10937ec681f3Smrg       * buffers. Only the context that has created the buffers can release
10947ec681f3Smrg       * them. Thus, when we create buffers, we prune the list of zombie
10957ec681f3Smrg       * buffers.
10967ec681f3Smrg       */
10977ec681f3Smrg      unreference_zombie_buffers_for_ctx(ctx);
10987ec681f3Smrg      _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects,
10997ec681f3Smrg                                  ctx->BufferObjectsLocked);
1100af69d88dSmrg   }
1101af69d88dSmrg
1102af69d88dSmrg   return true;
1103af69d88dSmrg}
11044a49301eSmrg
1105c1f859d4Smrg/**
1106c1f859d4Smrg * Bind the specified target to buffer for the specified context.
11074a49301eSmrg * Called by glBindBuffer() and other functions.
1108c1f859d4Smrg */
1109c1f859d4Smrgstatic void
111001e04c3fSmrgbind_buffer_object(struct gl_context *ctx,
111101e04c3fSmrg                   struct gl_buffer_object **bindTarget, GLuint buffer)
1112c1f859d4Smrg{
1113c1f859d4Smrg   struct gl_buffer_object *oldBufObj;
1114c1f859d4Smrg   struct gl_buffer_object *newBufObj = NULL;
1115c1f859d4Smrg
111601e04c3fSmrg   assert(bindTarget);
1117c1f859d4Smrg
1118c1f859d4Smrg   /* Get pointer to old buffer object (to be unbound) */
11194a49301eSmrg   oldBufObj = *bindTarget;
11207ec681f3Smrg   if ((oldBufObj && oldBufObj->Name == buffer && !oldBufObj->DeletePending) ||
11217ec681f3Smrg       (!oldBufObj && buffer == 0))
1122c1f859d4Smrg      return;   /* rebinding the same buffer object- no change */
1123c1f859d4Smrg
1124c1f859d4Smrg   /*
1125c1f859d4Smrg    * Get pointer to new buffer object (newBufObj)
1126c1f859d4Smrg    */
11277ec681f3Smrg   if (buffer != 0) {
1128c1f859d4Smrg      /* non-default buffer object */
1129c1f859d4Smrg      newBufObj = _mesa_lookup_bufferobj(ctx, buffer);
113001e04c3fSmrg      if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
1131af69d88dSmrg                                        &newBufObj, "glBindBuffer"))
1132af69d88dSmrg         return;
113301e04c3fSmrg
11347ec681f3Smrg      /* record usage history */
11357ec681f3Smrg      if (bindTarget == &ctx->Pack.BufferObj)
11367ec681f3Smrg         newBufObj->UsageHistory |= USAGE_PIXEL_PACK_BUFFER;
113701e04c3fSmrg   }
113801e04c3fSmrg
1139c1f859d4Smrg   /* bind new buffer */
1140c1f859d4Smrg   _mesa_reference_buffer_object(ctx, bindTarget, newBufObj);
1141c1f859d4Smrg}
1142c1f859d4Smrg
1143c1f859d4Smrg
1144c1f859d4Smrg/**
1145c1f859d4Smrg * Update the default buffer objects in the given context to reference those
114601e04c3fSmrg * specified in the shared state and release those referencing the old
1147c1f859d4Smrg * shared state.
1148c1f859d4Smrg */
1149c1f859d4Smrgvoid
11503464ebd5Sriastradh_mesa_update_default_objects_buffer_objects(struct gl_context *ctx)
1151c1f859d4Smrg{
11527ec681f3Smrg   /* Bind 0 to remove references to those in the shared context hash table. */
115301e04c3fSmrg   bind_buffer_object(ctx, &ctx->Array.ArrayBufferObj, 0);
115401e04c3fSmrg   bind_buffer_object(ctx, &ctx->Array.VAO->IndexBufferObj, 0);
115501e04c3fSmrg   bind_buffer_object(ctx, &ctx->Pack.BufferObj, 0);
115601e04c3fSmrg   bind_buffer_object(ctx, &ctx->Unpack.BufferObj, 0);
1157c1f859d4Smrg}
1158c1f859d4Smrg
11597117f1b4Smrg
1160c1f859d4Smrg
11617117f1b4Smrg/**
11627117f1b4Smrg * Return the gl_buffer_object for the given ID.
11637117f1b4Smrg * Always return NULL for ID 0.
11647117f1b4Smrg */
11657117f1b4Smrgstruct gl_buffer_object *
11663464ebd5Sriastradh_mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer)
11677117f1b4Smrg{
11687117f1b4Smrg   if (buffer == 0)
11697117f1b4Smrg      return NULL;
11707117f1b4Smrg   else
11717117f1b4Smrg      return (struct gl_buffer_object *)
11727ec681f3Smrg         _mesa_HashLookupMaybeLocked(ctx->Shared->BufferObjects, buffer,
11737ec681f3Smrg                                     ctx->BufferObjectsLocked);
11747117f1b4Smrg}
11757117f1b4Smrg
11767117f1b4Smrg
1177af69d88dSmrgstruct gl_buffer_object *
1178af69d88dSmrg_mesa_lookup_bufferobj_locked(struct gl_context *ctx, GLuint buffer)
1179af69d88dSmrg{
118001e04c3fSmrg   if (buffer == 0)
118101e04c3fSmrg      return NULL;
118201e04c3fSmrg   else
118301e04c3fSmrg      return (struct gl_buffer_object *)
118401e04c3fSmrg         _mesa_HashLookupLocked(ctx->Shared->BufferObjects, buffer);
1185af69d88dSmrg}
1186af69d88dSmrg
118701e04c3fSmrg/**
118801e04c3fSmrg * A convenience function for direct state access functions that throws
118901e04c3fSmrg * GL_INVALID_OPERATION if buffer is not the name of an existing
119001e04c3fSmrg * buffer object.
119101e04c3fSmrg */
119201e04c3fSmrgstruct gl_buffer_object *
119301e04c3fSmrg_mesa_lookup_bufferobj_err(struct gl_context *ctx, GLuint buffer,
119401e04c3fSmrg                           const char *caller)
1195af69d88dSmrg{
119601e04c3fSmrg   struct gl_buffer_object *bufObj;
1197af69d88dSmrg
119801e04c3fSmrg   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
119901e04c3fSmrg   if (!bufObj || bufObj == &DummyBufferObject) {
120001e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
120101e04c3fSmrg                  "%s(non-existent buffer object %u)", caller, buffer);
120201e04c3fSmrg      return NULL;
120301e04c3fSmrg   }
1204af69d88dSmrg
120501e04c3fSmrg   return bufObj;
1206af69d88dSmrg}
1207af69d88dSmrg
1208af69d88dSmrg
1209af69d88dSmrg/**
1210af69d88dSmrg * Look up a buffer object for a multi-bind function.
1211af69d88dSmrg *
1212af69d88dSmrg * Unlike _mesa_lookup_bufferobj(), this function also takes care
1213af69d88dSmrg * of generating an error if the buffer ID is not zero or the name
1214af69d88dSmrg * of an existing buffer object.
1215af69d88dSmrg *
1216af69d88dSmrg * If the buffer ID refers to an existing buffer object, a pointer
12177ec681f3Smrg * to the buffer object is returned.  If the ID is zero, NULL is returned.
12187ec681f3Smrg * If the ID is not zero and does not refer to a valid buffer object, this
12197ec681f3Smrg * function returns NULL.
1220af69d88dSmrg *
1221af69d88dSmrg * This function assumes that the caller has already locked the
122201e04c3fSmrg * hash table mutex by calling
122301e04c3fSmrg * _mesa_HashLockMutex(ctx->Shared->BufferObjects).
1224af69d88dSmrg */
1225af69d88dSmrgstruct gl_buffer_object *
1226af69d88dSmrg_mesa_multi_bind_lookup_bufferobj(struct gl_context *ctx,
1227af69d88dSmrg                                  const GLuint *buffers,
12287ec681f3Smrg                                  GLuint index, const char *caller,
12297ec681f3Smrg                                  bool *error)
1230af69d88dSmrg{
12317ec681f3Smrg   struct gl_buffer_object *bufObj = NULL;
12327ec681f3Smrg
12337ec681f3Smrg   *error = false;
1234af69d88dSmrg
1235af69d88dSmrg   if (buffers[index] != 0) {
1236af69d88dSmrg      bufObj = _mesa_lookup_bufferobj_locked(ctx, buffers[index]);
1237af69d88dSmrg
1238af69d88dSmrg      /* The multi-bind functions don't create the buffer objects
1239af69d88dSmrg         when they don't exist. */
1240af69d88dSmrg      if (bufObj == &DummyBufferObject)
1241af69d88dSmrg         bufObj = NULL;
1242af69d88dSmrg
12437ec681f3Smrg      if (!bufObj) {
12447ec681f3Smrg         /* The ARB_multi_bind spec says:
12457ec681f3Smrg          *
12467ec681f3Smrg          *    "An INVALID_OPERATION error is generated if any value
12477ec681f3Smrg          *     in <buffers> is not zero or the name of an existing
12487ec681f3Smrg          *     buffer object (per binding)."
12497ec681f3Smrg          */
12507ec681f3Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
12517ec681f3Smrg                     "%s(buffers[%u]=%u is not zero or the name "
12527ec681f3Smrg                     "of an existing buffer object)",
12537ec681f3Smrg                     caller, index, buffers[index]);
12547ec681f3Smrg         *error = true;
12557ec681f3Smrg      }
1256af69d88dSmrg   }
1257af69d88dSmrg
1258af69d88dSmrg   return bufObj;
1259af69d88dSmrg}
1260af69d88dSmrg
1261af69d88dSmrg
1262c1f859d4Smrg/**
1263c1f859d4Smrg * If *ptr points to obj, set ptr = the Null/default buffer object.
1264c1f859d4Smrg * This is a helper for buffer object deletion.
1265c1f859d4Smrg * The GL spec says that deleting a buffer object causes it to get
1266c1f859d4Smrg * unbound from all arrays in the current context.
1267c1f859d4Smrg */
1268c1f859d4Smrgstatic void
12693464ebd5Sriastradhunbind(struct gl_context *ctx,
127001e04c3fSmrg       struct gl_vertex_array_object *vao, unsigned index,
1271c1f859d4Smrg       struct gl_buffer_object *obj)
1272c1f859d4Smrg{
127301e04c3fSmrg   if (vao->BufferBinding[index].BufferObj == obj) {
12747ec681f3Smrg      _mesa_bind_vertex_buffer(ctx, vao, index, NULL,
127501e04c3fSmrg                               vao->BufferBinding[index].Offset,
12767ec681f3Smrg                               vao->BufferBinding[index].Stride, true, false);
1277c1f859d4Smrg   }
1278c1f859d4Smrg}
1279c1f859d4Smrg
1280c1f859d4Smrg
12814a49301eSmrg/**
12824a49301eSmrg * Plug default/fallback buffer object functions into the device
12834a49301eSmrg * driver hooks.
12844a49301eSmrg */
12854a49301eSmrgvoid
12864a49301eSmrg_mesa_init_buffer_object_functions(struct dd_function_table *driver)
12874a49301eSmrg{
12884a49301eSmrg   /* GL_ARB_vertex/pixel_buffer_object */
12894a49301eSmrg   driver->NewBufferObject = _mesa_new_buffer_object;
12904a49301eSmrg   driver->DeleteBuffer = _mesa_delete_buffer_object;
129101e04c3fSmrg   driver->BufferData = buffer_data_fallback;
129201e04c3fSmrg   driver->BufferSubData = buffer_sub_data_fallback;
129301e04c3fSmrg   driver->GetBufferSubData = buffer_get_subdata;
129401e04c3fSmrg   driver->UnmapBuffer = unmap_buffer_fallback;
12954a49301eSmrg
1296af69d88dSmrg   /* GL_ARB_clear_buffer_object */
129701e04c3fSmrg   driver->ClearBufferSubData = _mesa_ClearBufferSubData_sw;
1298af69d88dSmrg
12994a49301eSmrg   /* GL_ARB_map_buffer_range */
130001e04c3fSmrg   driver->MapBufferRange = map_buffer_range_fallback;
130101e04c3fSmrg   driver->FlushMappedBufferRange = flush_mapped_buffer_range_fallback;
13024a49301eSmrg
13034a49301eSmrg   /* GL_ARB_copy_buffer */
130401e04c3fSmrg   driver->CopyBufferSubData = copy_buffer_sub_data_fallback;
13054a49301eSmrg}
13064a49301eSmrg
13074a49301eSmrg
1308af69d88dSmrgvoid
1309af69d88dSmrg_mesa_buffer_unmap_all_mappings(struct gl_context *ctx,
1310af69d88dSmrg                                struct gl_buffer_object *bufObj)
1311af69d88dSmrg{
131201e04c3fSmrg   for (int i = 0; i < MAP_COUNT; i++) {
1313af69d88dSmrg      if (_mesa_bufferobj_mapped(bufObj, i)) {
1314af69d88dSmrg         ctx->Driver.UnmapBuffer(ctx, bufObj, i);
131501e04c3fSmrg         assert(bufObj->Mappings[i].Pointer == NULL);
1316af69d88dSmrg         bufObj->Mappings[i].AccessFlags = 0;
1317af69d88dSmrg      }
1318af69d88dSmrg   }
1319af69d88dSmrg}
1320af69d88dSmrg
13217117f1b4Smrg
13227117f1b4Smrg/**********************************************************************/
13237117f1b4Smrg/* API Functions                                                      */
13247117f1b4Smrg/**********************************************************************/
13257117f1b4Smrg
13267117f1b4Smrgvoid GLAPIENTRY
132701e04c3fSmrg_mesa_BindBuffer_no_error(GLenum target, GLuint buffer)
13287117f1b4Smrg{
13297117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
13307117f1b4Smrg
133101e04c3fSmrg   struct gl_buffer_object **bindTarget = get_buffer_target(ctx, target);
133201e04c3fSmrg   bind_buffer_object(ctx, bindTarget, buffer);
13337117f1b4Smrg}
13347117f1b4Smrg
13357117f1b4Smrg
13367117f1b4Smrgvoid GLAPIENTRY
133701e04c3fSmrg_mesa_BindBuffer(GLenum target, GLuint buffer)
13387117f1b4Smrg{
13397117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
13407117f1b4Smrg
134101e04c3fSmrg   if (MESA_VERBOSE & VERBOSE_API) {
134201e04c3fSmrg      _mesa_debug(ctx, "glBindBuffer(%s, %u)\n",
134301e04c3fSmrg                  _mesa_enum_to_string(target), buffer);
13447117f1b4Smrg   }
13457117f1b4Smrg
134601e04c3fSmrg   struct gl_buffer_object **bindTarget = get_buffer_target(ctx, target);
134701e04c3fSmrg   if (!bindTarget) {
134801e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target %s)",
134901e04c3fSmrg                  _mesa_enum_to_string(target));
135001e04c3fSmrg      return;
13517117f1b4Smrg   }
13527117f1b4Smrg
135301e04c3fSmrg   bind_buffer_object(ctx, bindTarget, buffer);
13547117f1b4Smrg}
13557117f1b4Smrg
13567ec681f3Smrgvoid
13577ec681f3Smrg_mesa_InternalBindElementBuffer(struct gl_context *ctx,
13587ec681f3Smrg                                struct gl_buffer_object *buf)
13597ec681f3Smrg{
13607ec681f3Smrg   struct gl_buffer_object **bindTarget =
13617ec681f3Smrg      get_buffer_target(ctx, GL_ELEMENT_ARRAY_BUFFER);
13627ec681f3Smrg
13637ec681f3Smrg   /* Move the buffer reference from the parameter to the bind point. */
13647ec681f3Smrg   _mesa_reference_buffer_object(ctx, bindTarget, NULL);
13657ec681f3Smrg   if (buf)
13667ec681f3Smrg      *bindTarget = buf;
13677ec681f3Smrg}
13687ec681f3Smrg
13697117f1b4Smrg/**
137001e04c3fSmrg * Binds a buffer object to a binding point.
137101e04c3fSmrg *
137201e04c3fSmrg * The caller is responsible for validating the offset,
137301e04c3fSmrg * flushing the vertices and updating NewDriverState.
13747117f1b4Smrg */
137501e04c3fSmrgstatic void
137601e04c3fSmrgset_buffer_binding(struct gl_context *ctx,
137701e04c3fSmrg                   struct gl_buffer_binding *binding,
137801e04c3fSmrg                   struct gl_buffer_object *bufObj,
137901e04c3fSmrg                   GLintptr offset,
138001e04c3fSmrg                   GLsizeiptr size,
138101e04c3fSmrg                   bool autoSize, gl_buffer_usage usage)
13827117f1b4Smrg{
138301e04c3fSmrg   _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj);
13847117f1b4Smrg
138501e04c3fSmrg   binding->Offset = offset;
138601e04c3fSmrg   binding->Size = size;
138701e04c3fSmrg   binding->AutomaticSize = autoSize;
13883464ebd5Sriastradh
138901e04c3fSmrg   /* If this is a real buffer object, mark it has having been used
139001e04c3fSmrg    * at some point as an atomic counter buffer.
139101e04c3fSmrg    */
139201e04c3fSmrg   if (size >= 0)
139301e04c3fSmrg      bufObj->UsageHistory |= usage;
139401e04c3fSmrg}
139501e04c3fSmrg
139601e04c3fSmrgstatic void
139701e04c3fSmrgset_buffer_multi_binding(struct gl_context *ctx,
139801e04c3fSmrg                         const GLuint *buffers,
139901e04c3fSmrg                         int idx,
140001e04c3fSmrg                         const char *caller,
140101e04c3fSmrg                         struct gl_buffer_binding *binding,
140201e04c3fSmrg                         GLintptr offset,
140301e04c3fSmrg                         GLsizeiptr size,
140401e04c3fSmrg                         bool range,
140501e04c3fSmrg                         gl_buffer_usage usage)
140601e04c3fSmrg{
140701e04c3fSmrg   struct gl_buffer_object *bufObj;
14087ec681f3Smrg
140901e04c3fSmrg   if (binding->BufferObject && binding->BufferObject->Name == buffers[idx])
141001e04c3fSmrg      bufObj = binding->BufferObject;
14117ec681f3Smrg   else {
14127ec681f3Smrg      bool error;
14137ec681f3Smrg      bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, idx, caller,
14147ec681f3Smrg                                                 &error);
14157ec681f3Smrg      if (error)
14167ec681f3Smrg         return;
14177117f1b4Smrg   }
14187ec681f3Smrg
14197ec681f3Smrg   if (!bufObj)
14207ec681f3Smrg      set_buffer_binding(ctx, binding, bufObj, -1, -1, !range, usage);
14217ec681f3Smrg   else
14227ec681f3Smrg      set_buffer_binding(ctx, binding, bufObj, offset, size, !range, usage);
142301e04c3fSmrg}
14247117f1b4Smrg
142501e04c3fSmrgstatic void
142601e04c3fSmrgbind_buffer(struct gl_context *ctx,
142701e04c3fSmrg            struct gl_buffer_binding *binding,
142801e04c3fSmrg            struct gl_buffer_object *bufObj,
142901e04c3fSmrg            GLintptr offset,
143001e04c3fSmrg            GLsizeiptr size,
143101e04c3fSmrg            GLboolean autoSize,
143201e04c3fSmrg            uint64_t driver_state,
143301e04c3fSmrg            gl_buffer_usage usage)
143401e04c3fSmrg{
143501e04c3fSmrg   if (binding->BufferObject == bufObj &&
143601e04c3fSmrg       binding->Offset == offset &&
143701e04c3fSmrg       binding->Size == size &&
143801e04c3fSmrg       binding->AutomaticSize == autoSize) {
14397117f1b4Smrg      return;
14407117f1b4Smrg   }
14417117f1b4Smrg
14427ec681f3Smrg   FLUSH_VERTICES(ctx, 0, 0);
144301e04c3fSmrg   ctx->NewDriverState |= driver_state;
14447117f1b4Smrg
144501e04c3fSmrg   set_buffer_binding(ctx, binding, bufObj, offset, size, autoSize, usage);
14467117f1b4Smrg}
14477117f1b4Smrg
14487117f1b4Smrg/**
144901e04c3fSmrg * Binds a buffer object to a uniform buffer binding point.
145001e04c3fSmrg *
145101e04c3fSmrg * Unlike set_buffer_binding(), this function also flushes vertices
145201e04c3fSmrg * and updates NewDriverState.  It also checks if the binding
145301e04c3fSmrg * has actually changed before updating it.
145401e04c3fSmrg */
145501e04c3fSmrgstatic void
145601e04c3fSmrgbind_uniform_buffer(struct gl_context *ctx,
145701e04c3fSmrg                    GLuint index,
145801e04c3fSmrg                    struct gl_buffer_object *bufObj,
145901e04c3fSmrg                    GLintptr offset,
146001e04c3fSmrg                    GLsizeiptr size,
146101e04c3fSmrg                    GLboolean autoSize)
146201e04c3fSmrg{
146301e04c3fSmrg   bind_buffer(ctx, &ctx->UniformBufferBindings[index],
146401e04c3fSmrg               bufObj, offset, size, autoSize,
146501e04c3fSmrg               ctx->DriverFlags.NewUniformBuffer,
146601e04c3fSmrg               USAGE_UNIFORM_BUFFER);
146701e04c3fSmrg}
146801e04c3fSmrg
146901e04c3fSmrg/**
147001e04c3fSmrg * Binds a buffer object to a shader storage buffer binding point.
147101e04c3fSmrg *
147201e04c3fSmrg * Unlike set_ssbo_binding(), this function also flushes vertices
147301e04c3fSmrg * and updates NewDriverState.  It also checks if the binding
147401e04c3fSmrg * has actually changed before updating it.
147501e04c3fSmrg */
147601e04c3fSmrgstatic void
147701e04c3fSmrgbind_shader_storage_buffer(struct gl_context *ctx,
147801e04c3fSmrg                           GLuint index,
147901e04c3fSmrg                           struct gl_buffer_object *bufObj,
148001e04c3fSmrg                           GLintptr offset,
148101e04c3fSmrg                           GLsizeiptr size,
148201e04c3fSmrg                           GLboolean autoSize)
148301e04c3fSmrg{
148401e04c3fSmrg   bind_buffer(ctx, &ctx->ShaderStorageBufferBindings[index],
148501e04c3fSmrg               bufObj, offset, size, autoSize,
148601e04c3fSmrg               ctx->DriverFlags.NewShaderStorageBuffer,
148701e04c3fSmrg               USAGE_SHADER_STORAGE_BUFFER);
148801e04c3fSmrg}
148901e04c3fSmrg
149001e04c3fSmrg/**
149101e04c3fSmrg * Binds a buffer object to an atomic buffer binding point.
149201e04c3fSmrg *
149301e04c3fSmrg * Unlike set_atomic_binding(), this function also flushes vertices
149401e04c3fSmrg * and updates NewDriverState.  It also checks if the binding
149501e04c3fSmrg * has actually changed before updating it.
149601e04c3fSmrg */
149701e04c3fSmrgstatic void
149801e04c3fSmrgbind_atomic_buffer(struct gl_context *ctx, unsigned index,
149901e04c3fSmrg                   struct gl_buffer_object *bufObj, GLintptr offset,
150001e04c3fSmrg                   GLsizeiptr size, GLboolean autoSize)
150101e04c3fSmrg{
150201e04c3fSmrg   bind_buffer(ctx, &ctx->AtomicBufferBindings[index],
150301e04c3fSmrg               bufObj, offset, size, autoSize,
150401e04c3fSmrg               ctx->DriverFlags.NewAtomicBuffer,
150501e04c3fSmrg               USAGE_ATOMIC_COUNTER_BUFFER);
150601e04c3fSmrg}
150701e04c3fSmrg
150801e04c3fSmrg/**
150901e04c3fSmrg * Bind a buffer object to a uniform block binding point.
151001e04c3fSmrg * As above, but offset = 0.
151101e04c3fSmrg */
151201e04c3fSmrgstatic void
151301e04c3fSmrgbind_buffer_base_uniform_buffer(struct gl_context *ctx,
151401e04c3fSmrg				GLuint index,
151501e04c3fSmrg				struct gl_buffer_object *bufObj)
151601e04c3fSmrg{
151701e04c3fSmrg   if (index >= ctx->Const.MaxUniformBufferBindings) {
151801e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index);
151901e04c3fSmrg      return;
152001e04c3fSmrg   }
152101e04c3fSmrg
152201e04c3fSmrg   _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj);
152301e04c3fSmrg
15247ec681f3Smrg   if (!bufObj)
152501e04c3fSmrg      bind_uniform_buffer(ctx, index, bufObj, -1, -1, GL_TRUE);
152601e04c3fSmrg   else
152701e04c3fSmrg      bind_uniform_buffer(ctx, index, bufObj, 0, 0, GL_TRUE);
152801e04c3fSmrg}
152901e04c3fSmrg
153001e04c3fSmrg/**
153101e04c3fSmrg * Bind a buffer object to a shader storage block binding point.
153201e04c3fSmrg * As above, but offset = 0.
153301e04c3fSmrg */
153401e04c3fSmrgstatic void
153501e04c3fSmrgbind_buffer_base_shader_storage_buffer(struct gl_context *ctx,
153601e04c3fSmrg                                       GLuint index,
153701e04c3fSmrg                                       struct gl_buffer_object *bufObj)
153801e04c3fSmrg{
153901e04c3fSmrg   if (index >= ctx->Const.MaxShaderStorageBufferBindings) {
154001e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index);
154101e04c3fSmrg      return;
154201e04c3fSmrg   }
154301e04c3fSmrg
154401e04c3fSmrg   _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer, bufObj);
154501e04c3fSmrg
15467ec681f3Smrg   if (!bufObj)
154701e04c3fSmrg      bind_shader_storage_buffer(ctx, index, bufObj, -1, -1, GL_TRUE);
154801e04c3fSmrg   else
154901e04c3fSmrg      bind_shader_storage_buffer(ctx, index, bufObj, 0, 0, GL_TRUE);
155001e04c3fSmrg}
155101e04c3fSmrg
155201e04c3fSmrg/**
155301e04c3fSmrg * Bind a buffer object to a shader storage block binding point.
155401e04c3fSmrg * As above, but offset = 0.
155501e04c3fSmrg */
155601e04c3fSmrgstatic void
155701e04c3fSmrgbind_buffer_base_atomic_buffer(struct gl_context *ctx,
155801e04c3fSmrg                               GLuint index,
155901e04c3fSmrg                               struct gl_buffer_object *bufObj)
156001e04c3fSmrg{
156101e04c3fSmrg   if (index >= ctx->Const.MaxAtomicBufferBindings) {
156201e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index);
156301e04c3fSmrg      return;
156401e04c3fSmrg   }
156501e04c3fSmrg
156601e04c3fSmrg   _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, bufObj);
156701e04c3fSmrg
15687ec681f3Smrg   if (!bufObj)
156901e04c3fSmrg      bind_atomic_buffer(ctx, index, bufObj, -1, -1, GL_TRUE);
157001e04c3fSmrg   else
157101e04c3fSmrg      bind_atomic_buffer(ctx, index, bufObj, 0, 0, GL_TRUE);
157201e04c3fSmrg}
157301e04c3fSmrg
157401e04c3fSmrg/**
157501e04c3fSmrg * Delete a set of buffer objects.
157601e04c3fSmrg *
157701e04c3fSmrg * \param n      Number of buffer objects to delete.
157801e04c3fSmrg * \param ids    Array of \c n buffer object IDs.
157901e04c3fSmrg */
158001e04c3fSmrgstatic void
158101e04c3fSmrgdelete_buffers(struct gl_context *ctx, GLsizei n, const GLuint *ids)
158201e04c3fSmrg{
15837ec681f3Smrg   FLUSH_VERTICES(ctx, 0, 0);
158401e04c3fSmrg
15857ec681f3Smrg   _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects,
15867ec681f3Smrg                             ctx->BufferObjectsLocked);
15877ec681f3Smrg   unreference_zombie_buffers_for_ctx(ctx);
158801e04c3fSmrg
158901e04c3fSmrg   for (GLsizei i = 0; i < n; i++) {
159001e04c3fSmrg      struct gl_buffer_object *bufObj =
159101e04c3fSmrg         _mesa_lookup_bufferobj_locked(ctx, ids[i]);
159201e04c3fSmrg      if (bufObj) {
159301e04c3fSmrg         struct gl_vertex_array_object *vao = ctx->Array.VAO;
159401e04c3fSmrg         GLuint j;
159501e04c3fSmrg
159601e04c3fSmrg         assert(bufObj->Name == ids[i] || bufObj == &DummyBufferObject);
159701e04c3fSmrg
159801e04c3fSmrg         _mesa_buffer_unmap_all_mappings(ctx, bufObj);
159901e04c3fSmrg
160001e04c3fSmrg         /* unbind any vertex pointers bound to this buffer */
160101e04c3fSmrg         for (j = 0; j < ARRAY_SIZE(vao->BufferBinding); j++) {
160201e04c3fSmrg            unbind(ctx, vao, j, bufObj);
160301e04c3fSmrg         }
160401e04c3fSmrg
160501e04c3fSmrg         if (ctx->Array.ArrayBufferObj == bufObj) {
160601e04c3fSmrg            bind_buffer_object(ctx, &ctx->Array.ArrayBufferObj, 0);
160701e04c3fSmrg         }
160801e04c3fSmrg         if (vao->IndexBufferObj == bufObj) {
160901e04c3fSmrg            bind_buffer_object(ctx, &vao->IndexBufferObj, 0);
161001e04c3fSmrg         }
161101e04c3fSmrg
161201e04c3fSmrg         /* unbind ARB_draw_indirect binding point */
161301e04c3fSmrg         if (ctx->DrawIndirectBuffer == bufObj) {
161401e04c3fSmrg            bind_buffer_object(ctx, &ctx->DrawIndirectBuffer, 0);
161501e04c3fSmrg         }
161601e04c3fSmrg
161701e04c3fSmrg         /* unbind ARB_indirect_parameters binding point */
161801e04c3fSmrg         if (ctx->ParameterBuffer == bufObj) {
161901e04c3fSmrg            bind_buffer_object(ctx, &ctx->ParameterBuffer, 0);
162001e04c3fSmrg         }
162101e04c3fSmrg
162201e04c3fSmrg         /* unbind ARB_compute_shader binding point */
162301e04c3fSmrg         if (ctx->DispatchIndirectBuffer == bufObj) {
162401e04c3fSmrg            bind_buffer_object(ctx, &ctx->DispatchIndirectBuffer, 0);
162501e04c3fSmrg         }
162601e04c3fSmrg
162701e04c3fSmrg         /* unbind ARB_copy_buffer binding points */
162801e04c3fSmrg         if (ctx->CopyReadBuffer == bufObj) {
162901e04c3fSmrg            bind_buffer_object(ctx, &ctx->CopyReadBuffer, 0);
163001e04c3fSmrg         }
163101e04c3fSmrg         if (ctx->CopyWriteBuffer == bufObj) {
163201e04c3fSmrg            bind_buffer_object(ctx, &ctx->CopyWriteBuffer, 0);
163301e04c3fSmrg         }
163401e04c3fSmrg
163501e04c3fSmrg         /* unbind transform feedback binding points */
163601e04c3fSmrg         if (ctx->TransformFeedback.CurrentBuffer == bufObj) {
163701e04c3fSmrg            bind_buffer_object(ctx, &ctx->TransformFeedback.CurrentBuffer, 0);
163801e04c3fSmrg         }
163901e04c3fSmrg         for (j = 0; j < MAX_FEEDBACK_BUFFERS; j++) {
164001e04c3fSmrg            if (ctx->TransformFeedback.CurrentObject->Buffers[j] == bufObj) {
164101e04c3fSmrg               _mesa_bind_buffer_base_transform_feedback(ctx,
164201e04c3fSmrg                                           ctx->TransformFeedback.CurrentObject,
16437ec681f3Smrg                                           j, NULL, false);
164401e04c3fSmrg            }
164501e04c3fSmrg         }
164601e04c3fSmrg
164701e04c3fSmrg         /* unbind UBO binding points */
164801e04c3fSmrg         for (j = 0; j < ctx->Const.MaxUniformBufferBindings; j++) {
164901e04c3fSmrg            if (ctx->UniformBufferBindings[j].BufferObject == bufObj) {
16507ec681f3Smrg               bind_buffer_base_uniform_buffer(ctx, j, NULL);
165101e04c3fSmrg            }
165201e04c3fSmrg         }
165301e04c3fSmrg
165401e04c3fSmrg         if (ctx->UniformBuffer == bufObj) {
165501e04c3fSmrg            bind_buffer_object(ctx, &ctx->UniformBuffer, 0);
165601e04c3fSmrg         }
165701e04c3fSmrg
165801e04c3fSmrg         /* unbind SSBO binding points */
165901e04c3fSmrg         for (j = 0; j < ctx->Const.MaxShaderStorageBufferBindings; j++) {
166001e04c3fSmrg            if (ctx->ShaderStorageBufferBindings[j].BufferObject == bufObj) {
16617ec681f3Smrg               bind_buffer_base_shader_storage_buffer(ctx, j, NULL);
166201e04c3fSmrg            }
166301e04c3fSmrg         }
166401e04c3fSmrg
166501e04c3fSmrg         if (ctx->ShaderStorageBuffer == bufObj) {
166601e04c3fSmrg            bind_buffer_object(ctx, &ctx->ShaderStorageBuffer, 0);
166701e04c3fSmrg         }
166801e04c3fSmrg
166901e04c3fSmrg         /* unbind Atomci Buffer binding points */
167001e04c3fSmrg         for (j = 0; j < ctx->Const.MaxAtomicBufferBindings; j++) {
167101e04c3fSmrg            if (ctx->AtomicBufferBindings[j].BufferObject == bufObj) {
16727ec681f3Smrg               bind_buffer_base_atomic_buffer(ctx, j, NULL);
167301e04c3fSmrg            }
167401e04c3fSmrg         }
167501e04c3fSmrg
167601e04c3fSmrg         if (ctx->AtomicBuffer == bufObj) {
167701e04c3fSmrg            bind_buffer_object(ctx, &ctx->AtomicBuffer, 0);
167801e04c3fSmrg         }
167901e04c3fSmrg
168001e04c3fSmrg         /* unbind any pixel pack/unpack pointers bound to this buffer */
168101e04c3fSmrg         if (ctx->Pack.BufferObj == bufObj) {
168201e04c3fSmrg            bind_buffer_object(ctx, &ctx->Pack.BufferObj, 0);
168301e04c3fSmrg         }
168401e04c3fSmrg         if (ctx->Unpack.BufferObj == bufObj) {
168501e04c3fSmrg            bind_buffer_object(ctx, &ctx->Unpack.BufferObj, 0);
168601e04c3fSmrg         }
168701e04c3fSmrg
168801e04c3fSmrg         if (ctx->Texture.BufferObject == bufObj) {
168901e04c3fSmrg            bind_buffer_object(ctx, &ctx->Texture.BufferObject, 0);
169001e04c3fSmrg         }
169101e04c3fSmrg
169201e04c3fSmrg         if (ctx->ExternalVirtualMemoryBuffer == bufObj) {
169301e04c3fSmrg            bind_buffer_object(ctx, &ctx->ExternalVirtualMemoryBuffer, 0);
169401e04c3fSmrg         }
169501e04c3fSmrg
169601e04c3fSmrg         /* unbind query buffer binding point */
169701e04c3fSmrg         if (ctx->QueryBuffer == bufObj) {
169801e04c3fSmrg            bind_buffer_object(ctx, &ctx->QueryBuffer, 0);
169901e04c3fSmrg         }
170001e04c3fSmrg
170101e04c3fSmrg         /* The ID is immediately freed for re-use */
170201e04c3fSmrg         _mesa_HashRemoveLocked(ctx->Shared->BufferObjects, ids[i]);
170301e04c3fSmrg         /* Make sure we do not run into the classic ABA problem on bind.
170401e04c3fSmrg          * We don't want to allow re-binding a buffer object that's been
170501e04c3fSmrg          * "deleted" by glDeleteBuffers().
170601e04c3fSmrg          *
170701e04c3fSmrg          * The explicit rebinding to the default object in the current context
170801e04c3fSmrg          * prevents the above in the current context, but another context
170901e04c3fSmrg          * sharing the same objects might suffer from this problem.
171001e04c3fSmrg          * The alternative would be to do the hash lookup in any case on bind
171101e04c3fSmrg          * which would introduce more runtime overhead than this.
171201e04c3fSmrg          */
171301e04c3fSmrg         bufObj->DeletePending = GL_TRUE;
17147ec681f3Smrg
17157ec681f3Smrg         /* The GLuint ID holds one reference and the context that created
17167ec681f3Smrg          * the buffer holds the other one.
17177ec681f3Smrg          */
17187ec681f3Smrg         assert(p_atomic_read(&bufObj->RefCount) >= (bufObj->Ctx ? 2 : 1));
17197ec681f3Smrg
17207ec681f3Smrg         if (bufObj->Ctx == ctx) {
17217ec681f3Smrg            detach_ctx_from_buffer(ctx, bufObj);
17227ec681f3Smrg         } else if (bufObj->Ctx) {
17237ec681f3Smrg            /* Only the context holding it can release it. */
17247ec681f3Smrg            _mesa_set_add(ctx->Shared->ZombieBufferObjects, bufObj);
17257ec681f3Smrg         }
17267ec681f3Smrg
172701e04c3fSmrg         _mesa_reference_buffer_object(ctx, &bufObj, NULL);
172801e04c3fSmrg      }
172901e04c3fSmrg   }
173001e04c3fSmrg
17317ec681f3Smrg   _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects,
17327ec681f3Smrg                               ctx->BufferObjectsLocked);
173301e04c3fSmrg}
173401e04c3fSmrg
173501e04c3fSmrg
173601e04c3fSmrgvoid GLAPIENTRY
173701e04c3fSmrg_mesa_DeleteBuffers_no_error(GLsizei n, const GLuint *ids)
173801e04c3fSmrg{
173901e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
174001e04c3fSmrg   delete_buffers(ctx, n, ids);
174101e04c3fSmrg}
174201e04c3fSmrg
174301e04c3fSmrg
174401e04c3fSmrgvoid GLAPIENTRY
174501e04c3fSmrg_mesa_DeleteBuffers(GLsizei n, const GLuint *ids)
174601e04c3fSmrg{
174701e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
174801e04c3fSmrg
174901e04c3fSmrg   if (n < 0) {
175001e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)");
175101e04c3fSmrg      return;
175201e04c3fSmrg   }
175301e04c3fSmrg
175401e04c3fSmrg   delete_buffers(ctx, n, ids);
175501e04c3fSmrg}
175601e04c3fSmrg
175701e04c3fSmrg
175801e04c3fSmrg/**
175901e04c3fSmrg * This is the implementation for glGenBuffers and glCreateBuffers. It is not
176001e04c3fSmrg * exposed to the rest of Mesa to encourage the use of nameless buffers in
176101e04c3fSmrg * driver internals.
176201e04c3fSmrg */
176301e04c3fSmrgstatic void
176401e04c3fSmrgcreate_buffers(struct gl_context *ctx, GLsizei n, GLuint *buffers, bool dsa)
176501e04c3fSmrg{
176601e04c3fSmrg   struct gl_buffer_object *buf;
176701e04c3fSmrg
176801e04c3fSmrg   if (!buffers)
176901e04c3fSmrg      return;
177001e04c3fSmrg
177101e04c3fSmrg   /*
177201e04c3fSmrg    * This must be atomic (generation and allocation of buffer object IDs)
177301e04c3fSmrg    */
17747ec681f3Smrg   _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects,
17757ec681f3Smrg                             ctx->BufferObjectsLocked);
17767ec681f3Smrg   /* If one context only creates buffers and another context only deletes
17777ec681f3Smrg    * buffers, buffers don't get released because it only produces zombie
17787ec681f3Smrg    * buffers. Only the context that has created the buffers can release
17797ec681f3Smrg    * them. Thus, when we create buffers, we prune the list of zombie
17807ec681f3Smrg    * buffers.
17817ec681f3Smrg    */
17827ec681f3Smrg   unreference_zombie_buffers_for_ctx(ctx);
178301e04c3fSmrg
17847ec681f3Smrg   _mesa_HashFindFreeKeys(ctx->Shared->BufferObjects, buffers, n);
178501e04c3fSmrg
178601e04c3fSmrg   /* Insert the ID and pointer into the hash table. If non-DSA, insert a
178701e04c3fSmrg    * DummyBufferObject.  Otherwise, create a new buffer object and insert
178801e04c3fSmrg    * it.
178901e04c3fSmrg    */
179001e04c3fSmrg   for (int i = 0; i < n; i++) {
179101e04c3fSmrg      if (dsa) {
179201e04c3fSmrg         assert(ctx->Driver.NewBufferObject);
17937ec681f3Smrg         buf = new_gl_buffer_object(ctx, buffers[i]);
179401e04c3fSmrg         if (!buf) {
179501e04c3fSmrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCreateBuffers");
17967ec681f3Smrg            _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects,
17977ec681f3Smrg                                        ctx->BufferObjectsLocked);
179801e04c3fSmrg            return;
179901e04c3fSmrg         }
180001e04c3fSmrg      }
180101e04c3fSmrg      else
180201e04c3fSmrg         buf = &DummyBufferObject;
180301e04c3fSmrg
18047ec681f3Smrg      _mesa_HashInsertLocked(ctx->Shared->BufferObjects, buffers[i], buf, true);
180501e04c3fSmrg   }
180601e04c3fSmrg
18077ec681f3Smrg   _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects,
18087ec681f3Smrg                               ctx->BufferObjectsLocked);
180901e04c3fSmrg}
181001e04c3fSmrg
181101e04c3fSmrg
181201e04c3fSmrgstatic void
181301e04c3fSmrgcreate_buffers_err(struct gl_context *ctx, GLsizei n, GLuint *buffers, bool dsa)
181401e04c3fSmrg{
181501e04c3fSmrg   const char *func = dsa ? "glCreateBuffers" : "glGenBuffers";
181601e04c3fSmrg
181701e04c3fSmrg   if (MESA_VERBOSE & VERBOSE_API)
181801e04c3fSmrg      _mesa_debug(ctx, "%s(%d)\n", func, n);
181901e04c3fSmrg
182001e04c3fSmrg   if (n < 0) {
182101e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n %d < 0)", func, n);
182201e04c3fSmrg      return;
182301e04c3fSmrg   }
182401e04c3fSmrg
182501e04c3fSmrg   create_buffers(ctx, n, buffers, dsa);
182601e04c3fSmrg}
182701e04c3fSmrg
182801e04c3fSmrg/**
182901e04c3fSmrg * Generate a set of unique buffer object IDs and store them in \c buffers.
183001e04c3fSmrg *
183101e04c3fSmrg * \param n        Number of IDs to generate.
183201e04c3fSmrg * \param buffers  Array of \c n locations to store the IDs.
183301e04c3fSmrg */
183401e04c3fSmrgvoid GLAPIENTRY
183501e04c3fSmrg_mesa_GenBuffers_no_error(GLsizei n, GLuint *buffers)
183601e04c3fSmrg{
183701e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
183801e04c3fSmrg   create_buffers(ctx, n, buffers, false);
183901e04c3fSmrg}
184001e04c3fSmrg
184101e04c3fSmrg
184201e04c3fSmrgvoid GLAPIENTRY
184301e04c3fSmrg_mesa_GenBuffers(GLsizei n, GLuint *buffers)
184401e04c3fSmrg{
184501e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
184601e04c3fSmrg   create_buffers_err(ctx, n, buffers, false);
184701e04c3fSmrg}
184801e04c3fSmrg
184901e04c3fSmrg/**
185001e04c3fSmrg * Create a set of buffer objects and store their unique IDs in \c buffers.
185101e04c3fSmrg *
185201e04c3fSmrg * \param n        Number of IDs to generate.
185301e04c3fSmrg * \param buffers  Array of \c n locations to store the IDs.
185401e04c3fSmrg */
185501e04c3fSmrgvoid GLAPIENTRY
185601e04c3fSmrg_mesa_CreateBuffers_no_error(GLsizei n, GLuint *buffers)
185701e04c3fSmrg{
185801e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
185901e04c3fSmrg   create_buffers(ctx, n, buffers, true);
186001e04c3fSmrg}
186101e04c3fSmrg
186201e04c3fSmrg
186301e04c3fSmrgvoid GLAPIENTRY
186401e04c3fSmrg_mesa_CreateBuffers(GLsizei n, GLuint *buffers)
186501e04c3fSmrg{
186601e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
186701e04c3fSmrg   create_buffers_err(ctx, n, buffers, true);
186801e04c3fSmrg}
186901e04c3fSmrg
187001e04c3fSmrg
187101e04c3fSmrg/**
187201e04c3fSmrg * Determine if ID is the name of a buffer object.
187301e04c3fSmrg *
187401e04c3fSmrg * \param id  ID of the potential buffer object.
187501e04c3fSmrg * \return  \c GL_TRUE if \c id is the name of a buffer object,
187601e04c3fSmrg *          \c GL_FALSE otherwise.
187701e04c3fSmrg */
18787117f1b4SmrgGLboolean GLAPIENTRY
1879af69d88dSmrg_mesa_IsBuffer(GLuint id)
18807117f1b4Smrg{
18817117f1b4Smrg   struct gl_buffer_object *bufObj;
18827117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
18837117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
18847117f1b4Smrg
18857117f1b4Smrg   bufObj = _mesa_lookup_bufferobj(ctx, id);
18867117f1b4Smrg
18873464ebd5Sriastradh   return bufObj && bufObj != &DummyBufferObject;
18887117f1b4Smrg}
18897117f1b4Smrg
18907117f1b4Smrg
189101e04c3fSmrgstatic bool
189201e04c3fSmrgvalidate_buffer_storage(struct gl_context *ctx,
189301e04c3fSmrg                        struct gl_buffer_object *bufObj, GLsizeiptr size,
189401e04c3fSmrg                        GLbitfield flags, const char *func)
18957117f1b4Smrg{
1896af69d88dSmrg   if (size <= 0) {
189701e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(size <= 0)", func);
189801e04c3fSmrg      return false;
1899af69d88dSmrg   }
19003464ebd5Sriastradh
190101e04c3fSmrg   GLbitfield valid_flags = GL_MAP_READ_BIT |
190201e04c3fSmrg                            GL_MAP_WRITE_BIT |
190301e04c3fSmrg                            GL_MAP_PERSISTENT_BIT |
190401e04c3fSmrg                            GL_MAP_COHERENT_BIT |
190501e04c3fSmrg                            GL_DYNAMIC_STORAGE_BIT |
190601e04c3fSmrg                            GL_CLIENT_STORAGE_BIT;
190701e04c3fSmrg
190801e04c3fSmrg   if (ctx->Extensions.ARB_sparse_buffer)
190901e04c3fSmrg      valid_flags |= GL_SPARSE_STORAGE_BIT_ARB;
191001e04c3fSmrg
191101e04c3fSmrg   if (flags & ~valid_flags) {
191201e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid flag bits set)", func);
191301e04c3fSmrg      return false;
191401e04c3fSmrg   }
191501e04c3fSmrg
191601e04c3fSmrg   /* The Errors section of the GL_ARB_sparse_buffer spec says:
191701e04c3fSmrg    *
191801e04c3fSmrg    *    "INVALID_VALUE is generated by BufferStorage if <flags> contains
191901e04c3fSmrg    *     SPARSE_STORAGE_BIT_ARB and <flags> also contains any combination of
192001e04c3fSmrg    *     MAP_READ_BIT or MAP_WRITE_BIT."
192101e04c3fSmrg    */
192201e04c3fSmrg   if (flags & GL_SPARSE_STORAGE_BIT_ARB &&
192301e04c3fSmrg       flags & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) {
192401e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(SPARSE_STORAGE and READ/WRITE)", func);
192501e04c3fSmrg      return false;
19267117f1b4Smrg   }
19277117f1b4Smrg
1928af69d88dSmrg   if (flags & GL_MAP_PERSISTENT_BIT &&
1929af69d88dSmrg       !(flags & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT))) {
193001e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
193101e04c3fSmrg                  "%s(PERSISTENT and flags!=READ/WRITE)", func);
193201e04c3fSmrg      return false;
1933af69d88dSmrg   }
1934af69d88dSmrg
1935af69d88dSmrg   if (flags & GL_MAP_COHERENT_BIT && !(flags & GL_MAP_PERSISTENT_BIT)) {
193601e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
193701e04c3fSmrg                  "%s(COHERENT and flags!=PERSISTENT)", func);
193801e04c3fSmrg      return false;
1939af69d88dSmrg   }
1940af69d88dSmrg
194101e04c3fSmrg   if (bufObj->Immutable || bufObj->HandleAllocated) {
194201e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(immutable)", func);
194301e04c3fSmrg      return false;
1944af69d88dSmrg   }
1945af69d88dSmrg
194601e04c3fSmrg   return true;
194701e04c3fSmrg}
194801e04c3fSmrg
194901e04c3fSmrg
195001e04c3fSmrgstatic void
195101e04c3fSmrgbuffer_storage(struct gl_context *ctx, struct gl_buffer_object *bufObj,
195201e04c3fSmrg               struct gl_memory_object *memObj, GLenum target,
195301e04c3fSmrg               GLsizeiptr size, const GLvoid *data, GLbitfield flags,
195401e04c3fSmrg               GLuint64 offset, const char *func)
195501e04c3fSmrg{
195601e04c3fSmrg   GLboolean res;
195701e04c3fSmrg
1958af69d88dSmrg   /* Unmap the existing buffer.  We'll replace it now.  Not an error. */
1959af69d88dSmrg   _mesa_buffer_unmap_all_mappings(ctx, bufObj);
1960af69d88dSmrg
19617ec681f3Smrg   FLUSH_VERTICES(ctx, 0, 0);
1962af69d88dSmrg
1963af69d88dSmrg   bufObj->Written = GL_TRUE;
1964af69d88dSmrg   bufObj->Immutable = GL_TRUE;
196501e04c3fSmrg   bufObj->MinMaxCacheDirty = true;
196601e04c3fSmrg
196701e04c3fSmrg   if (memObj) {
196801e04c3fSmrg      assert(ctx->Driver.BufferDataMem);
196901e04c3fSmrg      res = ctx->Driver.BufferDataMem(ctx, target, size, memObj, offset,
197001e04c3fSmrg                                      GL_DYNAMIC_DRAW, bufObj);
197101e04c3fSmrg   }
197201e04c3fSmrg   else {
197301e04c3fSmrg      assert(ctx->Driver.BufferData);
197401e04c3fSmrg      res = ctx->Driver.BufferData(ctx, target, size, data, GL_DYNAMIC_DRAW,
197501e04c3fSmrg                                   flags, bufObj);
197601e04c3fSmrg   }
1977af69d88dSmrg
197801e04c3fSmrg   if (!res) {
197901e04c3fSmrg      if (target == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD) {
198001e04c3fSmrg         /* Even though the interaction between AMD_pinned_memory and
198101e04c3fSmrg          * glBufferStorage is not described in the spec, Graham Sellers
198201e04c3fSmrg          * said that it should behave the same as glBufferData.
198301e04c3fSmrg          */
198401e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func);
198501e04c3fSmrg      }
198601e04c3fSmrg      else {
198701e04c3fSmrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
198801e04c3fSmrg      }
1989af69d88dSmrg   }
1990af69d88dSmrg}
1991af69d88dSmrg
1992af69d88dSmrg
199301e04c3fSmrgstatic ALWAYS_INLINE void
199401e04c3fSmrginlined_buffer_storage(GLenum target, GLuint buffer, GLsizeiptr size,
199501e04c3fSmrg                       const GLvoid *data, GLbitfield flags,
199601e04c3fSmrg                       GLuint memory, GLuint64 offset,
199701e04c3fSmrg                       bool dsa, bool mem, bool no_error, const char *func)
1998af69d88dSmrg{
1999af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
2000af69d88dSmrg   struct gl_buffer_object *bufObj;
200101e04c3fSmrg   struct gl_memory_object *memObj = NULL;
2002af69d88dSmrg
200301e04c3fSmrg   if (mem) {
200401e04c3fSmrg      if (!no_error) {
200501e04c3fSmrg         if (!ctx->Extensions.EXT_memory_object) {
200601e04c3fSmrg            _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
200701e04c3fSmrg            return;
200801e04c3fSmrg         }
2009af69d88dSmrg
201001e04c3fSmrg         /* From the EXT_external_objects spec:
201101e04c3fSmrg          *
201201e04c3fSmrg          *   "An INVALID_VALUE error is generated by BufferStorageMemEXT and
201301e04c3fSmrg          *   NamedBufferStorageMemEXT if <memory> is 0, or ..."
201401e04c3fSmrg          */
201501e04c3fSmrg         if (memory == 0) {
201601e04c3fSmrg            _mesa_error(ctx, GL_INVALID_VALUE, "%s(memory == 0)", func);
201701e04c3fSmrg         }
201801e04c3fSmrg      }
201901e04c3fSmrg
202001e04c3fSmrg      memObj = _mesa_lookup_memory_object(ctx, memory);
202101e04c3fSmrg      if (!memObj)
202201e04c3fSmrg         return;
202301e04c3fSmrg
202401e04c3fSmrg      /* From the EXT_external_objects spec:
202501e04c3fSmrg       *
202601e04c3fSmrg       *   "An INVALID_OPERATION error is generated if <memory> names a
202701e04c3fSmrg       *   valid memory object which has no associated memory."
202801e04c3fSmrg       */
202901e04c3fSmrg      if (!no_error && !memObj->Immutable) {
203001e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(no associated memory)",
203101e04c3fSmrg                     func);
203201e04c3fSmrg         return;
203301e04c3fSmrg      }
2034af69d88dSmrg   }
2035af69d88dSmrg
203601e04c3fSmrg   if (dsa) {
203701e04c3fSmrg      if (no_error) {
203801e04c3fSmrg         bufObj = _mesa_lookup_bufferobj(ctx, buffer);
203901e04c3fSmrg      } else {
204001e04c3fSmrg         bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, func);
204101e04c3fSmrg         if (!bufObj)
204201e04c3fSmrg            return;
204301e04c3fSmrg      }
204401e04c3fSmrg   } else {
204501e04c3fSmrg      if (no_error) {
204601e04c3fSmrg         struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target);
204701e04c3fSmrg         bufObj = *bufObjPtr;
204801e04c3fSmrg      } else {
204901e04c3fSmrg         bufObj = get_buffer(ctx, func, target, GL_INVALID_OPERATION);
205001e04c3fSmrg         if (!bufObj)
205101e04c3fSmrg            return;
205201e04c3fSmrg      }
205301e04c3fSmrg   }
2054af69d88dSmrg
205501e04c3fSmrg   if (no_error || validate_buffer_storage(ctx, bufObj, size, flags, func))
205601e04c3fSmrg      buffer_storage(ctx, bufObj, memObj, target, size, data, flags, offset, func);
205701e04c3fSmrg}
2058af69d88dSmrg
2059af69d88dSmrg
206001e04c3fSmrgvoid GLAPIENTRY
206101e04c3fSmrg_mesa_BufferStorage_no_error(GLenum target, GLsizeiptr size,
206201e04c3fSmrg                             const GLvoid *data, GLbitfield flags)
206301e04c3fSmrg{
206401e04c3fSmrg   inlined_buffer_storage(target, 0, size, data, flags, GL_NONE, 0,
206501e04c3fSmrg                          false, false, true, "glBufferStorage");
206601e04c3fSmrg}
20677117f1b4Smrg
206801e04c3fSmrg
206901e04c3fSmrgvoid GLAPIENTRY
207001e04c3fSmrg_mesa_BufferStorage(GLenum target, GLsizeiptr size, const GLvoid *data,
207101e04c3fSmrg                    GLbitfield flags)
207201e04c3fSmrg{
207301e04c3fSmrg   inlined_buffer_storage(target, 0, size, data, flags, GL_NONE, 0,
207401e04c3fSmrg                          false, false, false, "glBufferStorage");
207501e04c3fSmrg}
207601e04c3fSmrg
20777ec681f3Smrgvoid GLAPIENTRY
20787ec681f3Smrg_mesa_NamedBufferStorageEXT(GLuint buffer, GLsizeiptr size,
20797ec681f3Smrg                            const GLvoid *data, GLbitfield flags)
20807ec681f3Smrg{
20817ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
20827ec681f3Smrg
20837ec681f3Smrg   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
20847ec681f3Smrg   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
20857ec681f3Smrg                                     &bufObj, "glNamedBufferStorageEXT"))
20867ec681f3Smrg      return;
20877ec681f3Smrg
20887ec681f3Smrg   inlined_buffer_storage(GL_NONE, buffer, size, data, flags, GL_NONE, 0,
20897ec681f3Smrg                          true, false, false, "glNamedBufferStorageEXT");
20907ec681f3Smrg}
20917ec681f3Smrg
209201e04c3fSmrg
209301e04c3fSmrgvoid GLAPIENTRY
209401e04c3fSmrg_mesa_BufferStorageMemEXT(GLenum target, GLsizeiptr size,
209501e04c3fSmrg                          GLuint memory, GLuint64 offset)
209601e04c3fSmrg{
209701e04c3fSmrg   inlined_buffer_storage(target, 0, size, NULL, 0, memory, offset,
209801e04c3fSmrg                          false, true, false, "glBufferStorageMemEXT");
209901e04c3fSmrg}
210001e04c3fSmrg
210101e04c3fSmrg
210201e04c3fSmrgvoid GLAPIENTRY
210301e04c3fSmrg_mesa_BufferStorageMemEXT_no_error(GLenum target, GLsizeiptr size,
210401e04c3fSmrg                                   GLuint memory, GLuint64 offset)
210501e04c3fSmrg{
210601e04c3fSmrg   inlined_buffer_storage(target, 0, size, NULL, 0, memory, offset,
210701e04c3fSmrg                          false, true, true, "glBufferStorageMemEXT");
210801e04c3fSmrg}
210901e04c3fSmrg
211001e04c3fSmrg
211101e04c3fSmrgvoid GLAPIENTRY
211201e04c3fSmrg_mesa_NamedBufferStorage_no_error(GLuint buffer, GLsizeiptr size,
211301e04c3fSmrg                                  const GLvoid *data, GLbitfield flags)
211401e04c3fSmrg{
211501e04c3fSmrg   /* In direct state access, buffer objects have an unspecified target
211601e04c3fSmrg    * since they are not required to be bound.
211701e04c3fSmrg    */
211801e04c3fSmrg   inlined_buffer_storage(GL_NONE, buffer, size, data, flags, GL_NONE, 0,
211901e04c3fSmrg                          true, false, true, "glNamedBufferStorage");
212001e04c3fSmrg}
212101e04c3fSmrg
212201e04c3fSmrg
212301e04c3fSmrgvoid GLAPIENTRY
212401e04c3fSmrg_mesa_NamedBufferStorage(GLuint buffer, GLsizeiptr size, const GLvoid *data,
212501e04c3fSmrg                         GLbitfield flags)
212601e04c3fSmrg{
212701e04c3fSmrg   /* In direct state access, buffer objects have an unspecified target
212801e04c3fSmrg    * since they are not required to be bound.
212901e04c3fSmrg    */
213001e04c3fSmrg   inlined_buffer_storage(GL_NONE, buffer, size, data, flags, GL_NONE, 0,
213101e04c3fSmrg                          true, false, false, "glNamedBufferStorage");
213201e04c3fSmrg}
213301e04c3fSmrg
213401e04c3fSmrgvoid GLAPIENTRY
213501e04c3fSmrg_mesa_NamedBufferStorageMemEXT(GLuint buffer, GLsizeiptr size,
213601e04c3fSmrg                               GLuint memory, GLuint64 offset)
213701e04c3fSmrg{
213801e04c3fSmrg   inlined_buffer_storage(GL_NONE, buffer, size, GL_NONE, 0, memory, offset,
213901e04c3fSmrg                          true, true, false, "glNamedBufferStorageMemEXT");
214001e04c3fSmrg}
214101e04c3fSmrg
214201e04c3fSmrg
214301e04c3fSmrgvoid GLAPIENTRY
214401e04c3fSmrg_mesa_NamedBufferStorageMemEXT_no_error(GLuint buffer, GLsizeiptr size,
214501e04c3fSmrg                                        GLuint memory, GLuint64 offset)
214601e04c3fSmrg{
214701e04c3fSmrg   inlined_buffer_storage(GL_NONE, buffer, size, GL_NONE, 0, memory, offset,
214801e04c3fSmrg                          true, true, true, "glNamedBufferStorageMemEXT");
214901e04c3fSmrg}
215001e04c3fSmrg
215101e04c3fSmrg
215201e04c3fSmrgstatic ALWAYS_INLINE void
215301e04c3fSmrgbuffer_data(struct gl_context *ctx, struct gl_buffer_object *bufObj,
215401e04c3fSmrg            GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage,
215501e04c3fSmrg            const char *func, bool no_error)
215601e04c3fSmrg{
215701e04c3fSmrg   bool valid_usage;
215801e04c3fSmrg
215901e04c3fSmrg   if (MESA_VERBOSE & VERBOSE_API) {
216001e04c3fSmrg      _mesa_debug(ctx, "%s(%s, %ld, %p, %s)\n",
216101e04c3fSmrg                  func,
216201e04c3fSmrg                  _mesa_enum_to_string(target),
216301e04c3fSmrg                  (long int) size, data,
216401e04c3fSmrg                  _mesa_enum_to_string(usage));
21657117f1b4Smrg   }
2166af69d88dSmrg
216701e04c3fSmrg   if (!no_error) {
216801e04c3fSmrg      if (size < 0) {
216901e04c3fSmrg         _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", func);
217001e04c3fSmrg         return;
217101e04c3fSmrg      }
2172af69d88dSmrg
217301e04c3fSmrg      switch (usage) {
217401e04c3fSmrg      case GL_STREAM_DRAW_ARB:
217501e04c3fSmrg         valid_usage = (ctx->API != API_OPENGLES);
217601e04c3fSmrg         break;
217701e04c3fSmrg      case GL_STATIC_DRAW_ARB:
217801e04c3fSmrg      case GL_DYNAMIC_DRAW_ARB:
217901e04c3fSmrg         valid_usage = true;
218001e04c3fSmrg         break;
218101e04c3fSmrg      case GL_STREAM_READ_ARB:
218201e04c3fSmrg      case GL_STREAM_COPY_ARB:
218301e04c3fSmrg      case GL_STATIC_READ_ARB:
218401e04c3fSmrg      case GL_STATIC_COPY_ARB:
218501e04c3fSmrg      case GL_DYNAMIC_READ_ARB:
218601e04c3fSmrg      case GL_DYNAMIC_COPY_ARB:
218701e04c3fSmrg         valid_usage = _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx);
218801e04c3fSmrg         break;
218901e04c3fSmrg      default:
219001e04c3fSmrg         valid_usage = false;
219101e04c3fSmrg         break;
219201e04c3fSmrg      }
219301e04c3fSmrg
219401e04c3fSmrg      if (!valid_usage) {
219501e04c3fSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid usage: %s)", func,
219601e04c3fSmrg                     _mesa_enum_to_string(usage));
219701e04c3fSmrg         return;
219801e04c3fSmrg      }
219901e04c3fSmrg
220001e04c3fSmrg      if (bufObj->Immutable || bufObj->HandleAllocated) {
220101e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(immutable)", func);
220201e04c3fSmrg         return;
220301e04c3fSmrg      }
22047117f1b4Smrg   }
2205af69d88dSmrg
2206af69d88dSmrg   /* Unmap the existing buffer.  We'll replace it now.  Not an error. */
2207af69d88dSmrg   _mesa_buffer_unmap_all_mappings(ctx, bufObj);
22087117f1b4Smrg
22097ec681f3Smrg   FLUSH_VERTICES(ctx, 0, 0);
22104a49301eSmrg
22114a49301eSmrg   bufObj->Written = GL_TRUE;
221201e04c3fSmrg   bufObj->MinMaxCacheDirty = true;
22137117f1b4Smrg
22144a49301eSmrg#ifdef VBO_DEBUG
2215cdc920a0Smrg   printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n",
22164a49301eSmrg                bufObj->Name, size, data, usage);
22174a49301eSmrg#endif
22184a49301eSmrg
22194a49301eSmrg#ifdef BOUNDS_CHECK
22204a49301eSmrg   size += 100;
22214a49301eSmrg#endif
22224a49301eSmrg
222301e04c3fSmrg   assert(ctx->Driver.BufferData);
2224af69d88dSmrg   if (!ctx->Driver.BufferData(ctx, target, size, data, usage,
2225af69d88dSmrg                               GL_MAP_READ_BIT |
2226af69d88dSmrg                               GL_MAP_WRITE_BIT |
2227af69d88dSmrg                               GL_DYNAMIC_STORAGE_BIT,
2228af69d88dSmrg                               bufObj)) {
222901e04c3fSmrg      if (target == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD) {
223001e04c3fSmrg         if (!no_error) {
223101e04c3fSmrg            /* From GL_AMD_pinned_memory:
223201e04c3fSmrg             *
223301e04c3fSmrg             *   INVALID_OPERATION is generated by BufferData if <target> is
223401e04c3fSmrg             *   EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, and the store cannot be
223501e04c3fSmrg             *   mapped to the GPU address space.
223601e04c3fSmrg             */
223701e04c3fSmrg            _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func);
223801e04c3fSmrg         }
223901e04c3fSmrg      } else {
224001e04c3fSmrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
224101e04c3fSmrg      }
224201e04c3fSmrg   }
224301e04c3fSmrg}
224401e04c3fSmrg
224501e04c3fSmrgstatic void
224601e04c3fSmrgbuffer_data_error(struct gl_context *ctx, struct gl_buffer_object *bufObj,
224701e04c3fSmrg                  GLenum target, GLsizeiptr size, const GLvoid *data,
224801e04c3fSmrg                  GLenum usage, const char *func)
224901e04c3fSmrg{
225001e04c3fSmrg   buffer_data(ctx, bufObj, target, size, data, usage, func, false);
225101e04c3fSmrg}
225201e04c3fSmrg
225301e04c3fSmrgstatic void
225401e04c3fSmrgbuffer_data_no_error(struct gl_context *ctx, struct gl_buffer_object *bufObj,
225501e04c3fSmrg                     GLenum target, GLsizeiptr size, const GLvoid *data,
225601e04c3fSmrg                     GLenum usage, const char *func)
225701e04c3fSmrg{
225801e04c3fSmrg   buffer_data(ctx, bufObj, target, size, data, usage, func, true);
225901e04c3fSmrg}
226001e04c3fSmrg
226101e04c3fSmrgvoid
226201e04c3fSmrg_mesa_buffer_data(struct gl_context *ctx, struct gl_buffer_object *bufObj,
226301e04c3fSmrg                  GLenum target, GLsizeiptr size, const GLvoid *data,
226401e04c3fSmrg                  GLenum usage, const char *func)
226501e04c3fSmrg{
226601e04c3fSmrg   buffer_data_error(ctx, bufObj, target, size, data, usage, func);
226701e04c3fSmrg}
226801e04c3fSmrg
226901e04c3fSmrgvoid GLAPIENTRY
227001e04c3fSmrg_mesa_BufferData_no_error(GLenum target, GLsizeiptr size, const GLvoid *data,
227101e04c3fSmrg                          GLenum usage)
227201e04c3fSmrg{
227301e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
227401e04c3fSmrg
227501e04c3fSmrg   struct gl_buffer_object **bufObj = get_buffer_target(ctx, target);
227601e04c3fSmrg   buffer_data_no_error(ctx, *bufObj, target, size, data, usage,
227701e04c3fSmrg                        "glBufferData");
227801e04c3fSmrg}
227901e04c3fSmrg
228001e04c3fSmrgvoid GLAPIENTRY
228101e04c3fSmrg_mesa_BufferData(GLenum target, GLsizeiptr size,
228201e04c3fSmrg                 const GLvoid *data, GLenum usage)
228301e04c3fSmrg{
228401e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
228501e04c3fSmrg   struct gl_buffer_object *bufObj;
228601e04c3fSmrg
228701e04c3fSmrg   bufObj = get_buffer(ctx, "glBufferData", target, GL_INVALID_OPERATION);
228801e04c3fSmrg   if (!bufObj)
228901e04c3fSmrg      return;
229001e04c3fSmrg
229101e04c3fSmrg   _mesa_buffer_data(ctx, bufObj, target, size, data, usage,
229201e04c3fSmrg                     "glBufferData");
229301e04c3fSmrg}
229401e04c3fSmrg
229501e04c3fSmrgvoid GLAPIENTRY
229601e04c3fSmrg_mesa_NamedBufferData_no_error(GLuint buffer, GLsizeiptr size,
229701e04c3fSmrg                               const GLvoid *data, GLenum usage)
229801e04c3fSmrg{
229901e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
230001e04c3fSmrg
230101e04c3fSmrg   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
230201e04c3fSmrg   buffer_data_no_error(ctx, bufObj, GL_NONE, size, data, usage,
230301e04c3fSmrg                        "glNamedBufferData");
230401e04c3fSmrg}
230501e04c3fSmrg
230601e04c3fSmrgvoid GLAPIENTRY
230701e04c3fSmrg_mesa_NamedBufferData(GLuint buffer, GLsizeiptr size, const GLvoid *data,
230801e04c3fSmrg                      GLenum usage)
230901e04c3fSmrg{
231001e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
231101e04c3fSmrg   struct gl_buffer_object *bufObj;
231201e04c3fSmrg
231301e04c3fSmrg   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glNamedBufferData");
231401e04c3fSmrg   if (!bufObj)
231501e04c3fSmrg      return;
231601e04c3fSmrg
231701e04c3fSmrg   /* In direct state access, buffer objects have an unspecified target since
231801e04c3fSmrg    * they are not required to be bound.
231901e04c3fSmrg    */
232001e04c3fSmrg   _mesa_buffer_data(ctx, bufObj, GL_NONE, size, data, usage,
232101e04c3fSmrg                     "glNamedBufferData");
232201e04c3fSmrg}
232301e04c3fSmrg
23247ec681f3Smrgvoid GLAPIENTRY
23257ec681f3Smrg_mesa_NamedBufferDataEXT(GLuint buffer, GLsizeiptr size, const GLvoid *data,
23267ec681f3Smrg                         GLenum usage)
23277ec681f3Smrg{
23287ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
23297ec681f3Smrg   struct gl_buffer_object *bufObj;
23307ec681f3Smrg
23317ec681f3Smrg   if (!buffer) {
23327ec681f3Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
23337ec681f3Smrg                  "glNamedBufferDataEXT(buffer=0)");
23347ec681f3Smrg      return;
23357ec681f3Smrg   }
23367ec681f3Smrg
23377ec681f3Smrg   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
23387ec681f3Smrg   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
23397ec681f3Smrg                                     &bufObj, "glNamedBufferDataEXT"))
23407ec681f3Smrg      return;
23417ec681f3Smrg
23427ec681f3Smrg   _mesa_buffer_data(ctx, bufObj, GL_NONE, size, data, usage,
23437ec681f3Smrg                     "glNamedBufferDataEXT");
23447ec681f3Smrg}
234501e04c3fSmrg
234601e04c3fSmrgstatic bool
234701e04c3fSmrgvalidate_buffer_sub_data(struct gl_context *ctx,
234801e04c3fSmrg                         struct gl_buffer_object *bufObj,
234901e04c3fSmrg                         GLintptr offset, GLsizeiptr size,
235001e04c3fSmrg                         const char *func)
235101e04c3fSmrg{
235201e04c3fSmrg   if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size,
235301e04c3fSmrg                                         true, func)) {
235401e04c3fSmrg      /* error already recorded */
235501e04c3fSmrg      return false;
235601e04c3fSmrg   }
235701e04c3fSmrg
235801e04c3fSmrg   if (bufObj->Immutable &&
235901e04c3fSmrg       !(bufObj->StorageFlags & GL_DYNAMIC_STORAGE_BIT)) {
236001e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func);
236101e04c3fSmrg      return false;
236201e04c3fSmrg   }
236301e04c3fSmrg
236401e04c3fSmrg   if ((bufObj->Usage == GL_STATIC_DRAW ||
236501e04c3fSmrg        bufObj->Usage == GL_STATIC_COPY) &&
236601e04c3fSmrg       bufObj->NumSubDataCalls >= BUFFER_WARNING_CALL_COUNT - 1) {
236701e04c3fSmrg      /* If the application declared the buffer as static draw/copy or stream
236801e04c3fSmrg       * draw, it should not be frequently modified with glBufferSubData.
236901e04c3fSmrg       */
237001e04c3fSmrg      BUFFER_USAGE_WARNING(ctx,
237101e04c3fSmrg                           "using %s(buffer %u, offset %u, size %u) to "
237201e04c3fSmrg                           "update a %s buffer",
237301e04c3fSmrg                           func, bufObj->Name, offset, size,
237401e04c3fSmrg                           _mesa_enum_to_string(bufObj->Usage));
237501e04c3fSmrg   }
237601e04c3fSmrg
237701e04c3fSmrg   return true;
237801e04c3fSmrg}
237901e04c3fSmrg
238001e04c3fSmrg
238101e04c3fSmrg/**
238201e04c3fSmrg * Implementation for glBufferSubData and glNamedBufferSubData.
238301e04c3fSmrg *
238401e04c3fSmrg * \param ctx     GL context.
238501e04c3fSmrg * \param bufObj  The buffer object.
238601e04c3fSmrg * \param offset  Offset of the first byte of the subdata range.
238701e04c3fSmrg * \param size    Size, in bytes, of the subdata range.
238801e04c3fSmrg * \param data    The data store.
238901e04c3fSmrg * \param func  Name of calling function for recording errors.
239001e04c3fSmrg *
239101e04c3fSmrg */
239201e04c3fSmrgvoid
239301e04c3fSmrg_mesa_buffer_sub_data(struct gl_context *ctx, struct gl_buffer_object *bufObj,
239401e04c3fSmrg                      GLintptr offset, GLsizeiptr size, const GLvoid *data)
239501e04c3fSmrg{
239601e04c3fSmrg   if (size == 0)
239701e04c3fSmrg      return;
239801e04c3fSmrg
239901e04c3fSmrg   bufObj->NumSubDataCalls++;
240001e04c3fSmrg   bufObj->Written = GL_TRUE;
240101e04c3fSmrg   bufObj->MinMaxCacheDirty = true;
240201e04c3fSmrg
240301e04c3fSmrg   assert(ctx->Driver.BufferSubData);
240401e04c3fSmrg   ctx->Driver.BufferSubData(ctx, offset, size, data, bufObj);
240501e04c3fSmrg}
240601e04c3fSmrg
240701e04c3fSmrg
240801e04c3fSmrgstatic ALWAYS_INLINE void
240901e04c3fSmrgbuffer_sub_data(GLenum target, GLuint buffer, GLintptr offset,
241001e04c3fSmrg                GLsizeiptr size, const GLvoid *data,
241101e04c3fSmrg                bool dsa, bool no_error, const char *func)
241201e04c3fSmrg{
241301e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
241401e04c3fSmrg   struct gl_buffer_object *bufObj;
241501e04c3fSmrg
241601e04c3fSmrg   if (dsa) {
241701e04c3fSmrg      if (no_error) {
241801e04c3fSmrg         bufObj = _mesa_lookup_bufferobj(ctx, buffer);
241901e04c3fSmrg      } else {
242001e04c3fSmrg         bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, func);
242101e04c3fSmrg         if (!bufObj)
242201e04c3fSmrg            return;
242301e04c3fSmrg      }
242401e04c3fSmrg   } else {
242501e04c3fSmrg      if (no_error) {
242601e04c3fSmrg         struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target);
242701e04c3fSmrg         bufObj = *bufObjPtr;
242801e04c3fSmrg      } else {
242901e04c3fSmrg         bufObj = get_buffer(ctx, func, target, GL_INVALID_OPERATION);
243001e04c3fSmrg         if (!bufObj)
243101e04c3fSmrg            return;
243201e04c3fSmrg      }
24334a49301eSmrg   }
243401e04c3fSmrg
243501e04c3fSmrg   if (no_error || validate_buffer_sub_data(ctx, bufObj, offset, size, func))
243601e04c3fSmrg      _mesa_buffer_sub_data(ctx, bufObj, offset, size, data);
243701e04c3fSmrg}
243801e04c3fSmrg
243901e04c3fSmrg
244001e04c3fSmrgvoid GLAPIENTRY
244101e04c3fSmrg_mesa_BufferSubData_no_error(GLenum target, GLintptr offset,
244201e04c3fSmrg                             GLsizeiptr size, const GLvoid *data)
244301e04c3fSmrg{
244401e04c3fSmrg   buffer_sub_data(target, 0, offset, size, data, false, true,
244501e04c3fSmrg                   "glBufferSubData");
244601e04c3fSmrg}
244701e04c3fSmrg
244801e04c3fSmrg
244901e04c3fSmrgvoid GLAPIENTRY
245001e04c3fSmrg_mesa_BufferSubData(GLenum target, GLintptr offset,
245101e04c3fSmrg                    GLsizeiptr size, const GLvoid *data)
245201e04c3fSmrg{
245301e04c3fSmrg   buffer_sub_data(target, 0, offset, size, data, false, false,
245401e04c3fSmrg                   "glBufferSubData");
245501e04c3fSmrg}
245601e04c3fSmrg
245701e04c3fSmrgvoid GLAPIENTRY
245801e04c3fSmrg_mesa_NamedBufferSubData_no_error(GLuint buffer, GLintptr offset,
245901e04c3fSmrg                                  GLsizeiptr size, const GLvoid *data)
246001e04c3fSmrg{
246101e04c3fSmrg   buffer_sub_data(0, buffer, offset, size, data, true, true,
246201e04c3fSmrg                   "glNamedBufferSubData");
246301e04c3fSmrg}
246401e04c3fSmrg
246501e04c3fSmrgvoid GLAPIENTRY
246601e04c3fSmrg_mesa_NamedBufferSubData(GLuint buffer, GLintptr offset,
246701e04c3fSmrg                         GLsizeiptr size, const GLvoid *data)
246801e04c3fSmrg{
246901e04c3fSmrg   buffer_sub_data(0, buffer, offset, size, data, true, false,
247001e04c3fSmrg                   "glNamedBufferSubData");
24717117f1b4Smrg}
24727117f1b4Smrg
24737ec681f3Smrgvoid GLAPIENTRY
24747ec681f3Smrg_mesa_NamedBufferSubDataEXT(GLuint buffer, GLintptr offset,
24757ec681f3Smrg                            GLsizeiptr size, const GLvoid *data)
24767ec681f3Smrg{
24777ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
24787ec681f3Smrg   struct gl_buffer_object *bufObj;
24797ec681f3Smrg
24807ec681f3Smrg   if (!buffer) {
24817ec681f3Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
24827ec681f3Smrg                  "glNamedBufferSubDataEXT(buffer=0)");
24837ec681f3Smrg      return;
24847ec681f3Smrg   }
24857ec681f3Smrg
24867ec681f3Smrg   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
24877ec681f3Smrg   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
24887ec681f3Smrg                                     &bufObj, "glNamedBufferSubDataEXT"))
24897ec681f3Smrg      return;
24907ec681f3Smrg
24917ec681f3Smrg   if (validate_buffer_sub_data(ctx, bufObj, offset, size,
24927ec681f3Smrg                                "glNamedBufferSubDataEXT")) {
24937ec681f3Smrg      _mesa_buffer_sub_data(ctx, bufObj, offset, size, data);
24947ec681f3Smrg   }
24957ec681f3Smrg}
24967ec681f3Smrg
24977117f1b4Smrg
24987117f1b4Smrgvoid GLAPIENTRY
249901e04c3fSmrg_mesa_GetBufferSubData(GLenum target, GLintptr offset,
250001e04c3fSmrg                       GLsizeiptr size, GLvoid *data)
25017117f1b4Smrg{
25027117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
25037117f1b4Smrg   struct gl_buffer_object *bufObj;
25047117f1b4Smrg
250501e04c3fSmrg   bufObj = get_buffer(ctx, "glGetBufferSubData", target,
250601e04c3fSmrg                       GL_INVALID_OPERATION);
250701e04c3fSmrg   if (!bufObj)
25087117f1b4Smrg      return;
25097117f1b4Smrg
251001e04c3fSmrg   if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size, false,
251101e04c3fSmrg                                         "glGetBufferSubData")) {
2512af69d88dSmrg      return;
2513af69d88dSmrg   }
2514af69d88dSmrg
251501e04c3fSmrg   assert(ctx->Driver.GetBufferSubData);
251601e04c3fSmrg   ctx->Driver.GetBufferSubData(ctx, offset, size, data, bufObj);
25177117f1b4Smrg}
25187117f1b4Smrg
25197117f1b4Smrgvoid GLAPIENTRY
252001e04c3fSmrg_mesa_GetNamedBufferSubData(GLuint buffer, GLintptr offset,
252101e04c3fSmrg                            GLsizeiptr size, GLvoid *data)
25227117f1b4Smrg{
25237117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
25247117f1b4Smrg   struct gl_buffer_object *bufObj;
25257117f1b4Smrg
252601e04c3fSmrg   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer,
252701e04c3fSmrg                                       "glGetNamedBufferSubData");
252801e04c3fSmrg   if (!bufObj)
252901e04c3fSmrg      return;
253001e04c3fSmrg
253101e04c3fSmrg   if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size, false,
253201e04c3fSmrg                                         "glGetNamedBufferSubData")) {
25337117f1b4Smrg      return;
25347117f1b4Smrg   }
25357117f1b4Smrg
253601e04c3fSmrg   assert(ctx->Driver.GetBufferSubData);
253701e04c3fSmrg   ctx->Driver.GetBufferSubData(ctx, offset, size, data, bufObj);
2538af69d88dSmrg}
2539af69d88dSmrg
2540af69d88dSmrg
25417ec681f3Smrgvoid GLAPIENTRY
25427ec681f3Smrg_mesa_GetNamedBufferSubDataEXT(GLuint buffer, GLintptr offset,
25437ec681f3Smrg                               GLsizeiptr size, GLvoid *data)
25447ec681f3Smrg{
25457ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
25467ec681f3Smrg   struct gl_buffer_object *bufObj;
25477ec681f3Smrg
25487ec681f3Smrg   if (!buffer) {
25497ec681f3Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
25507ec681f3Smrg                  "glGetNamedBufferSubDataEXT(buffer=0)");
25517ec681f3Smrg      return;
25527ec681f3Smrg   }
25537ec681f3Smrg
25547ec681f3Smrg   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
25557ec681f3Smrg   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
25567ec681f3Smrg                                     &bufObj, "glGetNamedBufferSubDataEXT"))
25577ec681f3Smrg      return;
25587ec681f3Smrg
25597ec681f3Smrg   if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size, false,
25607ec681f3Smrg                                         "glGetNamedBufferSubDataEXT")) {
25617ec681f3Smrg      return;
25627ec681f3Smrg   }
25637ec681f3Smrg
25647ec681f3Smrg   assert(ctx->Driver.GetBufferSubData);
25657ec681f3Smrg   ctx->Driver.GetBufferSubData(ctx, offset, size, data, bufObj);
25667ec681f3Smrg}
25677ec681f3Smrg
256801e04c3fSmrg/**
256901e04c3fSmrg * \param subdata   true if caller is *SubData, false if *Data
257001e04c3fSmrg */
257101e04c3fSmrgstatic ALWAYS_INLINE void
257201e04c3fSmrgclear_buffer_sub_data(struct gl_context *ctx, struct gl_buffer_object *bufObj,
257301e04c3fSmrg                      GLenum internalformat, GLintptr offset, GLsizeiptr size,
257401e04c3fSmrg                      GLenum format, GLenum type, const GLvoid *data,
257501e04c3fSmrg                      const char *func, bool subdata, bool no_error)
2576af69d88dSmrg{
2577af69d88dSmrg   mesa_format mesaFormat;
2578af69d88dSmrg   GLubyte clearValue[MAX_PIXEL_BYTES];
2579af69d88dSmrg   GLsizeiptr clearValueSize;
2580af69d88dSmrg
258101e04c3fSmrg   /* This checks for disallowed mappings. */
258201e04c3fSmrg   if (!no_error && !buffer_object_subdata_range_good(ctx, bufObj, offset, size,
258301e04c3fSmrg                                                      subdata, func)) {
2584af69d88dSmrg      return;
2585af69d88dSmrg   }
2586af69d88dSmrg
258701e04c3fSmrg   if (no_error) {
258801e04c3fSmrg      mesaFormat = _mesa_get_texbuffer_format(ctx, internalformat);
258901e04c3fSmrg   } else {
259001e04c3fSmrg      mesaFormat = validate_clear_buffer_format(ctx, internalformat,
259101e04c3fSmrg                                                format, type, func);
2592af69d88dSmrg   }
2593af69d88dSmrg
259401e04c3fSmrg   if (mesaFormat == MESA_FORMAT_NONE)
2595af69d88dSmrg      return;
2596af69d88dSmrg
2597af69d88dSmrg   clearValueSize = _mesa_get_format_bytes(mesaFormat);
259801e04c3fSmrg   if (!no_error &&
259901e04c3fSmrg       (offset % clearValueSize != 0 || size % clearValueSize != 0)) {
2600af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
260101e04c3fSmrg                  "%s(offset or size is not a multiple of "
260201e04c3fSmrg                  "internalformat size)", func);
2603af69d88dSmrg      return;
2604af69d88dSmrg   }
2605af69d88dSmrg
260601e04c3fSmrg   /* Bail early. Negative size has already been checked. */
260701e04c3fSmrg   if (size == 0)
260801e04c3fSmrg      return;
260901e04c3fSmrg
261001e04c3fSmrg   bufObj->MinMaxCacheDirty = true;
261101e04c3fSmrg
2612af69d88dSmrg   if (data == NULL) {
2613af69d88dSmrg      /* clear to zeros, per the spec */
261401e04c3fSmrg      ctx->Driver.ClearBufferSubData(ctx, offset, size,
2615af69d88dSmrg                                     NULL, clearValueSize, bufObj);
2616af69d88dSmrg      return;
2617af69d88dSmrg   }
2618af69d88dSmrg
2619af69d88dSmrg   if (!convert_clear_buffer_data(ctx, mesaFormat, clearValue,
262001e04c3fSmrg                                  format, type, data, func)) {
2621af69d88dSmrg      return;
2622af69d88dSmrg   }
2623af69d88dSmrg
262401e04c3fSmrg   ctx->Driver.ClearBufferSubData(ctx, offset, size,
2625af69d88dSmrg                                  clearValue, clearValueSize, bufObj);
2626af69d88dSmrg}
2627af69d88dSmrg
262801e04c3fSmrgstatic void
262901e04c3fSmrgclear_buffer_sub_data_error(struct gl_context *ctx,
263001e04c3fSmrg                            struct gl_buffer_object *bufObj,
263101e04c3fSmrg                            GLenum internalformat, GLintptr offset,
263201e04c3fSmrg                            GLsizeiptr size, GLenum format, GLenum type,
263301e04c3fSmrg                            const GLvoid *data, const char *func, bool subdata)
263401e04c3fSmrg{
263501e04c3fSmrg   clear_buffer_sub_data(ctx, bufObj, internalformat, offset, size, format,
263601e04c3fSmrg                         type, data, func, subdata, false);
263701e04c3fSmrg}
263801e04c3fSmrg
263901e04c3fSmrg
264001e04c3fSmrgstatic void
264101e04c3fSmrgclear_buffer_sub_data_no_error(struct gl_context *ctx,
264201e04c3fSmrg                               struct gl_buffer_object *bufObj,
264301e04c3fSmrg                               GLenum internalformat, GLintptr offset,
264401e04c3fSmrg                               GLsizeiptr size, GLenum format, GLenum type,
264501e04c3fSmrg                               const GLvoid *data, const char *func,
264601e04c3fSmrg                               bool subdata)
264701e04c3fSmrg{
264801e04c3fSmrg   clear_buffer_sub_data(ctx, bufObj, internalformat, offset, size, format,
264901e04c3fSmrg                         type, data, func, subdata, true);
265001e04c3fSmrg}
265101e04c3fSmrg
2652af69d88dSmrg
2653af69d88dSmrgvoid GLAPIENTRY
265401e04c3fSmrg_mesa_ClearBufferData_no_error(GLenum target, GLenum internalformat,
265501e04c3fSmrg                               GLenum format, GLenum type, const GLvoid *data)
2656af69d88dSmrg{
2657af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
2658af69d88dSmrg
265901e04c3fSmrg   struct gl_buffer_object **bufObj = get_buffer_target(ctx, target);
266001e04c3fSmrg   clear_buffer_sub_data_no_error(ctx, *bufObj, internalformat, 0,
266101e04c3fSmrg                                  (*bufObj)->Size, format, type, data,
266201e04c3fSmrg                                  "glClearBufferData", false);
266301e04c3fSmrg}
2664af69d88dSmrg
2665af69d88dSmrg
266601e04c3fSmrgvoid GLAPIENTRY
266701e04c3fSmrg_mesa_ClearBufferData(GLenum target, GLenum internalformat, GLenum format,
266801e04c3fSmrg                      GLenum type, const GLvoid *data)
266901e04c3fSmrg{
267001e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
267101e04c3fSmrg   struct gl_buffer_object *bufObj;
2672af69d88dSmrg
267301e04c3fSmrg   bufObj = get_buffer(ctx, "glClearBufferData", target, GL_INVALID_VALUE);
267401e04c3fSmrg   if (!bufObj)
2675af69d88dSmrg      return;
2676af69d88dSmrg
267701e04c3fSmrg   clear_buffer_sub_data_error(ctx, bufObj, internalformat, 0, bufObj->Size,
267801e04c3fSmrg                               format, type, data, "glClearBufferData", false);
26797117f1b4Smrg}
26807117f1b4Smrg
26817117f1b4Smrg
268201e04c3fSmrgvoid GLAPIENTRY
268301e04c3fSmrg_mesa_ClearNamedBufferData_no_error(GLuint buffer, GLenum internalformat,
268401e04c3fSmrg                                    GLenum format, GLenum type,
268501e04c3fSmrg                                    const GLvoid *data)
26867117f1b4Smrg{
26877117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
26884a49301eSmrg
268901e04c3fSmrg   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
269001e04c3fSmrg   clear_buffer_sub_data_no_error(ctx, bufObj, internalformat, 0, bufObj->Size,
269101e04c3fSmrg                                  format, type, data, "glClearNamedBufferData",
269201e04c3fSmrg                                  false);
269301e04c3fSmrg}
26947117f1b4Smrg
2695af69d88dSmrg
269601e04c3fSmrgvoid GLAPIENTRY
269701e04c3fSmrg_mesa_ClearNamedBufferData(GLuint buffer, GLenum internalformat,
269801e04c3fSmrg                           GLenum format, GLenum type, const GLvoid *data)
269901e04c3fSmrg{
270001e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
270101e04c3fSmrg   struct gl_buffer_object *bufObj;
27027117f1b4Smrg
270301e04c3fSmrg   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glClearNamedBufferData");
2704af69d88dSmrg   if (!bufObj)
270501e04c3fSmrg      return;
2706af69d88dSmrg
270701e04c3fSmrg   clear_buffer_sub_data_error(ctx, bufObj, internalformat, 0, bufObj->Size,
270801e04c3fSmrg                               format, type, data, "glClearNamedBufferData",
270901e04c3fSmrg                               false);
271001e04c3fSmrg}
2711af69d88dSmrg
2712af69d88dSmrg
27137ec681f3Smrgvoid GLAPIENTRY
27147ec681f3Smrg_mesa_ClearNamedBufferDataEXT(GLuint buffer, GLenum internalformat,
27157ec681f3Smrg                              GLenum format, GLenum type, const GLvoid *data)
27167ec681f3Smrg{
27177ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
27187ec681f3Smrg   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
27197ec681f3Smrg   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
27207ec681f3Smrg                                     &bufObj, "glClearNamedBufferDataEXT"))
27217ec681f3Smrg      return;
27227ec681f3Smrg
27237ec681f3Smrg   clear_buffer_sub_data_error(ctx, bufObj, internalformat, 0, bufObj->Size,
27247ec681f3Smrg                               format, type, data, "glClearNamedBufferDataEXT",
27257ec681f3Smrg                               false);
27267ec681f3Smrg}
27277ec681f3Smrg
27287ec681f3Smrg
272901e04c3fSmrgvoid GLAPIENTRY
273001e04c3fSmrg_mesa_ClearBufferSubData_no_error(GLenum target, GLenum internalformat,
273101e04c3fSmrg                                  GLintptr offset, GLsizeiptr size,
273201e04c3fSmrg                                  GLenum format, GLenum type,
273301e04c3fSmrg                                  const GLvoid *data)
273401e04c3fSmrg{
273501e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
27367117f1b4Smrg
273701e04c3fSmrg   struct gl_buffer_object **bufObj = get_buffer_target(ctx, target);
273801e04c3fSmrg   clear_buffer_sub_data_no_error(ctx, *bufObj, internalformat, offset, size,
273901e04c3fSmrg                                  format, type, data, "glClearBufferSubData",
274001e04c3fSmrg                                  true);
274101e04c3fSmrg}
2742af69d88dSmrg
27437117f1b4Smrg
274401e04c3fSmrgvoid GLAPIENTRY
274501e04c3fSmrg_mesa_ClearBufferSubData(GLenum target, GLenum internalformat,
274601e04c3fSmrg                         GLintptr offset, GLsizeiptr size,
274701e04c3fSmrg                         GLenum format, GLenum type,
274801e04c3fSmrg                         const GLvoid *data)
274901e04c3fSmrg{
275001e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
275101e04c3fSmrg   struct gl_buffer_object *bufObj;
27524a49301eSmrg
275301e04c3fSmrg   bufObj = get_buffer(ctx, "glClearBufferSubData", target, GL_INVALID_VALUE);
275401e04c3fSmrg   if (!bufObj)
275501e04c3fSmrg      return;
275601e04c3fSmrg
275701e04c3fSmrg   clear_buffer_sub_data_error(ctx, bufObj, internalformat, offset, size,
275801e04c3fSmrg                               format, type, data, "glClearBufferSubData",
275901e04c3fSmrg                               true);
276001e04c3fSmrg}
27614a49301eSmrg
27627117f1b4Smrg
276301e04c3fSmrgvoid GLAPIENTRY
276401e04c3fSmrg_mesa_ClearNamedBufferSubData_no_error(GLuint buffer, GLenum internalformat,
276501e04c3fSmrg                                       GLintptr offset, GLsizeiptr size,
276601e04c3fSmrg                                       GLenum format, GLenum type,
276701e04c3fSmrg                                       const GLvoid *data)
276801e04c3fSmrg{
276901e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
277001e04c3fSmrg
277101e04c3fSmrg   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
277201e04c3fSmrg   clear_buffer_sub_data_no_error(ctx, bufObj, internalformat, offset, size,
277301e04c3fSmrg                                  format, type, data,
277401e04c3fSmrg                                  "glClearNamedBufferSubData", true);
27757117f1b4Smrg}
27767117f1b4Smrg
27777117f1b4Smrg
277801e04c3fSmrgvoid GLAPIENTRY
277901e04c3fSmrg_mesa_ClearNamedBufferSubData(GLuint buffer, GLenum internalformat,
278001e04c3fSmrg                              GLintptr offset, GLsizeiptr size,
278101e04c3fSmrg                              GLenum format, GLenum type,
278201e04c3fSmrg                              const GLvoid *data)
27837117f1b4Smrg{
27847117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
27857117f1b4Smrg   struct gl_buffer_object *bufObj;
27867117f1b4Smrg
278701e04c3fSmrg   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer,
278801e04c3fSmrg                                       "glClearNamedBufferSubData");
2789af69d88dSmrg   if (!bufObj)
279001e04c3fSmrg      return;
279101e04c3fSmrg
279201e04c3fSmrg   clear_buffer_sub_data_error(ctx, bufObj, internalformat, offset, size,
279301e04c3fSmrg                               format, type, data, "glClearNamedBufferSubData",
279401e04c3fSmrg                               true);
279501e04c3fSmrg}
279601e04c3fSmrg
27977ec681f3Smrgvoid GLAPIENTRY
27987ec681f3Smrg_mesa_ClearNamedBufferSubDataEXT(GLuint buffer, GLenum internalformat,
27997ec681f3Smrg                                 GLintptr offset, GLsizeiptr size,
28007ec681f3Smrg                                 GLenum format, GLenum type,
28017ec681f3Smrg                                 const GLvoid *data)
28027ec681f3Smrg{
28037ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
28047ec681f3Smrg   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
28057ec681f3Smrg   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
28067ec681f3Smrg                                     &bufObj, "glClearNamedBufferSubDataEXT"))
28077ec681f3Smrg      return;
28087ec681f3Smrg
28097ec681f3Smrg   clear_buffer_sub_data_error(ctx, bufObj, internalformat, offset, size,
28107ec681f3Smrg                               format, type, data, "glClearNamedBufferSubDataEXT",
28117ec681f3Smrg                               true);
28127ec681f3Smrg}
28137ec681f3Smrg
281401e04c3fSmrgstatic GLboolean
281501e04c3fSmrgunmap_buffer(struct gl_context *ctx, struct gl_buffer_object *bufObj)
281601e04c3fSmrg{
281701e04c3fSmrg   GLboolean status = ctx->Driver.UnmapBuffer(ctx, bufObj, MAP_USER);
281801e04c3fSmrg   bufObj->Mappings[MAP_USER].AccessFlags = 0;
281901e04c3fSmrg   assert(bufObj->Mappings[MAP_USER].Pointer == NULL);
282001e04c3fSmrg   assert(bufObj->Mappings[MAP_USER].Offset == 0);
282101e04c3fSmrg   assert(bufObj->Mappings[MAP_USER].Length == 0);
282201e04c3fSmrg
282301e04c3fSmrg   return status;
282401e04c3fSmrg}
282501e04c3fSmrg
282601e04c3fSmrgstatic GLboolean
282701e04c3fSmrgvalidate_and_unmap_buffer(struct gl_context *ctx,
282801e04c3fSmrg                          struct gl_buffer_object *bufObj,
282901e04c3fSmrg                          const char *func)
283001e04c3fSmrg{
283101e04c3fSmrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
2832af69d88dSmrg
2833af69d88dSmrg   if (!_mesa_bufferobj_mapped(bufObj, MAP_USER)) {
283401e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
283501e04c3fSmrg                  "%s(buffer is not mapped)", func);
28367117f1b4Smrg      return GL_FALSE;
28377117f1b4Smrg   }
28387117f1b4Smrg
28394a49301eSmrg#ifdef BOUNDS_CHECK
28407ec681f3Smrg   if (bufObj->Mappings[MAP_USER].AccessFlags != GL_READ_ONLY_ARB) {
28417ec681f3Smrg      GLubyte *buf = (GLubyte *) bufObj->Mappings[MAP_USER].Pointer;
28424a49301eSmrg      GLuint i;
28434a49301eSmrg      /* check that last 100 bytes are still = magic value */
28444a49301eSmrg      for (i = 0; i < 100; i++) {
28454a49301eSmrg         GLuint pos = bufObj->Size - i - 1;
28464a49301eSmrg         if (buf[pos] != 123) {
28474a49301eSmrg            _mesa_warning(ctx, "Out of bounds buffer object write detected"
28484a49301eSmrg                          " at position %d (value = %u)\n",
28494a49301eSmrg                          pos, buf[pos]);
28504a49301eSmrg         }
28514a49301eSmrg      }
28524a49301eSmrg   }
28534a49301eSmrg#endif
28544a49301eSmrg
28554a49301eSmrg#ifdef VBO_DEBUG
28567ec681f3Smrg   if (bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_WRITE_BIT) {
28574a49301eSmrg      GLuint i, unchanged = 0;
28587ec681f3Smrg      GLubyte *b = (GLubyte *) bufObj->Mappings[MAP_USER].Pointer;
28594a49301eSmrg      GLint pos = -1;
28604a49301eSmrg      /* check which bytes changed */
28614a49301eSmrg      for (i = 0; i < bufObj->Size - 1; i++) {
28624a49301eSmrg         if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) {
28634a49301eSmrg            unchanged++;
28644a49301eSmrg            if (pos == -1)
28654a49301eSmrg               pos = i;
28664a49301eSmrg         }
28674a49301eSmrg      }
28684a49301eSmrg      if (unchanged) {
2869cdc920a0Smrg         printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n",
28704a49301eSmrg                      bufObj->Name, unchanged, bufObj->Size, pos);
28714a49301eSmrg      }
28724a49301eSmrg   }
28734a49301eSmrg#endif
28744a49301eSmrg
287501e04c3fSmrg   return unmap_buffer(ctx, bufObj);
28767117f1b4Smrg}
28777117f1b4Smrg
287801e04c3fSmrgGLboolean GLAPIENTRY
287901e04c3fSmrg_mesa_UnmapBuffer_no_error(GLenum target)
288001e04c3fSmrg{
288101e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
288201e04c3fSmrg   struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target);
288301e04c3fSmrg   struct gl_buffer_object *bufObj = *bufObjPtr;
288401e04c3fSmrg
288501e04c3fSmrg   return unmap_buffer(ctx, bufObj);
288601e04c3fSmrg}
28877117f1b4Smrg
288801e04c3fSmrgGLboolean GLAPIENTRY
288901e04c3fSmrg_mesa_UnmapBuffer(GLenum target)
28907117f1b4Smrg{
28917117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
28927117f1b4Smrg   struct gl_buffer_object *bufObj;
28937117f1b4Smrg
289401e04c3fSmrg   bufObj = get_buffer(ctx, "glUnmapBuffer", target, GL_INVALID_OPERATION);
2895af69d88dSmrg   if (!bufObj)
289601e04c3fSmrg      return GL_FALSE;
28973464ebd5Sriastradh
289801e04c3fSmrg   return validate_and_unmap_buffer(ctx, bufObj, "glUnmapBuffer");
2899cdc920a0Smrg}
2900cdc920a0Smrg
290101e04c3fSmrgGLboolean GLAPIENTRY
29027ec681f3Smrg_mesa_UnmapNamedBufferEXT_no_error(GLuint buffer)
290301e04c3fSmrg{
290401e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
290501e04c3fSmrg   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
2906cdc920a0Smrg
290701e04c3fSmrg   return unmap_buffer(ctx, bufObj);
290801e04c3fSmrg}
290901e04c3fSmrg
291001e04c3fSmrgGLboolean GLAPIENTRY
29117ec681f3Smrg_mesa_UnmapNamedBufferEXT(GLuint buffer)
2912cdc920a0Smrg{
2913cdc920a0Smrg   GET_CURRENT_CONTEXT(ctx);
2914cdc920a0Smrg   struct gl_buffer_object *bufObj;
2915cdc920a0Smrg
29167ec681f3Smrg   if (!buffer) {
29177ec681f3Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
29187ec681f3Smrg                  "glUnmapNamedBufferEXT(buffer=0)");
29197ec681f3Smrg      return GL_FALSE;
29207ec681f3Smrg   }
29217ec681f3Smrg
292201e04c3fSmrg   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glUnmapNamedBuffer");
2923af69d88dSmrg   if (!bufObj)
292401e04c3fSmrg      return GL_FALSE;
292501e04c3fSmrg
292601e04c3fSmrg   return validate_and_unmap_buffer(ctx, bufObj, "glUnmapNamedBuffer");
292701e04c3fSmrg}
292801e04c3fSmrg
2929cdc920a0Smrg
293001e04c3fSmrgstatic bool
293101e04c3fSmrgget_buffer_parameter(struct gl_context *ctx,
293201e04c3fSmrg                     struct gl_buffer_object *bufObj, GLenum pname,
293301e04c3fSmrg                     GLint64 *params, const char *func)
293401e04c3fSmrg{
2935cdc920a0Smrg   switch (pname) {
2936cdc920a0Smrg   case GL_BUFFER_SIZE_ARB:
2937cdc920a0Smrg      *params = bufObj->Size;
293801e04c3fSmrg      break;
2939cdc920a0Smrg   case GL_BUFFER_USAGE_ARB:
2940cdc920a0Smrg      *params = bufObj->Usage;
294101e04c3fSmrg      break;
2942cdc920a0Smrg   case GL_BUFFER_ACCESS_ARB:
2943af69d88dSmrg      *params = simplified_access_mode(ctx,
294401e04c3fSmrg                            bufObj->Mappings[MAP_USER].AccessFlags);
294501e04c3fSmrg      break;
294601e04c3fSmrg   case GL_BUFFER_MAPPED_ARB:
294701e04c3fSmrg      *params = _mesa_bufferobj_mapped(bufObj, MAP_USER);
294801e04c3fSmrg      break;
29493464ebd5Sriastradh   case GL_BUFFER_ACCESS_FLAGS:
2950af69d88dSmrg      if (!ctx->Extensions.ARB_map_buffer_range)
29513464ebd5Sriastradh         goto invalid_pname;
2952af69d88dSmrg      *params = bufObj->Mappings[MAP_USER].AccessFlags;
295301e04c3fSmrg      break;
29543464ebd5Sriastradh   case GL_BUFFER_MAP_OFFSET:
2955af69d88dSmrg      if (!ctx->Extensions.ARB_map_buffer_range)
29563464ebd5Sriastradh         goto invalid_pname;
2957af69d88dSmrg      *params = bufObj->Mappings[MAP_USER].Offset;
295801e04c3fSmrg      break;
29593464ebd5Sriastradh   case GL_BUFFER_MAP_LENGTH:
2960af69d88dSmrg      if (!ctx->Extensions.ARB_map_buffer_range)
2961af69d88dSmrg         goto invalid_pname;
2962af69d88dSmrg      *params = bufObj->Mappings[MAP_USER].Length;
296301e04c3fSmrg      break;
2964af69d88dSmrg   case GL_BUFFER_IMMUTABLE_STORAGE:
2965af69d88dSmrg      if (!ctx->Extensions.ARB_buffer_storage)
2966af69d88dSmrg         goto invalid_pname;
2967af69d88dSmrg      *params = bufObj->Immutable;
296801e04c3fSmrg      break;
2969af69d88dSmrg   case GL_BUFFER_STORAGE_FLAGS:
2970af69d88dSmrg      if (!ctx->Extensions.ARB_buffer_storage)
29713464ebd5Sriastradh         goto invalid_pname;
2972af69d88dSmrg      *params = bufObj->StorageFlags;
297301e04c3fSmrg      break;
29743464ebd5Sriastradh   default:
297501e04c3fSmrg      goto invalid_pname;
29767117f1b4Smrg   }
29773464ebd5Sriastradh
297801e04c3fSmrg   return true;
297901e04c3fSmrg
29803464ebd5Sriastradhinvalid_pname:
298101e04c3fSmrg   _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname: %s)", func,
298201e04c3fSmrg               _mesa_enum_to_string(pname));
298301e04c3fSmrg   return false;
298401e04c3fSmrg}
298501e04c3fSmrg
298601e04c3fSmrgvoid GLAPIENTRY
298701e04c3fSmrg_mesa_GetBufferParameteriv(GLenum target, GLenum pname, GLint *params)
298801e04c3fSmrg{
298901e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
299001e04c3fSmrg   struct gl_buffer_object *bufObj;
299101e04c3fSmrg   GLint64 parameter;
299201e04c3fSmrg
299301e04c3fSmrg   bufObj = get_buffer(ctx, "glGetBufferParameteriv", target,
299401e04c3fSmrg                       GL_INVALID_OPERATION);
299501e04c3fSmrg   if (!bufObj)
299601e04c3fSmrg      return;
299701e04c3fSmrg
299801e04c3fSmrg   if (!get_buffer_parameter(ctx, bufObj, pname, &parameter,
299901e04c3fSmrg                             "glGetBufferParameteriv"))
300001e04c3fSmrg      return; /* Error already recorded. */
300101e04c3fSmrg
300201e04c3fSmrg   *params = (GLint) parameter;
300301e04c3fSmrg}
300401e04c3fSmrg
300501e04c3fSmrgvoid GLAPIENTRY
300601e04c3fSmrg_mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params)
300701e04c3fSmrg{
300801e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
300901e04c3fSmrg   struct gl_buffer_object *bufObj;
301001e04c3fSmrg   GLint64 parameter;
301101e04c3fSmrg
301201e04c3fSmrg   bufObj = get_buffer(ctx, "glGetBufferParameteri64v", target,
301301e04c3fSmrg                       GL_INVALID_OPERATION);
301401e04c3fSmrg   if (!bufObj)
301501e04c3fSmrg      return;
301601e04c3fSmrg
301701e04c3fSmrg   if (!get_buffer_parameter(ctx, bufObj, pname, &parameter,
301801e04c3fSmrg                             "glGetBufferParameteri64v"))
301901e04c3fSmrg      return; /* Error already recorded. */
302001e04c3fSmrg
302101e04c3fSmrg   *params = parameter;
302201e04c3fSmrg}
302301e04c3fSmrg
302401e04c3fSmrgvoid GLAPIENTRY
302501e04c3fSmrg_mesa_GetNamedBufferParameteriv(GLuint buffer, GLenum pname, GLint *params)
302601e04c3fSmrg{
302701e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
302801e04c3fSmrg   struct gl_buffer_object *bufObj;
302901e04c3fSmrg   GLint64 parameter;
303001e04c3fSmrg
303101e04c3fSmrg   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer,
303201e04c3fSmrg                                       "glGetNamedBufferParameteriv");
303301e04c3fSmrg   if (!bufObj)
303401e04c3fSmrg      return;
303501e04c3fSmrg
303601e04c3fSmrg   if (!get_buffer_parameter(ctx, bufObj, pname, &parameter,
303701e04c3fSmrg                             "glGetNamedBufferParameteriv"))
303801e04c3fSmrg      return; /* Error already recorded. */
303901e04c3fSmrg
304001e04c3fSmrg   *params = (GLint) parameter;
304101e04c3fSmrg}
304201e04c3fSmrg
30437ec681f3Smrgvoid GLAPIENTRY
30447ec681f3Smrg_mesa_GetNamedBufferParameterivEXT(GLuint buffer, GLenum pname, GLint *params)
30457ec681f3Smrg{
30467ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
30477ec681f3Smrg   struct gl_buffer_object *bufObj;
30487ec681f3Smrg   GLint64 parameter;
30497ec681f3Smrg
30507ec681f3Smrg   if (!buffer) {
30517ec681f3Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
30527ec681f3Smrg                  "glGetNamedBufferParameterivEXT: buffer=0");
30537ec681f3Smrg      return;
30547ec681f3Smrg   }
30557ec681f3Smrg
30567ec681f3Smrg   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
30577ec681f3Smrg   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
30587ec681f3Smrg                                     &bufObj, "glGetNamedBufferParameterivEXT"))
30597ec681f3Smrg      return;
30607ec681f3Smrg
30617ec681f3Smrg   if (!get_buffer_parameter(ctx, bufObj, pname, &parameter,
30627ec681f3Smrg                             "glGetNamedBufferParameterivEXT"))
30637ec681f3Smrg      return; /* Error already recorded. */
30647ec681f3Smrg
30657ec681f3Smrg   *params = (GLint) parameter;
30667ec681f3Smrg}
30677ec681f3Smrg
306801e04c3fSmrgvoid GLAPIENTRY
306901e04c3fSmrg_mesa_GetNamedBufferParameteri64v(GLuint buffer, GLenum pname,
307001e04c3fSmrg                                  GLint64 *params)
307101e04c3fSmrg{
307201e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
307301e04c3fSmrg   struct gl_buffer_object *bufObj;
307401e04c3fSmrg   GLint64 parameter;
307501e04c3fSmrg
307601e04c3fSmrg   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer,
307701e04c3fSmrg                                       "glGetNamedBufferParameteri64v");
307801e04c3fSmrg   if (!bufObj)
307901e04c3fSmrg      return;
308001e04c3fSmrg
308101e04c3fSmrg   if (!get_buffer_parameter(ctx, bufObj, pname, &parameter,
308201e04c3fSmrg                             "glGetNamedBufferParameteri64v"))
308301e04c3fSmrg      return; /* Error already recorded. */
308401e04c3fSmrg
308501e04c3fSmrg   *params = parameter;
30867117f1b4Smrg}
30877117f1b4Smrg
30887117f1b4Smrg
30897117f1b4Smrgvoid GLAPIENTRY
3090af69d88dSmrg_mesa_GetBufferPointerv(GLenum target, GLenum pname, GLvoid **params)
30917117f1b4Smrg{
30927117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
309301e04c3fSmrg   struct gl_buffer_object *bufObj;
30947117f1b4Smrg
309501e04c3fSmrg   if (pname != GL_BUFFER_MAP_POINTER) {
309601e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointerv(pname != "
309701e04c3fSmrg                  "GL_BUFFER_MAP_POINTER)");
30987117f1b4Smrg      return;
30997117f1b4Smrg   }
31007117f1b4Smrg
310101e04c3fSmrg   bufObj = get_buffer(ctx, "glGetBufferPointerv", target,
3102af69d88dSmrg                       GL_INVALID_OPERATION);
3103af69d88dSmrg   if (!bufObj)
31047117f1b4Smrg      return;
31057117f1b4Smrg
3106af69d88dSmrg   *params = bufObj->Mappings[MAP_USER].Pointer;
31077117f1b4Smrg}
31084a49301eSmrg
31094a49301eSmrgvoid GLAPIENTRY
311001e04c3fSmrg_mesa_GetNamedBufferPointerv(GLuint buffer, GLenum pname, GLvoid **params)
31114a49301eSmrg{
31124a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
311301e04c3fSmrg   struct gl_buffer_object *bufObj;
31144a49301eSmrg
311501e04c3fSmrg   if (pname != GL_BUFFER_MAP_POINTER) {
311601e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetNamedBufferPointerv(pname != "
311701e04c3fSmrg                  "GL_BUFFER_MAP_POINTER)");
31184a49301eSmrg      return;
311901e04c3fSmrg   }
31204a49301eSmrg
312101e04c3fSmrg   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer,
312201e04c3fSmrg                                       "glGetNamedBufferPointerv");
312301e04c3fSmrg   if (!bufObj)
31244a49301eSmrg      return;
31254a49301eSmrg
312601e04c3fSmrg   *params = bufObj->Mappings[MAP_USER].Pointer;
312701e04c3fSmrg}
312801e04c3fSmrg
31297ec681f3Smrgvoid GLAPIENTRY
31307ec681f3Smrg_mesa_GetNamedBufferPointervEXT(GLuint buffer, GLenum pname, GLvoid **params)
31317ec681f3Smrg{
31327ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
31337ec681f3Smrg   struct gl_buffer_object *bufObj;
31347ec681f3Smrg
31357ec681f3Smrg   if (!buffer) {
31367ec681f3Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
31377ec681f3Smrg                  "glGetNamedBufferPointervEXT(buffer=0)");
31387ec681f3Smrg      return;
31397ec681f3Smrg   }
31407ec681f3Smrg   if (pname != GL_BUFFER_MAP_POINTER) {
31417ec681f3Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetNamedBufferPointervEXT(pname != "
31427ec681f3Smrg                  "GL_BUFFER_MAP_POINTER)");
31437ec681f3Smrg      return;
31447ec681f3Smrg   }
31457ec681f3Smrg
31467ec681f3Smrg   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
31477ec681f3Smrg   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
31487ec681f3Smrg                                     &bufObj, "glGetNamedBufferPointervEXT"))
31497ec681f3Smrg      return;
31507ec681f3Smrg
31517ec681f3Smrg   *params = bufObj->Mappings[MAP_USER].Pointer;
31527ec681f3Smrg}
315301e04c3fSmrg
315401e04c3fSmrgstatic void
315501e04c3fSmrgcopy_buffer_sub_data(struct gl_context *ctx, struct gl_buffer_object *src,
315601e04c3fSmrg                     struct gl_buffer_object *dst, GLintptr readOffset,
315701e04c3fSmrg                     GLintptr writeOffset, GLsizeiptr size, const char *func)
315801e04c3fSmrg{
3159af69d88dSmrg   if (_mesa_check_disallowed_mapping(src)) {
31604a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
316101e04c3fSmrg                  "%s(readBuffer is mapped)", func);
31624a49301eSmrg      return;
31634a49301eSmrg   }
31644a49301eSmrg
3165af69d88dSmrg   if (_mesa_check_disallowed_mapping(dst)) {
31664a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
316701e04c3fSmrg                  "%s(writeBuffer is mapped)", func);
31684a49301eSmrg      return;
31694a49301eSmrg   }
31704a49301eSmrg
31714a49301eSmrg   if (readOffset < 0) {
31724a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
317301e04c3fSmrg                  "%s(readOffset %d < 0)", func, (int) readOffset);
31744a49301eSmrg      return;
31754a49301eSmrg   }
31764a49301eSmrg
31774a49301eSmrg   if (writeOffset < 0) {
31784a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
317901e04c3fSmrg                  "%s(writeOffset %d < 0)", func, (int) writeOffset);
3180af69d88dSmrg      return;
3181af69d88dSmrg   }
3182af69d88dSmrg
3183af69d88dSmrg   if (size < 0) {
3184af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
318501e04c3fSmrg                  "%s(size %d < 0)", func, (int) size);
31864a49301eSmrg      return;
31874a49301eSmrg   }
31884a49301eSmrg
31894a49301eSmrg   if (readOffset + size > src->Size) {
31904a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
319101e04c3fSmrg                  "%s(readOffset %d + size %d > src_buffer_size %d)", func,
319201e04c3fSmrg                  (int) readOffset, (int) size, (int) src->Size);
31934a49301eSmrg      return;
31944a49301eSmrg   }
31954a49301eSmrg
31964a49301eSmrg   if (writeOffset + size > dst->Size) {
31974a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
319801e04c3fSmrg                  "%s(writeOffset %d + size %d > dst_buffer_size %d)", func,
319901e04c3fSmrg                  (int) writeOffset, (int) size, (int) dst->Size);
32004a49301eSmrg      return;
32014a49301eSmrg   }
32024a49301eSmrg
32034a49301eSmrg   if (src == dst) {
32044a49301eSmrg      if (readOffset + size <= writeOffset) {
32054a49301eSmrg         /* OK */
32064a49301eSmrg      }
32074a49301eSmrg      else if (writeOffset + size <= readOffset) {
32084a49301eSmrg         /* OK */
32094a49301eSmrg      }
32104a49301eSmrg      else {
32114a49301eSmrg         /* overlapping src/dst is illegal */
32124a49301eSmrg         _mesa_error(ctx, GL_INVALID_VALUE,
321301e04c3fSmrg                     "%s(overlapping src/dst)", func);
32144a49301eSmrg         return;
32154a49301eSmrg      }
32164a49301eSmrg   }
32174a49301eSmrg
321801e04c3fSmrg   dst->MinMaxCacheDirty = true;
321901e04c3fSmrg
32204a49301eSmrg   ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size);
32214a49301eSmrg}
32224a49301eSmrg
322301e04c3fSmrgvoid GLAPIENTRY
322401e04c3fSmrg_mesa_CopyBufferSubData_no_error(GLenum readTarget, GLenum writeTarget,
322501e04c3fSmrg                                 GLintptr readOffset, GLintptr writeOffset,
322601e04c3fSmrg                                 GLsizeiptr size)
322701e04c3fSmrg{
322801e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
322901e04c3fSmrg
323001e04c3fSmrg   struct gl_buffer_object **src_ptr = get_buffer_target(ctx, readTarget);
323101e04c3fSmrg   struct gl_buffer_object *src = *src_ptr;
32324a49301eSmrg
323301e04c3fSmrg   struct gl_buffer_object **dst_ptr = get_buffer_target(ctx, writeTarget);
323401e04c3fSmrg   struct gl_buffer_object *dst = *dst_ptr;
323501e04c3fSmrg
323601e04c3fSmrg   dst->MinMaxCacheDirty = true;
323701e04c3fSmrg   ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset,
323801e04c3fSmrg                                 size);
323901e04c3fSmrg}
324001e04c3fSmrg
324101e04c3fSmrgvoid GLAPIENTRY
324201e04c3fSmrg_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
324301e04c3fSmrg                        GLintptr readOffset, GLintptr writeOffset,
324401e04c3fSmrg                        GLsizeiptr size)
32454a49301eSmrg{
32464a49301eSmrg   GET_CURRENT_CONTEXT(ctx);
324701e04c3fSmrg   struct gl_buffer_object *src, *dst;
32484a49301eSmrg
324901e04c3fSmrg   src = get_buffer(ctx, "glCopyBufferSubData", readTarget,
325001e04c3fSmrg                    GL_INVALID_OPERATION);
325101e04c3fSmrg   if (!src)
325201e04c3fSmrg      return;
32534a49301eSmrg
325401e04c3fSmrg   dst = get_buffer(ctx, "glCopyBufferSubData", writeTarget,
325501e04c3fSmrg                    GL_INVALID_OPERATION);
325601e04c3fSmrg   if (!dst)
325701e04c3fSmrg      return;
325801e04c3fSmrg
325901e04c3fSmrg   copy_buffer_sub_data(ctx, src, dst, readOffset, writeOffset, size,
326001e04c3fSmrg                        "glCopyBufferSubData");
326101e04c3fSmrg}
326201e04c3fSmrg
32637ec681f3Smrgvoid GLAPIENTRY
32647ec681f3Smrg_mesa_NamedCopyBufferSubDataEXT(GLuint readBuffer, GLuint writeBuffer,
32657ec681f3Smrg                                GLintptr readOffset, GLintptr writeOffset,
32667ec681f3Smrg                                GLsizeiptr size)
32677ec681f3Smrg{
32687ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
32697ec681f3Smrg   struct gl_buffer_object *src, *dst;
32707ec681f3Smrg
32717ec681f3Smrg   src = _mesa_lookup_bufferobj(ctx, readBuffer);
32727ec681f3Smrg   if (!_mesa_handle_bind_buffer_gen(ctx, readBuffer,
32737ec681f3Smrg                                     &src,
32747ec681f3Smrg                                     "glNamedCopyBufferSubDataEXT"))
32757ec681f3Smrg      return;
32767ec681f3Smrg
32777ec681f3Smrg   dst = _mesa_lookup_bufferobj(ctx, writeBuffer);
32787ec681f3Smrg   if (!_mesa_handle_bind_buffer_gen(ctx, writeBuffer,
32797ec681f3Smrg                                     &dst,
32807ec681f3Smrg                                     "glNamedCopyBufferSubDataEXT"))
32817ec681f3Smrg      return;
32827ec681f3Smrg
32837ec681f3Smrg   copy_buffer_sub_data(ctx, src, dst, readOffset, writeOffset, size,
32847ec681f3Smrg                        "glNamedCopyBufferSubDataEXT");
32857ec681f3Smrg}
32867ec681f3Smrg
328701e04c3fSmrgvoid GLAPIENTRY
328801e04c3fSmrg_mesa_CopyNamedBufferSubData_no_error(GLuint readBuffer, GLuint writeBuffer,
328901e04c3fSmrg                                      GLintptr readOffset,
329001e04c3fSmrg                                      GLintptr writeOffset, GLsizeiptr size)
329101e04c3fSmrg{
329201e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
329301e04c3fSmrg
329401e04c3fSmrg   struct gl_buffer_object *src = _mesa_lookup_bufferobj(ctx, readBuffer);
329501e04c3fSmrg   struct gl_buffer_object *dst = _mesa_lookup_bufferobj(ctx, writeBuffer);
329601e04c3fSmrg
329701e04c3fSmrg   dst->MinMaxCacheDirty = true;
329801e04c3fSmrg   ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset,
329901e04c3fSmrg                                 size);
330001e04c3fSmrg}
330101e04c3fSmrg
330201e04c3fSmrgvoid GLAPIENTRY
330301e04c3fSmrg_mesa_CopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer,
330401e04c3fSmrg                             GLintptr readOffset, GLintptr writeOffset,
330501e04c3fSmrg                             GLsizeiptr size)
330601e04c3fSmrg{
330701e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
330801e04c3fSmrg   struct gl_buffer_object *src, *dst;
330901e04c3fSmrg
331001e04c3fSmrg   src = _mesa_lookup_bufferobj_err(ctx, readBuffer,
331101e04c3fSmrg                                    "glCopyNamedBufferSubData");
331201e04c3fSmrg   if (!src)
331301e04c3fSmrg      return;
331401e04c3fSmrg
331501e04c3fSmrg   dst = _mesa_lookup_bufferobj_err(ctx, writeBuffer,
331601e04c3fSmrg                                    "glCopyNamedBufferSubData");
331701e04c3fSmrg   if (!dst)
331801e04c3fSmrg      return;
331901e04c3fSmrg
332001e04c3fSmrg   copy_buffer_sub_data(ctx, src, dst, readOffset, writeOffset, size,
332101e04c3fSmrg                        "glCopyNamedBufferSubData");
332201e04c3fSmrg}
332301e04c3fSmrg
33247ec681f3Smrgvoid GLAPIENTRY
33257ec681f3Smrg_mesa_InternalBufferSubDataCopyMESA(GLintptr srcBuffer, GLuint srcOffset,
33267ec681f3Smrg                                    GLuint dstTargetOrName, GLintptr dstOffset,
33277ec681f3Smrg                                    GLsizeiptr size, GLboolean named,
33287ec681f3Smrg                                    GLboolean ext_dsa)
33297ec681f3Smrg{
33307ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
33317ec681f3Smrg   struct gl_buffer_object *src = (struct gl_buffer_object *)srcBuffer;
33327ec681f3Smrg   struct gl_buffer_object *dst;
33337ec681f3Smrg   const char *func;
33347ec681f3Smrg
33357ec681f3Smrg   /* Handle behavior for all 3 variants. */
33367ec681f3Smrg   if (named && ext_dsa) {
33377ec681f3Smrg      func = "glNamedBufferSubDataEXT";
33387ec681f3Smrg      dst = _mesa_lookup_bufferobj(ctx, dstTargetOrName);
33397ec681f3Smrg      if (!_mesa_handle_bind_buffer_gen(ctx, dstTargetOrName, &dst, func))
33407ec681f3Smrg         goto done;
33417ec681f3Smrg   } else if (named) {
33427ec681f3Smrg      func = "glNamedBufferSubData";
33437ec681f3Smrg      dst = _mesa_lookup_bufferobj_err(ctx, dstTargetOrName, func);
33447ec681f3Smrg      if (!dst)
33457ec681f3Smrg         goto done;
33467ec681f3Smrg   } else {
33477ec681f3Smrg      assert(!ext_dsa);
33487ec681f3Smrg      func = "glBufferSubData";
33497ec681f3Smrg      dst = get_buffer(ctx, func, dstTargetOrName, GL_INVALID_OPERATION);
33507ec681f3Smrg      if (!dst)
33517ec681f3Smrg         goto done;
33527ec681f3Smrg   }
33537ec681f3Smrg
33547ec681f3Smrg   if (!validate_buffer_sub_data(ctx, dst, dstOffset, size, func))
33557ec681f3Smrg      goto done; /* the error is already set */
33567ec681f3Smrg
33577ec681f3Smrg   dst->MinMaxCacheDirty = true;
33587ec681f3Smrg   ctx->Driver.CopyBufferSubData(ctx, src, dst, srcOffset, dstOffset, size);
33597ec681f3Smrg
33607ec681f3Smrgdone:
33617ec681f3Smrg   /* The caller passes the reference to this function, so unreference it. */
33627ec681f3Smrg   _mesa_reference_buffer_object(ctx, &src, NULL);
33637ec681f3Smrg}
33647ec681f3Smrg
336501e04c3fSmrgstatic bool
336601e04c3fSmrgvalidate_map_buffer_range(struct gl_context *ctx,
336701e04c3fSmrg                          struct gl_buffer_object *bufObj, GLintptr offset,
336801e04c3fSmrg                          GLsizeiptr length, GLbitfield access,
336901e04c3fSmrg                          const char *func)
337001e04c3fSmrg{
337101e04c3fSmrg   GLbitfield allowed_access;
337201e04c3fSmrg
337301e04c3fSmrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, false);
33744a49301eSmrg
33754a49301eSmrg   if (offset < 0) {
33764a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
337701e04c3fSmrg                  "%s(offset %ld < 0)", func, (long) offset);
337801e04c3fSmrg      return false;
33794a49301eSmrg   }
33804a49301eSmrg
33814a49301eSmrg   if (length < 0) {
33824a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
338301e04c3fSmrg                  "%s(length %ld < 0)", func, (long) length);
338401e04c3fSmrg      return false;
33853464ebd5Sriastradh   }
33863464ebd5Sriastradh
3387af69d88dSmrg   /* Page 38 of the PDF of the OpenGL ES 3.0 spec says:
3388af69d88dSmrg    *
3389af69d88dSmrg    *     "An INVALID_OPERATION error is generated for any of the following
3390af69d88dSmrg    *     conditions:
3391af69d88dSmrg    *
3392af69d88dSmrg    *     * <length> is zero."
339301e04c3fSmrg    *
339401e04c3fSmrg    * Additionally, page 94 of the PDF of the OpenGL 4.5 core spec
339501e04c3fSmrg    * (30.10.2014) also says this, so it's no longer allowed for desktop GL,
339601e04c3fSmrg    * either.
3397af69d88dSmrg    */
339801e04c3fSmrg   if (length == 0) {
339901e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(length = 0)", func);
340001e04c3fSmrg      return false;
3401af69d88dSmrg   }
3402af69d88dSmrg
3403af69d88dSmrg   allowed_access = GL_MAP_READ_BIT |
3404af69d88dSmrg                    GL_MAP_WRITE_BIT |
3405af69d88dSmrg                    GL_MAP_INVALIDATE_RANGE_BIT |
3406af69d88dSmrg                    GL_MAP_INVALIDATE_BUFFER_BIT |
3407af69d88dSmrg                    GL_MAP_FLUSH_EXPLICIT_BIT |
3408af69d88dSmrg                    GL_MAP_UNSYNCHRONIZED_BIT;
3409af69d88dSmrg
3410af69d88dSmrg   if (ctx->Extensions.ARB_buffer_storage) {
3411af69d88dSmrg         allowed_access |= GL_MAP_PERSISTENT_BIT |
3412af69d88dSmrg                           GL_MAP_COHERENT_BIT;
3413af69d88dSmrg   }
3414af69d88dSmrg
3415af69d88dSmrg   if (access & ~allowed_access) {
341601e04c3fSmrg      /* generate an error if any bits other than those allowed are set */
341701e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
341801e04c3fSmrg                  "%s(access has undefined bits set)", func);
341901e04c3fSmrg      return false;
34204a49301eSmrg   }
34214a49301eSmrg
34224a49301eSmrg   if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) {
34234a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
342401e04c3fSmrg                  "%s(access indicates neither read or write)", func);
342501e04c3fSmrg      return false;
34264a49301eSmrg   }
34274a49301eSmrg
34283464ebd5Sriastradh   if ((access & GL_MAP_READ_BIT) &&
34293464ebd5Sriastradh       (access & (GL_MAP_INVALIDATE_RANGE_BIT |
34303464ebd5Sriastradh                  GL_MAP_INVALIDATE_BUFFER_BIT |
34313464ebd5Sriastradh                  GL_MAP_UNSYNCHRONIZED_BIT))) {
34323464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_OPERATION,
343301e04c3fSmrg                  "%s(read access with disallowed bits)", func);
343401e04c3fSmrg      return false;
34354a49301eSmrg   }
34364a49301eSmrg
34374a49301eSmrg   if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) &&
34384a49301eSmrg       ((access & GL_MAP_WRITE_BIT) == 0)) {
34394a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
344001e04c3fSmrg                  "%s(access has flush explicit without write)", func);
344101e04c3fSmrg      return false;
34424a49301eSmrg   }
34434a49301eSmrg
3444af69d88dSmrg   if (access & GL_MAP_READ_BIT &&
3445af69d88dSmrg       !(bufObj->StorageFlags & GL_MAP_READ_BIT)) {
3446af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
344701e04c3fSmrg                  "%s(buffer does not allow read access)", func);
344801e04c3fSmrg      return false;
3449af69d88dSmrg   }
3450af69d88dSmrg
3451af69d88dSmrg   if (access & GL_MAP_WRITE_BIT &&
3452af69d88dSmrg       !(bufObj->StorageFlags & GL_MAP_WRITE_BIT)) {
3453af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
345401e04c3fSmrg                  "%s(buffer does not allow write access)", func);
345501e04c3fSmrg      return false;
3456af69d88dSmrg   }
3457af69d88dSmrg
3458af69d88dSmrg   if (access & GL_MAP_COHERENT_BIT &&
3459af69d88dSmrg       !(bufObj->StorageFlags & GL_MAP_COHERENT_BIT)) {
3460af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
346101e04c3fSmrg                  "%s(buffer does not allow coherent access)", func);
346201e04c3fSmrg      return false;
34634a49301eSmrg   }
34644a49301eSmrg
346501e04c3fSmrg   if (access & GL_MAP_PERSISTENT_BIT &&
346601e04c3fSmrg       !(bufObj->StorageFlags & GL_MAP_PERSISTENT_BIT)) {
34674a49301eSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
346801e04c3fSmrg                  "%s(buffer does not allow persistent access)", func);
346901e04c3fSmrg      return false;
34704a49301eSmrg   }
34714a49301eSmrg
347201e04c3fSmrg   if (offset + length > bufObj->Size) {
34734a49301eSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
347401e04c3fSmrg                  "%s(offset %lu + length %lu > buffer_size %lu)", func,
347501e04c3fSmrg                  (unsigned long) offset, (unsigned long) length,
347601e04c3fSmrg                  (unsigned long) bufObj->Size);
347701e04c3fSmrg      return false;
34784a49301eSmrg   }
34794a49301eSmrg
348001e04c3fSmrg   if (_mesa_bufferobj_mapped(bufObj, MAP_USER)) {
348101e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
348201e04c3fSmrg                  "%s(buffer already mapped)", func);
348301e04c3fSmrg      return false;
348401e04c3fSmrg   }
34854a49301eSmrg
348601e04c3fSmrg   if (access & GL_MAP_WRITE_BIT) {
348701e04c3fSmrg      bufObj->NumMapBufferWriteCalls++;
348801e04c3fSmrg      if ((bufObj->Usage == GL_STATIC_DRAW ||
348901e04c3fSmrg           bufObj->Usage == GL_STATIC_COPY) &&
349001e04c3fSmrg          bufObj->NumMapBufferWriteCalls >= BUFFER_WARNING_CALL_COUNT) {
349101e04c3fSmrg         BUFFER_USAGE_WARNING(ctx,
349201e04c3fSmrg                              "using %s(buffer %u, offset %u, length %u) to "
349301e04c3fSmrg                              "update a %s buffer",
349401e04c3fSmrg                              func, bufObj->Name, offset, length,
349501e04c3fSmrg                              _mesa_enum_to_string(bufObj->Usage));
349601e04c3fSmrg      }
349701e04c3fSmrg   }
3498cdc920a0Smrg
349901e04c3fSmrg   return true;
350001e04c3fSmrg}
3501cdc920a0Smrg
350201e04c3fSmrgstatic void *
350301e04c3fSmrgmap_buffer_range(struct gl_context *ctx, struct gl_buffer_object *bufObj,
350401e04c3fSmrg                 GLintptr offset, GLsizeiptr length, GLbitfield access,
350501e04c3fSmrg                 const char *func)
3506cdc920a0Smrg{
350701e04c3fSmrg   if (!bufObj->Size) {
350801e04c3fSmrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s(buffer size = 0)", func);
350901e04c3fSmrg      return NULL;
351001e04c3fSmrg   }
3511cdc920a0Smrg
351201e04c3fSmrg   assert(ctx->Driver.MapBufferRange);
351301e04c3fSmrg   void *map = ctx->Driver.MapBufferRange(ctx, offset, length, access, bufObj,
351401e04c3fSmrg                                          MAP_USER);
351501e04c3fSmrg   if (!map) {
351601e04c3fSmrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s(map failed)", func);
3517cdc920a0Smrg   }
351801e04c3fSmrg   else {
351901e04c3fSmrg      /* The driver callback should have set all these fields.
352001e04c3fSmrg       * This is important because other modules (like VBO) might call
352101e04c3fSmrg       * the driver function directly.
352201e04c3fSmrg       */
352301e04c3fSmrg      assert(bufObj->Mappings[MAP_USER].Pointer == map);
352401e04c3fSmrg      assert(bufObj->Mappings[MAP_USER].Length == length);
352501e04c3fSmrg      assert(bufObj->Mappings[MAP_USER].Offset == offset);
352601e04c3fSmrg      assert(bufObj->Mappings[MAP_USER].AccessFlags == access);
3527cdc920a0Smrg   }
3528cdc920a0Smrg
352901e04c3fSmrg   if (access & GL_MAP_WRITE_BIT) {
353001e04c3fSmrg      bufObj->Written = GL_TRUE;
353101e04c3fSmrg      bufObj->MinMaxCacheDirty = true;
3532cdc920a0Smrg   }
3533cdc920a0Smrg
353401e04c3fSmrg#ifdef VBO_DEBUG
353501e04c3fSmrg   if (strstr(func, "Range") == NULL) { /* If not MapRange */
353601e04c3fSmrg      printf("glMapBuffer(%u, sz %ld, access 0x%x)\n",
353701e04c3fSmrg            bufObj->Name, bufObj->Size, access);
353801e04c3fSmrg      /* Access must be write only */
353901e04c3fSmrg      if ((access & GL_MAP_WRITE_BIT) && (!(access & ~GL_MAP_WRITE_BIT))) {
354001e04c3fSmrg         GLuint i;
35417ec681f3Smrg         GLubyte *b = (GLubyte *) bufObj->Mappings[MAP_USER].Pointer;
354201e04c3fSmrg         for (i = 0; i < bufObj->Size; i++)
354301e04c3fSmrg            b[i] = i & 0xff;
354401e04c3fSmrg      }
354501e04c3fSmrg   }
354601e04c3fSmrg#endif
3547cdc920a0Smrg
354801e04c3fSmrg#ifdef BOUNDS_CHECK
354901e04c3fSmrg   if (strstr(func, "Range") == NULL) { /* If not MapRange */
35507ec681f3Smrg      GLubyte *buf = (GLubyte *) bufObj->Mappings[MAP_USER].Pointer;
355101e04c3fSmrg      GLuint i;
355201e04c3fSmrg      /* buffer is 100 bytes larger than requested, fill with magic value */
355301e04c3fSmrg      for (i = 0; i < 100; i++) {
355401e04c3fSmrg         buf[bufObj->Size - i - 1] = 123;
355501e04c3fSmrg      }
355601e04c3fSmrg   }
355701e04c3fSmrg#endif
3558cdc920a0Smrg
355901e04c3fSmrg   return map;
3560cdc920a0Smrg}
3561cdc920a0Smrg
356201e04c3fSmrgvoid * GLAPIENTRY
356301e04c3fSmrg_mesa_MapBufferRange_no_error(GLenum target, GLintptr offset,
356401e04c3fSmrg                              GLsizeiptr length, GLbitfield access)
3565cdc920a0Smrg{
356601e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
3567cdc920a0Smrg
356801e04c3fSmrg   struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target);
356901e04c3fSmrg   struct gl_buffer_object *bufObj = *bufObjPtr;
3570cdc920a0Smrg
357101e04c3fSmrg   return map_buffer_range(ctx, bufObj, offset, length, access,
357201e04c3fSmrg                           "glMapBufferRange");
3573cdc920a0Smrg}
3574cdc920a0Smrg
357501e04c3fSmrgvoid * GLAPIENTRY
357601e04c3fSmrg_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
357701e04c3fSmrg                     GLbitfield access)
3578cdc920a0Smrg{
357901e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
358001e04c3fSmrg   struct gl_buffer_object *bufObj;
3581cdc920a0Smrg
358201e04c3fSmrg   if (!ctx->Extensions.ARB_map_buffer_range) {
3583cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
358401e04c3fSmrg                  "glMapBufferRange(ARB_map_buffer_range not supported)");
358501e04c3fSmrg      return NULL;
3586cdc920a0Smrg   }
3587cdc920a0Smrg
358801e04c3fSmrg   bufObj = get_buffer(ctx, "glMapBufferRange", target, GL_INVALID_OPERATION);
358901e04c3fSmrg   if (!bufObj)
359001e04c3fSmrg      return NULL;
3591cdc920a0Smrg
359201e04c3fSmrg   if (!validate_map_buffer_range(ctx, bufObj, offset, length, access,
359301e04c3fSmrg                                  "glMapBufferRange"))
359401e04c3fSmrg      return NULL;
3595cdc920a0Smrg
359601e04c3fSmrg   return map_buffer_range(ctx, bufObj, offset, length, access,
359701e04c3fSmrg                           "glMapBufferRange");
3598cdc920a0Smrg}
3599cdc920a0Smrg
360001e04c3fSmrgvoid * GLAPIENTRY
360101e04c3fSmrg_mesa_MapNamedBufferRange_no_error(GLuint buffer, GLintptr offset,
360201e04c3fSmrg                                   GLsizeiptr length, GLbitfield access)
3603cdc920a0Smrg{
3604cdc920a0Smrg   GET_CURRENT_CONTEXT(ctx);
360501e04c3fSmrg   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
3606cdc920a0Smrg
360701e04c3fSmrg   return map_buffer_range(ctx, bufObj, offset, length, access,
360801e04c3fSmrg                           "glMapNamedBufferRange");
3609cdc920a0Smrg}
3610cdc920a0Smrg
36117ec681f3Smrgstatic void *
36127ec681f3Smrgmap_named_buffer_range(GLuint buffer, GLintptr offset, GLsizeiptr length,
36137ec681f3Smrg                       GLbitfield access, bool dsa_ext, const char *func)
3614cdc920a0Smrg{
361501e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
36167ec681f3Smrg   struct gl_buffer_object *bufObj = NULL;
3617cdc920a0Smrg
361801e04c3fSmrg   if (!ctx->Extensions.ARB_map_buffer_range) {
3619cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
36207ec681f3Smrg                  "%s(ARB_map_buffer_range not supported)", func);
362101e04c3fSmrg      return NULL;
3622cdc920a0Smrg   }
3623cdc920a0Smrg
36247ec681f3Smrg   if (dsa_ext) {
36257ec681f3Smrg      bufObj = _mesa_lookup_bufferobj(ctx, buffer);
36267ec681f3Smrg      if (!_mesa_handle_bind_buffer_gen(ctx, buffer, &bufObj, func))
36277ec681f3Smrg         return NULL;
36287ec681f3Smrg   } else {
36297ec681f3Smrg      bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, func);
36307ec681f3Smrg      if (!bufObj)
36317ec681f3Smrg         return NULL;
36327ec681f3Smrg   }
36337ec681f3Smrg
36347ec681f3Smrg   if (!validate_map_buffer_range(ctx, bufObj, offset, length, access, func))
363501e04c3fSmrg      return NULL;
3636cdc920a0Smrg
36377ec681f3Smrg   return map_buffer_range(ctx, bufObj, offset, length, access, func);
36387ec681f3Smrg}
36397ec681f3Smrg
36407ec681f3Smrgvoid * GLAPIENTRY
36417ec681f3Smrg_mesa_MapNamedBufferRangeEXT(GLuint buffer, GLintptr offset, GLsizeiptr length,
36427ec681f3Smrg                             GLbitfield access)
36437ec681f3Smrg{
36447ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
36457ec681f3Smrg   if (!buffer) {
36467ec681f3Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
36477ec681f3Smrg                  "glMapNamedBufferRangeEXT(buffer=0)");
364801e04c3fSmrg      return NULL;
36497ec681f3Smrg   }
36507ec681f3Smrg   return map_named_buffer_range(buffer, offset, length, access, true,
36517ec681f3Smrg                                 "glMapNamedBufferRangeEXT");
36527ec681f3Smrg}
3653cdc920a0Smrg
36547ec681f3Smrgvoid * GLAPIENTRY
36557ec681f3Smrg_mesa_MapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length,
36567ec681f3Smrg                          GLbitfield access)
36577ec681f3Smrg{
36587ec681f3Smrg   return map_named_buffer_range(buffer, offset, length, access, false,
36597ec681f3Smrg                                 "glMapNamedBufferRange");
3660cdc920a0Smrg}
3661cdc920a0Smrg
366201e04c3fSmrg/**
366301e04c3fSmrg * Converts GLenum access from MapBuffer and MapNamedBuffer into
366401e04c3fSmrg * flags for input to map_buffer_range.
366501e04c3fSmrg *
366601e04c3fSmrg * \return true if the type of requested access is permissible.
366701e04c3fSmrg */
366801e04c3fSmrgstatic bool
366901e04c3fSmrgget_map_buffer_access_flags(struct gl_context *ctx, GLenum access,
367001e04c3fSmrg                            GLbitfield *flags)
3671cdc920a0Smrg{
367201e04c3fSmrg   switch (access) {
367301e04c3fSmrg   case GL_READ_ONLY_ARB:
367401e04c3fSmrg      *flags = GL_MAP_READ_BIT;
367501e04c3fSmrg      return _mesa_is_desktop_gl(ctx);
367601e04c3fSmrg   case GL_WRITE_ONLY_ARB:
367701e04c3fSmrg      *flags = GL_MAP_WRITE_BIT;
367801e04c3fSmrg      return true;
367901e04c3fSmrg   case GL_READ_WRITE_ARB:
368001e04c3fSmrg      *flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
368101e04c3fSmrg      return _mesa_is_desktop_gl(ctx);
368201e04c3fSmrg   default:
368301e04c3fSmrg      *flags = 0;
368401e04c3fSmrg      return false;
3685cdc920a0Smrg   }
368601e04c3fSmrg}
3687cdc920a0Smrg
368801e04c3fSmrgvoid * GLAPIENTRY
368901e04c3fSmrg_mesa_MapBuffer_no_error(GLenum target, GLenum access)
369001e04c3fSmrg{
369101e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
3692cdc920a0Smrg
369301e04c3fSmrg   GLbitfield accessFlags;
369401e04c3fSmrg   get_map_buffer_access_flags(ctx, access, &accessFlags);
3695cdc920a0Smrg
369601e04c3fSmrg   struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target);
369701e04c3fSmrg   struct gl_buffer_object *bufObj = *bufObjPtr;
3698cdc920a0Smrg
369901e04c3fSmrg   return map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags,
370001e04c3fSmrg                           "glMapBuffer");
3701cdc920a0Smrg}
3702cdc920a0Smrg
370301e04c3fSmrgvoid * GLAPIENTRY
370401e04c3fSmrg_mesa_MapBuffer(GLenum target, GLenum access)
3705cdc920a0Smrg{
370601e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
370701e04c3fSmrg   struct gl_buffer_object *bufObj;
370801e04c3fSmrg   GLbitfield accessFlags;
3709cdc920a0Smrg
371001e04c3fSmrg   if (!get_map_buffer_access_flags(ctx, access, &accessFlags)) {
371101e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glMapBuffer(invalid access)");
371201e04c3fSmrg      return NULL;
3713cdc920a0Smrg   }
3714cdc920a0Smrg
371501e04c3fSmrg   bufObj = get_buffer(ctx, "glMapBuffer", target, GL_INVALID_OPERATION);
371601e04c3fSmrg   if (!bufObj)
371701e04c3fSmrg      return NULL;
3718cdc920a0Smrg
371901e04c3fSmrg   if (!validate_map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags,
372001e04c3fSmrg                                  "glMapBuffer"))
372101e04c3fSmrg      return NULL;
3722cdc920a0Smrg
372301e04c3fSmrg   return map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags,
372401e04c3fSmrg                           "glMapBuffer");
3725cdc920a0Smrg}
3726cdc920a0Smrg
372701e04c3fSmrgvoid * GLAPIENTRY
372801e04c3fSmrg_mesa_MapNamedBuffer_no_error(GLuint buffer, GLenum access)
372901e04c3fSmrg{
373001e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
373101e04c3fSmrg
373201e04c3fSmrg   GLbitfield accessFlags;
373301e04c3fSmrg   get_map_buffer_access_flags(ctx, access, &accessFlags);
373401e04c3fSmrg
373501e04c3fSmrg   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
373601e04c3fSmrg
373701e04c3fSmrg   return map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags,
373801e04c3fSmrg                           "glMapNamedBuffer");
373901e04c3fSmrg}
3740cdc920a0Smrg
374101e04c3fSmrgvoid * GLAPIENTRY
374201e04c3fSmrg_mesa_MapNamedBuffer(GLuint buffer, GLenum access)
3743cdc920a0Smrg{
3744cdc920a0Smrg   GET_CURRENT_CONTEXT(ctx);
374501e04c3fSmrg   struct gl_buffer_object *bufObj;
374601e04c3fSmrg   GLbitfield accessFlags;
3747cdc920a0Smrg
374801e04c3fSmrg   if (!get_map_buffer_access_flags(ctx, access, &accessFlags)) {
374901e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glMapNamedBuffer(invalid access)");
375001e04c3fSmrg      return NULL;
3751cdc920a0Smrg   }
3752cdc920a0Smrg
375301e04c3fSmrg   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glMapNamedBuffer");
375401e04c3fSmrg   if (!bufObj)
375501e04c3fSmrg      return NULL;
375601e04c3fSmrg
375701e04c3fSmrg   if (!validate_map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags,
375801e04c3fSmrg                                  "glMapNamedBuffer"))
375901e04c3fSmrg      return NULL;
376001e04c3fSmrg
376101e04c3fSmrg   return map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags,
376201e04c3fSmrg                           "glMapNamedBuffer");
3763cdc920a0Smrg}
3764cdc920a0Smrg
37657ec681f3Smrgvoid * GLAPIENTRY
37667ec681f3Smrg_mesa_MapNamedBufferEXT(GLuint buffer, GLenum access)
37677ec681f3Smrg{
37687ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
37697ec681f3Smrg
37707ec681f3Smrg   GLbitfield accessFlags;
37717ec681f3Smrg   if (!buffer) {
37727ec681f3Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
37737ec681f3Smrg                  "glMapNamedBufferEXT(buffer=0)");
37747ec681f3Smrg      return NULL;
37757ec681f3Smrg   }
37767ec681f3Smrg   if (!get_map_buffer_access_flags(ctx, access, &accessFlags)) {
37777ec681f3Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glMapNamedBufferEXT(invalid access)");
37787ec681f3Smrg      return NULL;
37797ec681f3Smrg   }
37807ec681f3Smrg
37817ec681f3Smrg   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
37827ec681f3Smrg   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
37837ec681f3Smrg                                     &bufObj, "glMapNamedBufferEXT"))
37847ec681f3Smrg      return NULL;
37857ec681f3Smrg
37867ec681f3Smrg   if (!validate_map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags,
37877ec681f3Smrg                                  "glMapNamedBufferEXT"))
37887ec681f3Smrg      return NULL;
37897ec681f3Smrg
37907ec681f3Smrg   return map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags,
37917ec681f3Smrg                           "glMapNamedBufferEXT");
37927ec681f3Smrg}
3793cdc920a0Smrg
3794cdc920a0Smrgstatic void
379501e04c3fSmrgflush_mapped_buffer_range(struct gl_context *ctx,
379601e04c3fSmrg                          struct gl_buffer_object *bufObj,
379701e04c3fSmrg                          GLintptr offset, GLsizeiptr length,
379801e04c3fSmrg                          const char *func)
3799cdc920a0Smrg{
380001e04c3fSmrg   if (!ctx->Extensions.ARB_map_buffer_range) {
380101e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
380201e04c3fSmrg                  "%s(ARB_map_buffer_range not supported)", func);
3803cdc920a0Smrg      return;
3804cdc920a0Smrg   }
3805cdc920a0Smrg
380601e04c3fSmrg   if (offset < 0) {
380701e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
380801e04c3fSmrg                  "%s(offset %ld < 0)", func, (long) offset);
380901e04c3fSmrg      return;
3810cdc920a0Smrg   }
3811cdc920a0Smrg
381201e04c3fSmrg   if (length < 0) {
3813cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
381401e04c3fSmrg                  "%s(length %ld < 0)", func, (long) length);
3815cdc920a0Smrg      return;
3816cdc920a0Smrg   }
3817cdc920a0Smrg
381801e04c3fSmrg   if (!_mesa_bufferobj_mapped(bufObj, MAP_USER)) {
381901e04c3fSmrg      /* buffer is not mapped */
382001e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
382101e04c3fSmrg                  "%s(buffer is not mapped)", func);
382201e04c3fSmrg      return;
3823cdc920a0Smrg   }
3824cdc920a0Smrg
382501e04c3fSmrg   if ((bufObj->Mappings[MAP_USER].AccessFlags &
382601e04c3fSmrg        GL_MAP_FLUSH_EXPLICIT_BIT) == 0) {
382701e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
382801e04c3fSmrg                  "%s(GL_MAP_FLUSH_EXPLICIT_BIT not set)", func);
382901e04c3fSmrg      return;
383001e04c3fSmrg   }
3831cdc920a0Smrg
383201e04c3fSmrg   if (offset + length > bufObj->Mappings[MAP_USER].Length) {
3833cdc920a0Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
383401e04c3fSmrg                  "%s(offset %ld + length %ld > mapped length %ld)", func,
383501e04c3fSmrg                  (long) offset, (long) length,
383601e04c3fSmrg                  (long) bufObj->Mappings[MAP_USER].Length);
3837cdc920a0Smrg      return;
3838cdc920a0Smrg   }
3839cdc920a0Smrg
384001e04c3fSmrg   assert(bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_WRITE_BIT);
384101e04c3fSmrg
384201e04c3fSmrg   if (ctx->Driver.FlushMappedBufferRange)
384301e04c3fSmrg      ctx->Driver.FlushMappedBufferRange(ctx, offset, length, bufObj,
384401e04c3fSmrg                                         MAP_USER);
3845cdc920a0Smrg}
3846cdc920a0Smrg
384701e04c3fSmrgvoid GLAPIENTRY
384801e04c3fSmrg_mesa_FlushMappedBufferRange_no_error(GLenum target, GLintptr offset,
384901e04c3fSmrg                                      GLsizeiptr length)
385001e04c3fSmrg{
385101e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
385201e04c3fSmrg   struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target);
385301e04c3fSmrg   struct gl_buffer_object *bufObj = *bufObjPtr;
385401e04c3fSmrg
385501e04c3fSmrg   if (ctx->Driver.FlushMappedBufferRange)
385601e04c3fSmrg      ctx->Driver.FlushMappedBufferRange(ctx, offset, length, bufObj,
385701e04c3fSmrg                                         MAP_USER);
385801e04c3fSmrg}
3859cdc920a0Smrg
3860cdc920a0Smrgvoid GLAPIENTRY
386101e04c3fSmrg_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset,
386201e04c3fSmrg                             GLsizeiptr length)
3863cdc920a0Smrg{
3864cdc920a0Smrg   GET_CURRENT_CONTEXT(ctx);
386501e04c3fSmrg   struct gl_buffer_object *bufObj;
3866cdc920a0Smrg
386701e04c3fSmrg   bufObj = get_buffer(ctx, "glFlushMappedBufferRange", target,
386801e04c3fSmrg                       GL_INVALID_OPERATION);
386901e04c3fSmrg   if (!bufObj)
3870cdc920a0Smrg      return;
3871cdc920a0Smrg
387201e04c3fSmrg   flush_mapped_buffer_range(ctx, bufObj, offset, length,
387301e04c3fSmrg                             "glFlushMappedBufferRange");
3874cdc920a0Smrg}
3875cdc920a0Smrg
387601e04c3fSmrgvoid GLAPIENTRY
387701e04c3fSmrg_mesa_FlushMappedNamedBufferRange_no_error(GLuint buffer, GLintptr offset,
387801e04c3fSmrg                                           GLsizeiptr length)
387901e04c3fSmrg{
388001e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
388101e04c3fSmrg   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
388201e04c3fSmrg
388301e04c3fSmrg   if (ctx->Driver.FlushMappedBufferRange)
388401e04c3fSmrg      ctx->Driver.FlushMappedBufferRange(ctx, offset, length, bufObj,
388501e04c3fSmrg                                         MAP_USER);
388601e04c3fSmrg}
388701e04c3fSmrg
388801e04c3fSmrgvoid GLAPIENTRY
388901e04c3fSmrg_mesa_FlushMappedNamedBufferRange(GLuint buffer, GLintptr offset,
389001e04c3fSmrg                                  GLsizeiptr length)
3891af69d88dSmrg{
389201e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
389301e04c3fSmrg   struct gl_buffer_object *bufObj;
3894af69d88dSmrg
389501e04c3fSmrg   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer,
389601e04c3fSmrg                                       "glFlushMappedNamedBufferRange");
389701e04c3fSmrg   if (!bufObj)
389801e04c3fSmrg      return;
389901e04c3fSmrg
390001e04c3fSmrg   flush_mapped_buffer_range(ctx, bufObj, offset, length,
390101e04c3fSmrg                             "glFlushMappedNamedBufferRange");
3902af69d88dSmrg}
3903af69d88dSmrg
39047ec681f3Smrgvoid GLAPIENTRY
39057ec681f3Smrg_mesa_FlushMappedNamedBufferRangeEXT(GLuint buffer, GLintptr offset,
39067ec681f3Smrg                                     GLsizeiptr length)
39077ec681f3Smrg{
39087ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
39097ec681f3Smrg   struct gl_buffer_object *bufObj;
39107ec681f3Smrg
39117ec681f3Smrg   if (!buffer) {
39127ec681f3Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
39137ec681f3Smrg                  "glFlushMappedNamedBufferRangeEXT(buffer=0)");
39147ec681f3Smrg      return;
39157ec681f3Smrg   }
39167ec681f3Smrg
39177ec681f3Smrg   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
39187ec681f3Smrg   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
39197ec681f3Smrg                                     &bufObj, "glFlushMappedNamedBufferRangeEXT"))
39207ec681f3Smrg      return;
39217ec681f3Smrg
39227ec681f3Smrg   flush_mapped_buffer_range(ctx, bufObj, offset, length,
39237ec681f3Smrg                             "glFlushMappedNamedBufferRangeEXT");
39247ec681f3Smrg}
39257ec681f3Smrg
3926af69d88dSmrgstatic void
392701e04c3fSmrgbind_buffer_range_uniform_buffer(struct gl_context *ctx, GLuint index,
392801e04c3fSmrg                                 struct gl_buffer_object *bufObj,
392901e04c3fSmrg                                 GLintptr offset, GLsizeiptr size)
3930af69d88dSmrg{
39317ec681f3Smrg   if (!bufObj) {
393201e04c3fSmrg      offset = -1;
393301e04c3fSmrg      size = -1;
3934af69d88dSmrg   }
3935af69d88dSmrg
393601e04c3fSmrg   _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj);
393701e04c3fSmrg   bind_uniform_buffer(ctx, index, bufObj, offset, size, GL_FALSE);
3938af69d88dSmrg}
3939af69d88dSmrg
3940af69d88dSmrg/**
3941af69d88dSmrg * Bind a region of a buffer object to a uniform block binding point.
3942af69d88dSmrg * \param index  the uniform buffer binding point index
3943af69d88dSmrg * \param bufObj  the buffer object
3944af69d88dSmrg * \param offset  offset to the start of buffer object region
3945af69d88dSmrg * \param size  size of the buffer object region
3946af69d88dSmrg */
3947af69d88dSmrgstatic void
394801e04c3fSmrgbind_buffer_range_uniform_buffer_err(struct gl_context *ctx, GLuint index,
394901e04c3fSmrg                                     struct gl_buffer_object *bufObj,
395001e04c3fSmrg                                     GLintptr offset, GLsizeiptr size)
3951af69d88dSmrg{
3952af69d88dSmrg   if (index >= ctx->Const.MaxUniformBufferBindings) {
3953af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index);
3954af69d88dSmrg      return;
3955af69d88dSmrg   }
3956af69d88dSmrg
3957af69d88dSmrg   if (offset & (ctx->Const.UniformBufferOffsetAlignment - 1)) {
3958af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
395901e04c3fSmrg                  "glBindBufferRange(offset misaligned %d/%d)", (int) offset,
3960af69d88dSmrg		  ctx->Const.UniformBufferOffsetAlignment);
3961af69d88dSmrg      return;
3962af69d88dSmrg   }
3963af69d88dSmrg
396401e04c3fSmrg   bind_buffer_range_uniform_buffer(ctx, index, bufObj, offset, size);
396501e04c3fSmrg}
396601e04c3fSmrg
396701e04c3fSmrgstatic void
396801e04c3fSmrgbind_buffer_range_shader_storage_buffer(struct gl_context *ctx,
396901e04c3fSmrg                                        GLuint index,
397001e04c3fSmrg                                        struct gl_buffer_object *bufObj,
397101e04c3fSmrg                                        GLintptr offset,
397201e04c3fSmrg                                        GLsizeiptr size)
397301e04c3fSmrg{
39747ec681f3Smrg   if (!bufObj) {
3975af69d88dSmrg      offset = -1;
3976af69d88dSmrg      size = -1;
3977af69d88dSmrg   }
3978af69d88dSmrg
397901e04c3fSmrg   _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer, bufObj);
398001e04c3fSmrg   bind_shader_storage_buffer(ctx, index, bufObj, offset, size, GL_FALSE);
3981af69d88dSmrg}
3982af69d88dSmrg
3983af69d88dSmrg/**
398401e04c3fSmrg * Bind a region of a buffer object to a shader storage block binding point.
398501e04c3fSmrg * \param index  the shader storage buffer binding point index
398601e04c3fSmrg * \param bufObj  the buffer object
398701e04c3fSmrg * \param offset  offset to the start of buffer object region
398801e04c3fSmrg * \param size  size of the buffer object region
3989af69d88dSmrg */
3990af69d88dSmrgstatic void
399101e04c3fSmrgbind_buffer_range_shader_storage_buffer_err(struct gl_context *ctx,
399201e04c3fSmrg                                            GLuint index,
399301e04c3fSmrg                                            struct gl_buffer_object *bufObj,
399401e04c3fSmrg                                            GLintptr offset, GLsizeiptr size)
3995af69d88dSmrg{
399601e04c3fSmrg   if (index >= ctx->Const.MaxShaderStorageBufferBindings) {
399701e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index);
3998af69d88dSmrg      return;
3999af69d88dSmrg   }
4000af69d88dSmrg
400101e04c3fSmrg   if (offset & (ctx->Const.ShaderStorageBufferOffsetAlignment - 1)) {
400201e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
400301e04c3fSmrg                  "glBindBufferRange(offset misaligned %d/%d)", (int) offset,
400401e04c3fSmrg                  ctx->Const.ShaderStorageBufferOffsetAlignment);
400501e04c3fSmrg      return;
400601e04c3fSmrg   }
4007af69d88dSmrg
400801e04c3fSmrg   bind_buffer_range_shader_storage_buffer(ctx, index, bufObj, offset, size);
4009af69d88dSmrg}
4010af69d88dSmrg
4011af69d88dSmrgstatic void
401201e04c3fSmrgbind_buffer_range_atomic_buffer(struct gl_context *ctx, GLuint index,
401301e04c3fSmrg                                 struct gl_buffer_object *bufObj,
401401e04c3fSmrg                                 GLintptr offset, GLsizeiptr size)
4015af69d88dSmrg{
40167ec681f3Smrg   if (!bufObj) {
401701e04c3fSmrg      offset = -1;
401801e04c3fSmrg      size = -1;
4019af69d88dSmrg   }
402001e04c3fSmrg
402101e04c3fSmrg   _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, bufObj);
402201e04c3fSmrg   bind_atomic_buffer(ctx, index, bufObj, offset, size, GL_FALSE);
4023af69d88dSmrg}
4024af69d88dSmrg
4025af69d88dSmrg/**
402601e04c3fSmrg * Bind a region of a buffer object to an atomic storage block binding point.
402701e04c3fSmrg * \param index  the shader storage buffer binding point index
402801e04c3fSmrg * \param bufObj  the buffer object
402901e04c3fSmrg * \param offset  offset to the start of buffer object region
403001e04c3fSmrg * \param size  size of the buffer object region
4031af69d88dSmrg */
4032af69d88dSmrgstatic void
403301e04c3fSmrgbind_buffer_range_atomic_buffer_err(struct gl_context *ctx,
403401e04c3fSmrg                                    GLuint index,
403501e04c3fSmrg                                    struct gl_buffer_object *bufObj,
403601e04c3fSmrg                                    GLintptr offset, GLsizeiptr size)
4037af69d88dSmrg{
4038af69d88dSmrg   if (index >= ctx->Const.MaxAtomicBufferBindings) {
403901e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index);
4040af69d88dSmrg      return;
4041af69d88dSmrg   }
4042af69d88dSmrg
4043af69d88dSmrg   if (offset & (ATOMIC_COUNTER_SIZE - 1)) {
4044af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
404501e04c3fSmrg		  "glBindBufferRange(offset misaligned %d/%d)", (int) offset,
404601e04c3fSmrg		  ATOMIC_COUNTER_SIZE);
4047af69d88dSmrg      return;
4048af69d88dSmrg   }
4049af69d88dSmrg
405001e04c3fSmrg   bind_buffer_range_atomic_buffer(ctx, index, bufObj, offset, size);
4051af69d88dSmrg}
4052af69d88dSmrg
4053af69d88dSmrgstatic inline bool
4054af69d88dSmrgbind_buffers_check_offset_and_size(struct gl_context *ctx,
4055af69d88dSmrg                                   GLuint index,
4056af69d88dSmrg                                   const GLintptr *offsets,
4057af69d88dSmrg                                   const GLsizeiptr *sizes)
4058af69d88dSmrg{
4059af69d88dSmrg   if (offsets[index] < 0) {
406001e04c3fSmrg      /* The ARB_multi_bind spec says:
406101e04c3fSmrg       *
406201e04c3fSmrg       *    "An INVALID_VALUE error is generated by BindBuffersRange if any
406301e04c3fSmrg       *     value in <offsets> is less than zero (per binding)."
406401e04c3fSmrg       */
4065af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
4066af69d88dSmrg                  "glBindBuffersRange(offsets[%u]=%" PRId64 " < 0)",
4067af69d88dSmrg                  index, (int64_t) offsets[index]);
4068af69d88dSmrg      return false;
4069af69d88dSmrg   }
4070af69d88dSmrg
4071af69d88dSmrg   if (sizes[index] <= 0) {
407201e04c3fSmrg      /* The ARB_multi_bind spec says:
407301e04c3fSmrg       *
407401e04c3fSmrg       *     "An INVALID_VALUE error is generated by BindBuffersRange if any
407501e04c3fSmrg       *      value in <sizes> is less than or equal to zero (per binding)."
407601e04c3fSmrg       */
4077af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
4078af69d88dSmrg                  "glBindBuffersRange(sizes[%u]=%" PRId64 " <= 0)",
4079af69d88dSmrg                  index, (int64_t) sizes[index]);
4080af69d88dSmrg      return false;
4081af69d88dSmrg   }
4082af69d88dSmrg
4083af69d88dSmrg   return true;
4084af69d88dSmrg}
4085af69d88dSmrg
4086af69d88dSmrgstatic bool
4087af69d88dSmrgerror_check_bind_uniform_buffers(struct gl_context *ctx,
4088af69d88dSmrg                                 GLuint first, GLsizei count,
4089af69d88dSmrg                                 const char *caller)
4090af69d88dSmrg{
4091af69d88dSmrg   if (!ctx->Extensions.ARB_uniform_buffer_object) {
4092af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
4093af69d88dSmrg                  "%s(target=GL_UNIFORM_BUFFER)", caller);
4094af69d88dSmrg      return false;
4095af69d88dSmrg   }
4096af69d88dSmrg
4097af69d88dSmrg   /* The ARB_multi_bind_spec says:
4098af69d88dSmrg    *
4099af69d88dSmrg    *     "An INVALID_OPERATION error is generated if <first> + <count> is
4100af69d88dSmrg    *      greater than the number of target-specific indexed binding points,
4101af69d88dSmrg    *      as described in section 6.7.1."
4102af69d88dSmrg    */
4103af69d88dSmrg   if (first + count > ctx->Const.MaxUniformBufferBindings) {
4104af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
4105af69d88dSmrg                  "%s(first=%u + count=%d > the value of "
4106af69d88dSmrg                  "GL_MAX_UNIFORM_BUFFER_BINDINGS=%u)",
4107af69d88dSmrg                  caller, first, count,
4108af69d88dSmrg                  ctx->Const.MaxUniformBufferBindings);
4109af69d88dSmrg      return false;
4110af69d88dSmrg   }
4111af69d88dSmrg
4112af69d88dSmrg   return true;
4113af69d88dSmrg}
4114af69d88dSmrg
411501e04c3fSmrgstatic bool
411601e04c3fSmrgerror_check_bind_shader_storage_buffers(struct gl_context *ctx,
411701e04c3fSmrg                                        GLuint first, GLsizei count,
411801e04c3fSmrg                                        const char *caller)
411901e04c3fSmrg{
412001e04c3fSmrg   if (!ctx->Extensions.ARB_shader_storage_buffer_object) {
412101e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
412201e04c3fSmrg                  "%s(target=GL_SHADER_STORAGE_BUFFER)", caller);
412301e04c3fSmrg      return false;
412401e04c3fSmrg   }
412501e04c3fSmrg
412601e04c3fSmrg   /* The ARB_multi_bind_spec says:
412701e04c3fSmrg    *
412801e04c3fSmrg    *     "An INVALID_OPERATION error is generated if <first> + <count> is
412901e04c3fSmrg    *      greater than the number of target-specific indexed binding points,
413001e04c3fSmrg    *      as described in section 6.7.1."
413101e04c3fSmrg    */
413201e04c3fSmrg   if (first + count > ctx->Const.MaxShaderStorageBufferBindings) {
413301e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
413401e04c3fSmrg                  "%s(first=%u + count=%d > the value of "
413501e04c3fSmrg                  "GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS=%u)",
413601e04c3fSmrg                  caller, first, count,
413701e04c3fSmrg                  ctx->Const.MaxShaderStorageBufferBindings);
413801e04c3fSmrg      return false;
413901e04c3fSmrg   }
414001e04c3fSmrg
414101e04c3fSmrg   return true;
414201e04c3fSmrg}
414301e04c3fSmrg
4144af69d88dSmrg/**
4145af69d88dSmrg * Unbind all uniform buffers in the range
4146af69d88dSmrg * <first> through <first>+<count>-1
4147af69d88dSmrg */
4148af69d88dSmrgstatic void
4149af69d88dSmrgunbind_uniform_buffers(struct gl_context *ctx, GLuint first, GLsizei count)
4150af69d88dSmrg{
415101e04c3fSmrg   for (int i = 0; i < count; i++)
415201e04c3fSmrg      set_buffer_binding(ctx, &ctx->UniformBufferBindings[first + i],
41537ec681f3Smrg                         NULL, -1, -1, GL_TRUE, 0);
4154af69d88dSmrg}
4155af69d88dSmrg
415601e04c3fSmrg/**
415701e04c3fSmrg * Unbind all shader storage buffers in the range
415801e04c3fSmrg * <first> through <first>+<count>-1
415901e04c3fSmrg */
4160af69d88dSmrgstatic void
416101e04c3fSmrgunbind_shader_storage_buffers(struct gl_context *ctx, GLuint first,
416201e04c3fSmrg                              GLsizei count)
4163af69d88dSmrg{
416401e04c3fSmrg   for (int i = 0; i < count; i++)
416501e04c3fSmrg      set_buffer_binding(ctx, &ctx->ShaderStorageBufferBindings[first + i],
41667ec681f3Smrg                         NULL, -1, -1, GL_TRUE, 0);
416701e04c3fSmrg}
4168af69d88dSmrg
416901e04c3fSmrgstatic void
417001e04c3fSmrgbind_uniform_buffers(struct gl_context *ctx, GLuint first, GLsizei count,
417101e04c3fSmrg                     const GLuint *buffers,
417201e04c3fSmrg                     bool range,
417301e04c3fSmrg                     const GLintptr *offsets, const GLsizeiptr *sizes,
417401e04c3fSmrg                     const char *caller)
417501e04c3fSmrg{
417601e04c3fSmrg   if (!error_check_bind_uniform_buffers(ctx, first, count, caller))
4177af69d88dSmrg      return;
4178af69d88dSmrg
4179af69d88dSmrg   /* Assume that at least one binding will be changed */
41807ec681f3Smrg   FLUSH_VERTICES(ctx, 0, 0);
4181af69d88dSmrg   ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer;
4182af69d88dSmrg
4183af69d88dSmrg   if (!buffers) {
4184af69d88dSmrg      /* The ARB_multi_bind spec says:
4185af69d88dSmrg       *
418601e04c3fSmrg       *    "If <buffers> is NULL, all bindings from <first> through
418701e04c3fSmrg       *     <first>+<count>-1 are reset to their unbound (zero) state.
418801e04c3fSmrg       *     In this case, the offsets and sizes associated with the
418901e04c3fSmrg       *     binding points are set to default values, ignoring
419001e04c3fSmrg       *     <offsets> and <sizes>."
4191af69d88dSmrg       */
4192af69d88dSmrg      unbind_uniform_buffers(ctx, first, count);
4193af69d88dSmrg      return;
4194af69d88dSmrg   }
4195af69d88dSmrg
4196af69d88dSmrg   /* Note that the error semantics for multi-bind commands differ from
4197af69d88dSmrg    * those of other GL commands.
4198af69d88dSmrg    *
4199af69d88dSmrg    * The Issues section in the ARB_multi_bind spec says:
4200af69d88dSmrg    *
4201af69d88dSmrg    *    "(11) Typically, OpenGL specifies that if an error is generated by a
4202af69d88dSmrg    *          command, that command has no effect.  This is somewhat
4203af69d88dSmrg    *          unfortunate for multi-bind commands, because it would require a
4204af69d88dSmrg    *          first pass to scan the entire list of bound objects for errors
4205af69d88dSmrg    *          and then a second pass to actually perform the bindings.
4206af69d88dSmrg    *          Should we have different error semantics?
4207af69d88dSmrg    *
4208af69d88dSmrg    *       RESOLVED:  Yes.  In this specification, when the parameters for
4209af69d88dSmrg    *       one of the <count> binding points are invalid, that binding point
4210af69d88dSmrg    *       is not updated and an error will be generated.  However, other
4211af69d88dSmrg    *       binding points in the same command will be updated if their
4212af69d88dSmrg    *       parameters are valid and no other error occurs."
4213af69d88dSmrg    */
4214af69d88dSmrg
42157ec681f3Smrg   _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects,
42167ec681f3Smrg                             ctx->BufferObjectsLocked);
4217af69d88dSmrg
421801e04c3fSmrg   for (int i = 0; i < count; i++) {
421901e04c3fSmrg      struct gl_buffer_binding *binding =
422001e04c3fSmrg         &ctx->UniformBufferBindings[first + i];
422101e04c3fSmrg      GLintptr offset = 0;
422201e04c3fSmrg      GLsizeiptr size = 0;
4223af69d88dSmrg
422401e04c3fSmrg      if (range) {
422501e04c3fSmrg         if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
422601e04c3fSmrg            continue;
4227af69d88dSmrg
422801e04c3fSmrg         /* The ARB_multi_bind spec says:
422901e04c3fSmrg          *
423001e04c3fSmrg          *     "An INVALID_VALUE error is generated by BindBuffersRange if any
423101e04c3fSmrg          *      pair of values in <offsets> and <sizes> does not respectively
423201e04c3fSmrg          *      satisfy the constraints described for those parameters for the
423301e04c3fSmrg          *      specified target, as described in section 6.7.1 (per binding)."
423401e04c3fSmrg          *
423501e04c3fSmrg          * Section 6.7.1 refers to table 6.5, which says:
423601e04c3fSmrg          *
423701e04c3fSmrg          *     "┌───────────────────────────────────────────────────────────────┐
423801e04c3fSmrg          *      │ Uniform buffer array bindings (see sec. 7.6)                  │
423901e04c3fSmrg          *      ├─────────────────────┬─────────────────────────────────────────┤
424001e04c3fSmrg          *      │  ...                │  ...                                    │
424101e04c3fSmrg          *      │  offset restriction │  multiple of value of UNIFORM_BUFFER_-  │
424201e04c3fSmrg          *      │                     │  OFFSET_ALIGNMENT                       │
424301e04c3fSmrg          *      │  ...                │  ...                                    │
424401e04c3fSmrg          *      │  size restriction   │  none                                   │
424501e04c3fSmrg          *      └─────────────────────┴─────────────────────────────────────────┘"
424601e04c3fSmrg          */
424701e04c3fSmrg         if (offsets[i] & (ctx->Const.UniformBufferOffsetAlignment - 1)) {
424801e04c3fSmrg            _mesa_error(ctx, GL_INVALID_VALUE,
424901e04c3fSmrg                        "glBindBuffersRange(offsets[%u]=%" PRId64
425001e04c3fSmrg                        " is misaligned; it must be a multiple of the value of "
425101e04c3fSmrg                        "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT=%u when "
425201e04c3fSmrg                        "target=GL_UNIFORM_BUFFER)",
425301e04c3fSmrg                        i, (int64_t) offsets[i],
425401e04c3fSmrg                        ctx->Const.UniformBufferOffsetAlignment);
425501e04c3fSmrg            continue;
425601e04c3fSmrg         }
425701e04c3fSmrg
425801e04c3fSmrg         offset = offsets[i];
425901e04c3fSmrg         size = sizes[i];
4260af69d88dSmrg      }
426101e04c3fSmrg
426201e04c3fSmrg      set_buffer_multi_binding(ctx, buffers, i, caller,
426301e04c3fSmrg                               binding, offset, size, range,
426401e04c3fSmrg                               USAGE_UNIFORM_BUFFER);
4265af69d88dSmrg   }
4266af69d88dSmrg
42677ec681f3Smrg   _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects,
42687ec681f3Smrg                               ctx->BufferObjectsLocked);
4269af69d88dSmrg}
4270af69d88dSmrg
4271af69d88dSmrgstatic void
427201e04c3fSmrgbind_shader_storage_buffers(struct gl_context *ctx, GLuint first,
427301e04c3fSmrg                            GLsizei count, const GLuint *buffers,
427401e04c3fSmrg                            bool range,
427501e04c3fSmrg                            const GLintptr *offsets,
427601e04c3fSmrg                            const GLsizeiptr *sizes,
427701e04c3fSmrg                            const char *caller)
4278af69d88dSmrg{
427901e04c3fSmrg   if (!error_check_bind_shader_storage_buffers(ctx, first, count, caller))
4280af69d88dSmrg      return;
4281af69d88dSmrg
4282af69d88dSmrg   /* Assume that at least one binding will be changed */
42837ec681f3Smrg   FLUSH_VERTICES(ctx, 0, 0);
428401e04c3fSmrg   ctx->NewDriverState |= ctx->DriverFlags.NewShaderStorageBuffer;
4285af69d88dSmrg
4286af69d88dSmrg   if (!buffers) {
4287af69d88dSmrg      /* The ARB_multi_bind spec says:
4288af69d88dSmrg       *
4289af69d88dSmrg       *    "If <buffers> is NULL, all bindings from <first> through
4290af69d88dSmrg       *     <first>+<count>-1 are reset to their unbound (zero) state.
4291af69d88dSmrg       *     In this case, the offsets and sizes associated with the
4292af69d88dSmrg       *     binding points are set to default values, ignoring
4293af69d88dSmrg       *     <offsets> and <sizes>."
4294af69d88dSmrg       */
429501e04c3fSmrg      unbind_shader_storage_buffers(ctx, first, count);
4296af69d88dSmrg      return;
4297af69d88dSmrg   }
4298af69d88dSmrg
4299af69d88dSmrg   /* Note that the error semantics for multi-bind commands differ from
4300af69d88dSmrg    * those of other GL commands.
4301af69d88dSmrg    *
4302af69d88dSmrg    * The Issues section in the ARB_multi_bind spec says:
4303af69d88dSmrg    *
4304af69d88dSmrg    *    "(11) Typically, OpenGL specifies that if an error is generated by a
4305af69d88dSmrg    *          command, that command has no effect.  This is somewhat
4306af69d88dSmrg    *          unfortunate for multi-bind commands, because it would require a
4307af69d88dSmrg    *          first pass to scan the entire list of bound objects for errors
4308af69d88dSmrg    *          and then a second pass to actually perform the bindings.
4309af69d88dSmrg    *          Should we have different error semantics?
4310af69d88dSmrg    *
4311af69d88dSmrg    *       RESOLVED:  Yes.  In this specification, when the parameters for
4312af69d88dSmrg    *       one of the <count> binding points are invalid, that binding point
4313af69d88dSmrg    *       is not updated and an error will be generated.  However, other
4314af69d88dSmrg    *       binding points in the same command will be updated if their
4315af69d88dSmrg    *       parameters are valid and no other error occurs."
4316af69d88dSmrg    */
4317af69d88dSmrg
43187ec681f3Smrg   _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects,
43197ec681f3Smrg                             ctx->BufferObjectsLocked);
4320af69d88dSmrg
432101e04c3fSmrg   for (int i = 0; i < count; i++) {
432201e04c3fSmrg      struct gl_buffer_binding *binding =
432301e04c3fSmrg         &ctx->ShaderStorageBufferBindings[first + i];
432401e04c3fSmrg      GLintptr offset = 0;
432501e04c3fSmrg      GLsizeiptr size = 0;
432601e04c3fSmrg
432701e04c3fSmrg      if (range) {
432801e04c3fSmrg         if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
432901e04c3fSmrg            continue;
433001e04c3fSmrg
433101e04c3fSmrg         /* The ARB_multi_bind spec says:
433201e04c3fSmrg         *
433301e04c3fSmrg         *     "An INVALID_VALUE error is generated by BindBuffersRange if any
433401e04c3fSmrg         *      pair of values in <offsets> and <sizes> does not respectively
433501e04c3fSmrg         *      satisfy the constraints described for those parameters for the
433601e04c3fSmrg         *      specified target, as described in section 6.7.1 (per binding)."
433701e04c3fSmrg         *
433801e04c3fSmrg         * Section 6.7.1 refers to table 6.5, which says:
433901e04c3fSmrg         *
434001e04c3fSmrg         *     "┌───────────────────────────────────────────────────────────────┐
434101e04c3fSmrg         *      │ Shader storage buffer array bindings (see sec. 7.8)           │
434201e04c3fSmrg         *      ├─────────────────────┬─────────────────────────────────────────┤
434301e04c3fSmrg         *      │  ...                │  ...                                    │
434401e04c3fSmrg         *      │  offset restriction │  multiple of value of SHADER_STORAGE_-  │
434501e04c3fSmrg         *      │                     │  BUFFER_OFFSET_ALIGNMENT                │
434601e04c3fSmrg         *      │  ...                │  ...                                    │
434701e04c3fSmrg         *      │  size restriction   │  none                                   │
434801e04c3fSmrg         *      └─────────────────────┴─────────────────────────────────────────┘"
434901e04c3fSmrg         */
435001e04c3fSmrg         if (offsets[i] & (ctx->Const.ShaderStorageBufferOffsetAlignment - 1)) {
435101e04c3fSmrg            _mesa_error(ctx, GL_INVALID_VALUE,
435201e04c3fSmrg                        "glBindBuffersRange(offsets[%u]=%" PRId64
435301e04c3fSmrg                        " is misaligned; it must be a multiple of the value of "
435401e04c3fSmrg                        "GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT=%u when "
435501e04c3fSmrg                        "target=GL_SHADER_STORAGE_BUFFER)",
435601e04c3fSmrg                        i, (int64_t) offsets[i],
435701e04c3fSmrg                        ctx->Const.ShaderStorageBufferOffsetAlignment);
435801e04c3fSmrg            continue;
435901e04c3fSmrg         }
4360af69d88dSmrg
436101e04c3fSmrg         offset = offsets[i];
436201e04c3fSmrg         size = sizes[i];
4363af69d88dSmrg      }
4364af69d88dSmrg
436501e04c3fSmrg      set_buffer_multi_binding(ctx, buffers, i, caller,
436601e04c3fSmrg                               binding, offset, size, range,
436701e04c3fSmrg                               USAGE_SHADER_STORAGE_BUFFER);
4368af69d88dSmrg   }
4369af69d88dSmrg
43707ec681f3Smrg   _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects,
43717ec681f3Smrg                               ctx->BufferObjectsLocked);
4372af69d88dSmrg}
4373af69d88dSmrg
4374af69d88dSmrgstatic bool
4375af69d88dSmrgerror_check_bind_xfb_buffers(struct gl_context *ctx,
4376af69d88dSmrg                             struct gl_transform_feedback_object *tfObj,
4377af69d88dSmrg                             GLuint first, GLsizei count, const char *caller)
4378af69d88dSmrg{
4379af69d88dSmrg   if (!ctx->Extensions.EXT_transform_feedback) {
4380af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
4381af69d88dSmrg                  "%s(target=GL_TRANSFORM_FEEDBACK_BUFFER)", caller);
4382af69d88dSmrg      return false;
4383af69d88dSmrg   }
4384af69d88dSmrg
4385af69d88dSmrg   /* Page 398 of the PDF of the OpenGL 4.4 (Core Profile) spec says:
4386af69d88dSmrg    *
4387af69d88dSmrg    *     "An INVALID_OPERATION error is generated :
4388af69d88dSmrg    *
4389af69d88dSmrg    *     ...
4390af69d88dSmrg    *     • by BindBufferRange or BindBufferBase if target is TRANSFORM_-
439101e04c3fSmrg    *       FEEDBACK_BUFFER and transform feedback is currently active."
439201e04c3fSmrg    *
439301e04c3fSmrg    * We assume that this is also meant to apply to BindBuffersRange
439401e04c3fSmrg    * and BindBuffersBase.
4395af69d88dSmrg    */
439601e04c3fSmrg   if (tfObj->Active) {
439701e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
439801e04c3fSmrg                  "%s(Changing transform feedback buffers while "
439901e04c3fSmrg                  "transform feedback is active)", caller);
440001e04c3fSmrg      return false;
440101e04c3fSmrg   }
4402af69d88dSmrg
440301e04c3fSmrg   /* The ARB_multi_bind_spec says:
440401e04c3fSmrg    *
440501e04c3fSmrg    *     "An INVALID_OPERATION error is generated if <first> + <count> is
440601e04c3fSmrg    *      greater than the number of target-specific indexed binding points,
440701e04c3fSmrg    *      as described in section 6.7.1."
440801e04c3fSmrg    */
440901e04c3fSmrg   if (first + count > ctx->Const.MaxTransformFeedbackBuffers) {
441001e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
441101e04c3fSmrg                  "%s(first=%u + count=%d > the value of "
441201e04c3fSmrg                  "GL_MAX_TRANSFORM_FEEDBACK_BUFFERS=%u)",
441301e04c3fSmrg                  caller, first, count,
441401e04c3fSmrg                  ctx->Const.MaxTransformFeedbackBuffers);
441501e04c3fSmrg      return false;
441601e04c3fSmrg   }
4417af69d88dSmrg
441801e04c3fSmrg   return true;
441901e04c3fSmrg}
4420af69d88dSmrg
442101e04c3fSmrg/**
442201e04c3fSmrg * Unbind all transform feedback buffers in the range
442301e04c3fSmrg * <first> through <first>+<count>-1
442401e04c3fSmrg */
442501e04c3fSmrgstatic void
442601e04c3fSmrgunbind_xfb_buffers(struct gl_context *ctx,
442701e04c3fSmrg                   struct gl_transform_feedback_object *tfObj,
442801e04c3fSmrg                   GLuint first, GLsizei count)
442901e04c3fSmrg{
443001e04c3fSmrg   for (int i = 0; i < count; i++)
443101e04c3fSmrg      _mesa_set_transform_feedback_binding(ctx, tfObj, first + i,
44327ec681f3Smrg                                           NULL, 0, 0);
4433af69d88dSmrg}
4434af69d88dSmrg
4435af69d88dSmrgstatic void
443601e04c3fSmrgbind_xfb_buffers(struct gl_context *ctx,
443701e04c3fSmrg                 GLuint first, GLsizei count,
443801e04c3fSmrg                 const GLuint *buffers,
443901e04c3fSmrg                 bool range,
444001e04c3fSmrg                 const GLintptr *offsets,
444101e04c3fSmrg                 const GLsizeiptr *sizes,
444201e04c3fSmrg                 const char *caller)
4443af69d88dSmrg{
4444af69d88dSmrg   struct gl_transform_feedback_object *tfObj =
4445af69d88dSmrg       ctx->TransformFeedback.CurrentObject;
4446af69d88dSmrg
444701e04c3fSmrg   if (!error_check_bind_xfb_buffers(ctx, tfObj, first, count, caller))
4448af69d88dSmrg      return;
4449af69d88dSmrg
4450af69d88dSmrg   /* Assume that at least one binding will be changed */
44517ec681f3Smrg   FLUSH_VERTICES(ctx, 0, 0);
4452af69d88dSmrg   ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
4453af69d88dSmrg
4454af69d88dSmrg   if (!buffers) {
4455af69d88dSmrg      /* The ARB_multi_bind spec says:
4456af69d88dSmrg       *
4457af69d88dSmrg       *    "If <buffers> is NULL, all bindings from <first> through
4458af69d88dSmrg       *     <first>+<count>-1 are reset to their unbound (zero) state.
4459af69d88dSmrg       *     In this case, the offsets and sizes associated with the
4460af69d88dSmrg       *     binding points are set to default values, ignoring
4461af69d88dSmrg       *     <offsets> and <sizes>."
4462af69d88dSmrg       */
4463af69d88dSmrg      unbind_xfb_buffers(ctx, tfObj, first, count);
4464af69d88dSmrg      return;
4465af69d88dSmrg   }
4466af69d88dSmrg
4467af69d88dSmrg   /* Note that the error semantics for multi-bind commands differ from
4468af69d88dSmrg    * those of other GL commands.
4469af69d88dSmrg    *
4470af69d88dSmrg    * The Issues section in the ARB_multi_bind spec says:
4471af69d88dSmrg    *
4472af69d88dSmrg    *    "(11) Typically, OpenGL specifies that if an error is generated by a
4473af69d88dSmrg    *          command, that command has no effect.  This is somewhat
4474af69d88dSmrg    *          unfortunate for multi-bind commands, because it would require a
4475af69d88dSmrg    *          first pass to scan the entire list of bound objects for errors
4476af69d88dSmrg    *          and then a second pass to actually perform the bindings.
4477af69d88dSmrg    *          Should we have different error semantics?
4478af69d88dSmrg    *
4479af69d88dSmrg    *       RESOLVED:  Yes.  In this specification, when the parameters for
4480af69d88dSmrg    *       one of the <count> binding points are invalid, that binding point
4481af69d88dSmrg    *       is not updated and an error will be generated.  However, other
4482af69d88dSmrg    *       binding points in the same command will be updated if their
4483af69d88dSmrg    *       parameters are valid and no other error occurs."
4484af69d88dSmrg    */
4485af69d88dSmrg
44867ec681f3Smrg   _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects,
44877ec681f3Smrg                             ctx->BufferObjectsLocked);
4488af69d88dSmrg
448901e04c3fSmrg   for (int i = 0; i < count; i++) {
4490af69d88dSmrg      const GLuint index = first + i;
4491af69d88dSmrg      struct gl_buffer_object * const boundBufObj = tfObj->Buffers[index];
4492af69d88dSmrg      struct gl_buffer_object *bufObj;
449301e04c3fSmrg      GLintptr offset = 0;
449401e04c3fSmrg      GLsizeiptr size = 0;
4495af69d88dSmrg
449601e04c3fSmrg      if (range) {
449701e04c3fSmrg         if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
449801e04c3fSmrg            continue;
4499af69d88dSmrg
450001e04c3fSmrg         /* The ARB_multi_bind spec says:
450101e04c3fSmrg          *
450201e04c3fSmrg          *     "An INVALID_VALUE error is generated by BindBuffersRange if any
450301e04c3fSmrg          *      pair of values in <offsets> and <sizes> does not respectively
450401e04c3fSmrg          *      satisfy the constraints described for those parameters for the
450501e04c3fSmrg          *      specified target, as described in section 6.7.1 (per binding)."
450601e04c3fSmrg          *
450701e04c3fSmrg          * Section 6.7.1 refers to table 6.5, which says:
450801e04c3fSmrg          *
450901e04c3fSmrg          *     "┌───────────────────────────────────────────────────────────────┐
451001e04c3fSmrg          *      │ Transform feedback array bindings (see sec. 13.2.2)           │
451101e04c3fSmrg          *      ├───────────────────────┬───────────────────────────────────────┤
451201e04c3fSmrg          *      │    ...                │    ...                                │
451301e04c3fSmrg          *      │    offset restriction │    multiple of 4                      │
451401e04c3fSmrg          *      │    ...                │    ...                                │
451501e04c3fSmrg          *      │    size restriction   │    multiple of 4                      │
451601e04c3fSmrg          *      └───────────────────────┴───────────────────────────────────────┘"
451701e04c3fSmrg          */
451801e04c3fSmrg         if (offsets[i] & 0x3) {
451901e04c3fSmrg            _mesa_error(ctx, GL_INVALID_VALUE,
452001e04c3fSmrg                        "glBindBuffersRange(offsets[%u]=%" PRId64
452101e04c3fSmrg                        " is misaligned; it must be a multiple of 4 when "
452201e04c3fSmrg                        "target=GL_TRANSFORM_FEEDBACK_BUFFER)",
452301e04c3fSmrg                        i, (int64_t) offsets[i]);
452401e04c3fSmrg            continue;
452501e04c3fSmrg         }
4526af69d88dSmrg
452701e04c3fSmrg         if (sizes[i] & 0x3) {
452801e04c3fSmrg            _mesa_error(ctx, GL_INVALID_VALUE,
452901e04c3fSmrg                        "glBindBuffersRange(sizes[%u]=%" PRId64
453001e04c3fSmrg                        " is misaligned; it must be a multiple of 4 when "
453101e04c3fSmrg                        "target=GL_TRANSFORM_FEEDBACK_BUFFER)",
453201e04c3fSmrg                        i, (int64_t) sizes[i]);
453301e04c3fSmrg            continue;
453401e04c3fSmrg         }
453501e04c3fSmrg
453601e04c3fSmrg         offset = offsets[i];
453701e04c3fSmrg         size = sizes[i];
4538af69d88dSmrg      }
4539af69d88dSmrg
4540af69d88dSmrg      if (boundBufObj && boundBufObj->Name == buffers[i])
4541af69d88dSmrg         bufObj = boundBufObj;
45427ec681f3Smrg      else {
45437ec681f3Smrg         bool error;
45447ec681f3Smrg         bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, caller,
45457ec681f3Smrg                                                    &error);
45467ec681f3Smrg         if (error)
45477ec681f3Smrg            continue;
45487ec681f3Smrg      }
4549af69d88dSmrg
45507ec681f3Smrg      _mesa_set_transform_feedback_binding(ctx, tfObj, index, bufObj,
45517ec681f3Smrg                                           offset, size);
4552af69d88dSmrg   }
4553af69d88dSmrg
45547ec681f3Smrg   _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects,
45557ec681f3Smrg                               ctx->BufferObjectsLocked);
4556af69d88dSmrg}
4557af69d88dSmrg
4558af69d88dSmrgstatic bool
4559af69d88dSmrgerror_check_bind_atomic_buffers(struct gl_context *ctx,
4560af69d88dSmrg                                GLuint first, GLsizei count,
4561af69d88dSmrg                                const char *caller)
4562af69d88dSmrg{
4563af69d88dSmrg   if (!ctx->Extensions.ARB_shader_atomic_counters) {
4564af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM,
4565af69d88dSmrg                  "%s(target=GL_ATOMIC_COUNTER_BUFFER)", caller);
4566af69d88dSmrg      return false;
4567af69d88dSmrg   }
4568af69d88dSmrg
4569af69d88dSmrg   /* The ARB_multi_bind_spec says:
4570af69d88dSmrg    *
4571af69d88dSmrg    *     "An INVALID_OPERATION error is generated if <first> + <count> is
4572af69d88dSmrg    *      greater than the number of target-specific indexed binding points,
4573af69d88dSmrg    *      as described in section 6.7.1."
4574af69d88dSmrg    */
4575af69d88dSmrg   if (first + count > ctx->Const.MaxAtomicBufferBindings) {
4576af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
4577af69d88dSmrg                  "%s(first=%u + count=%d > the value of "
4578af69d88dSmrg                  "GL_MAX_ATOMIC_BUFFER_BINDINGS=%u)",
4579af69d88dSmrg                  caller, first, count, ctx->Const.MaxAtomicBufferBindings);
4580af69d88dSmrg      return false;
4581af69d88dSmrg   }
4582af69d88dSmrg
4583af69d88dSmrg   return true;
4584af69d88dSmrg}
4585af69d88dSmrg
4586af69d88dSmrg/**
4587af69d88dSmrg * Unbind all atomic counter buffers in the range
4588af69d88dSmrg * <first> through <first>+<count>-1
4589af69d88dSmrg */
4590af69d88dSmrgstatic void
4591af69d88dSmrgunbind_atomic_buffers(struct gl_context *ctx, GLuint first, GLsizei count)
4592af69d88dSmrg{
459301e04c3fSmrg   for (int i = 0; i < count; i++)
459401e04c3fSmrg      set_buffer_binding(ctx, &ctx->AtomicBufferBindings[first + i],
45957ec681f3Smrg                         NULL, -1, -1, GL_TRUE, 0);
4596af69d88dSmrg}
4597af69d88dSmrg
4598af69d88dSmrgstatic void
459901e04c3fSmrgbind_atomic_buffers(struct gl_context *ctx,
460001e04c3fSmrg                    GLuint first,
460101e04c3fSmrg                    GLsizei count,
460201e04c3fSmrg                    const GLuint *buffers,
460301e04c3fSmrg                    bool range,
460401e04c3fSmrg                    const GLintptr *offsets,
460501e04c3fSmrg                    const GLsizeiptr *sizes,
460601e04c3fSmrg                    const char *caller)
4607af69d88dSmrg{
460801e04c3fSmrg   if (!error_check_bind_atomic_buffers(ctx, first, count, caller))
4609af69d88dSmrg     return;
4610af69d88dSmrg
4611af69d88dSmrg   /* Assume that at least one binding will be changed */
46127ec681f3Smrg   FLUSH_VERTICES(ctx, 0, 0);
4613af69d88dSmrg   ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer;
4614af69d88dSmrg
4615af69d88dSmrg   if (!buffers) {
4616af69d88dSmrg      /* The ARB_multi_bind spec says:
4617af69d88dSmrg       *
4618af69d88dSmrg       *    "If <buffers> is NULL, all bindings from <first> through
4619af69d88dSmrg       *     <first>+<count>-1 are reset to their unbound (zero) state.
4620af69d88dSmrg       *     In this case, the offsets and sizes associated with the
4621af69d88dSmrg       *     binding points are set to default values, ignoring
4622af69d88dSmrg       *     <offsets> and <sizes>."
4623af69d88dSmrg       */
4624af69d88dSmrg      unbind_atomic_buffers(ctx, first, count);
4625af69d88dSmrg      return;
4626af69d88dSmrg   }
4627af69d88dSmrg
4628af69d88dSmrg   /* Note that the error semantics for multi-bind commands differ from
4629af69d88dSmrg    * those of other GL commands.
4630af69d88dSmrg    *
4631af69d88dSmrg    * The Issues section in the ARB_multi_bind spec says:
4632af69d88dSmrg    *
4633af69d88dSmrg    *    "(11) Typically, OpenGL specifies that if an error is generated by a
4634af69d88dSmrg    *          command, that command has no effect.  This is somewhat
4635af69d88dSmrg    *          unfortunate for multi-bind commands, because it would require a
4636af69d88dSmrg    *          first pass to scan the entire list of bound objects for errors
4637af69d88dSmrg    *          and then a second pass to actually perform the bindings.
4638af69d88dSmrg    *          Should we have different error semantics?
4639af69d88dSmrg    *
4640af69d88dSmrg    *       RESOLVED:  Yes.  In this specification, when the parameters for
4641af69d88dSmrg    *       one of the <count> binding points are invalid, that binding point
4642af69d88dSmrg    *       is not updated and an error will be generated.  However, other
4643af69d88dSmrg    *       binding points in the same command will be updated if their
4644af69d88dSmrg    *       parameters are valid and no other error occurs."
4645af69d88dSmrg    */
4646af69d88dSmrg
46477ec681f3Smrg   _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects,
46487ec681f3Smrg                             ctx->BufferObjectsLocked);
4649af69d88dSmrg
465001e04c3fSmrg   for (int i = 0; i < count; i++) {
465101e04c3fSmrg      struct gl_buffer_binding *binding =
4652af69d88dSmrg         &ctx->AtomicBufferBindings[first + i];
465301e04c3fSmrg      GLintptr offset = 0;
465401e04c3fSmrg      GLsizeiptr size = 0;
4655af69d88dSmrg
465601e04c3fSmrg      if (range) {
465701e04c3fSmrg         if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
465801e04c3fSmrg            continue;
4659af69d88dSmrg
466001e04c3fSmrg         /* The ARB_multi_bind spec says:
466101e04c3fSmrg          *
466201e04c3fSmrg          *     "An INVALID_VALUE error is generated by BindBuffersRange if any
466301e04c3fSmrg          *      pair of values in <offsets> and <sizes> does not respectively
466401e04c3fSmrg          *      satisfy the constraints described for those parameters for the
466501e04c3fSmrg          *      specified target, as described in section 6.7.1 (per binding)."
466601e04c3fSmrg          *
466701e04c3fSmrg          * Section 6.7.1 refers to table 6.5, which says:
466801e04c3fSmrg          *
466901e04c3fSmrg          *     "┌───────────────────────────────────────────────────────────────┐
467001e04c3fSmrg          *      │ Atomic counter array bindings (see sec. 7.7.2)                │
467101e04c3fSmrg          *      ├───────────────────────┬───────────────────────────────────────┤
467201e04c3fSmrg          *      │    ...                │    ...                                │
467301e04c3fSmrg          *      │    offset restriction │    multiple of 4                      │
467401e04c3fSmrg          *      │    ...                │    ...                                │
467501e04c3fSmrg          *      │    size restriction   │    none                               │
467601e04c3fSmrg          *      └───────────────────────┴───────────────────────────────────────┘"
467701e04c3fSmrg          */
467801e04c3fSmrg         if (offsets[i] & (ATOMIC_COUNTER_SIZE - 1)) {
467901e04c3fSmrg            _mesa_error(ctx, GL_INVALID_VALUE,
468001e04c3fSmrg                        "glBindBuffersRange(offsets[%u]=%" PRId64
468101e04c3fSmrg                        " is misaligned; it must be a multiple of %d when "
468201e04c3fSmrg                        "target=GL_ATOMIC_COUNTER_BUFFER)",
468301e04c3fSmrg                        i, (int64_t) offsets[i], ATOMIC_COUNTER_SIZE);
468401e04c3fSmrg            continue;
468501e04c3fSmrg         }
4686af69d88dSmrg
468701e04c3fSmrg         offset = offsets[i];
468801e04c3fSmrg         size = sizes[i];
468901e04c3fSmrg      }
4690af69d88dSmrg
469101e04c3fSmrg      set_buffer_multi_binding(ctx, buffers, i, caller,
469201e04c3fSmrg                               binding, offset, size, range,
469301e04c3fSmrg                               USAGE_ATOMIC_COUNTER_BUFFER);
4694af69d88dSmrg   }
4695af69d88dSmrg
46967ec681f3Smrg   _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects,
46977ec681f3Smrg                               ctx->BufferObjectsLocked);
4698af69d88dSmrg}
4699af69d88dSmrg
470001e04c3fSmrgstatic ALWAYS_INLINE void
470101e04c3fSmrgbind_buffer_range(GLenum target, GLuint index, GLuint buffer, GLintptr offset,
470201e04c3fSmrg                  GLsizeiptr size, bool no_error)
4703af69d88dSmrg{
4704af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
4705af69d88dSmrg   struct gl_buffer_object *bufObj;
4706af69d88dSmrg
470701e04c3fSmrg   if (MESA_VERBOSE & VERBOSE_API) {
470801e04c3fSmrg      _mesa_debug(ctx, "glBindBufferRange(%s, %u, %u, %lu, %lu)\n",
470901e04c3fSmrg                  _mesa_enum_to_string(target), index, buffer,
471001e04c3fSmrg                  (unsigned long) offset, (unsigned long) size);
471101e04c3fSmrg   }
471201e04c3fSmrg
4713af69d88dSmrg   if (buffer == 0) {
47147ec681f3Smrg      bufObj = NULL;
4715af69d88dSmrg   } else {
4716af69d88dSmrg      bufObj = _mesa_lookup_bufferobj(ctx, buffer);
471701e04c3fSmrg      if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
471801e04c3fSmrg                                        &bufObj, "glBindBufferRange"))
471901e04c3fSmrg         return;
4720af69d88dSmrg
472101e04c3fSmrg      if (!no_error && !bufObj) {
472201e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
472301e04c3fSmrg                     "glBindBufferRange(invalid buffer=%u)", buffer);
472401e04c3fSmrg         return;
472501e04c3fSmrg      }
4726af69d88dSmrg   }
4727af69d88dSmrg
472801e04c3fSmrg   if (no_error) {
472901e04c3fSmrg      switch (target) {
473001e04c3fSmrg      case GL_TRANSFORM_FEEDBACK_BUFFER:
473101e04c3fSmrg         _mesa_bind_buffer_range_xfb(ctx, ctx->TransformFeedback.CurrentObject,
473201e04c3fSmrg                                     index, bufObj, offset, size);
4733af69d88dSmrg         return;
473401e04c3fSmrg      case GL_UNIFORM_BUFFER:
473501e04c3fSmrg         bind_buffer_range_uniform_buffer(ctx, index, bufObj, offset, size);
473601e04c3fSmrg         return;
473701e04c3fSmrg      case GL_SHADER_STORAGE_BUFFER:
473801e04c3fSmrg         bind_buffer_range_shader_storage_buffer(ctx, index, bufObj, offset,
473901e04c3fSmrg                                                 size);
474001e04c3fSmrg         return;
474101e04c3fSmrg      case GL_ATOMIC_COUNTER_BUFFER:
474201e04c3fSmrg         bind_buffer_range_atomic_buffer(ctx, index, bufObj, offset, size);
474301e04c3fSmrg         return;
474401e04c3fSmrg      default:
474501e04c3fSmrg         unreachable("invalid BindBufferRange target with KHR_no_error");
474601e04c3fSmrg      }
474701e04c3fSmrg   } else {
474801e04c3fSmrg      if (buffer != 0) {
474901e04c3fSmrg         if (size <= 0) {
475001e04c3fSmrg            _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(size=%d)",
475101e04c3fSmrg                        (int) size);
475201e04c3fSmrg            return;
475301e04c3fSmrg         }
4754af69d88dSmrg      }
4755af69d88dSmrg
475601e04c3fSmrg      switch (target) {
475701e04c3fSmrg      case GL_TRANSFORM_FEEDBACK_BUFFER:
475801e04c3fSmrg         if (!_mesa_validate_buffer_range_xfb(ctx,
475901e04c3fSmrg                                              ctx->TransformFeedback.CurrentObject,
476001e04c3fSmrg                                              index, bufObj, offset, size,
476101e04c3fSmrg                                              false))
476201e04c3fSmrg            return;
476301e04c3fSmrg
476401e04c3fSmrg         _mesa_bind_buffer_range_xfb(ctx, ctx->TransformFeedback.CurrentObject,
476501e04c3fSmrg                                     index, bufObj, offset, size);
476601e04c3fSmrg         return;
476701e04c3fSmrg      case GL_UNIFORM_BUFFER:
476801e04c3fSmrg         bind_buffer_range_uniform_buffer_err(ctx, index, bufObj, offset,
476901e04c3fSmrg                                              size);
477001e04c3fSmrg         return;
477101e04c3fSmrg      case GL_SHADER_STORAGE_BUFFER:
477201e04c3fSmrg         bind_buffer_range_shader_storage_buffer_err(ctx, index, bufObj,
477301e04c3fSmrg                                                     offset, size);
477401e04c3fSmrg         return;
477501e04c3fSmrg      case GL_ATOMIC_COUNTER_BUFFER:
477601e04c3fSmrg         bind_buffer_range_atomic_buffer_err(ctx, index, bufObj,
477701e04c3fSmrg                                             offset, size);
477801e04c3fSmrg         return;
477901e04c3fSmrg      default:
478001e04c3fSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferRange(target)");
478101e04c3fSmrg         return;
478201e04c3fSmrg      }
4783af69d88dSmrg   }
4784af69d88dSmrg}
4785af69d88dSmrg
478601e04c3fSmrgvoid GLAPIENTRY
478701e04c3fSmrg_mesa_BindBufferRange_no_error(GLenum target, GLuint index, GLuint buffer,
478801e04c3fSmrg                               GLintptr offset, GLsizeiptr size)
478901e04c3fSmrg{
479001e04c3fSmrg   bind_buffer_range(target, index, buffer, offset, size, true);
479101e04c3fSmrg}
479201e04c3fSmrg
479301e04c3fSmrgvoid GLAPIENTRY
479401e04c3fSmrg_mesa_BindBufferRange(GLenum target, GLuint index,
479501e04c3fSmrg                      GLuint buffer, GLintptr offset, GLsizeiptr size)
479601e04c3fSmrg{
479701e04c3fSmrg   bind_buffer_range(target, index, buffer, offset, size, false);
479801e04c3fSmrg}
479901e04c3fSmrg
4800af69d88dSmrgvoid GLAPIENTRY
4801af69d88dSmrg_mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer)
4802af69d88dSmrg{
4803af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
4804af69d88dSmrg   struct gl_buffer_object *bufObj;
4805af69d88dSmrg
480601e04c3fSmrg   if (MESA_VERBOSE & VERBOSE_API) {
480701e04c3fSmrg      _mesa_debug(ctx, "glBindBufferBase(%s, %u, %u)\n",
480801e04c3fSmrg                  _mesa_enum_to_string(target), index, buffer);
480901e04c3fSmrg   }
481001e04c3fSmrg
4811af69d88dSmrg   if (buffer == 0) {
48127ec681f3Smrg      bufObj = NULL;
4813af69d88dSmrg   } else {
4814af69d88dSmrg      bufObj = _mesa_lookup_bufferobj(ctx, buffer);
481501e04c3fSmrg      if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
481601e04c3fSmrg                                        &bufObj, "glBindBufferBase"))
481701e04c3fSmrg         return;
4818af69d88dSmrg
481901e04c3fSmrg      if (!bufObj) {
482001e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
482101e04c3fSmrg                     "glBindBufferBase(invalid buffer=%u)", buffer);
482201e04c3fSmrg         return;
482301e04c3fSmrg      }
4824af69d88dSmrg   }
4825af69d88dSmrg
4826af69d88dSmrg   /* Note that there's some oddness in the GL 3.1-GL 3.3 specifications with
4827af69d88dSmrg    * regards to BindBufferBase.  It says (GL 3.1 core spec, page 63):
4828af69d88dSmrg    *
4829af69d88dSmrg    *     "BindBufferBase is equivalent to calling BindBufferRange with offset
4830af69d88dSmrg    *      zero and size equal to the size of buffer."
4831af69d88dSmrg    *
4832af69d88dSmrg    * but it says for glGetIntegeri_v (GL 3.1 core spec, page 230):
4833af69d88dSmrg    *
4834af69d88dSmrg    *     "If the parameter (starting offset or size) was not specified when the
4835af69d88dSmrg    *      buffer object was bound, zero is returned."
4836af69d88dSmrg    *
4837af69d88dSmrg    * What happens if the size of the buffer changes?  Does the size of the
4838af69d88dSmrg    * buffer at the moment glBindBufferBase was called still play a role, like
4839af69d88dSmrg    * the first quote would imply, or is the size meaningless in the
4840af69d88dSmrg    * glBindBufferBase case like the second quote would suggest?  The GL 4.1
4841af69d88dSmrg    * core spec page 45 says:
4842af69d88dSmrg    *
4843af69d88dSmrg    *     "It is equivalent to calling BindBufferRange with offset zero, while
4844af69d88dSmrg    *      size is determined by the size of the bound buffer at the time the
4845af69d88dSmrg    *      binding is used."
4846af69d88dSmrg    *
4847af69d88dSmrg    * My interpretation is that the GL 4.1 spec was a clarification of the
4848af69d88dSmrg    * behavior, not a change.  In particular, this choice will only make
4849af69d88dSmrg    * rendering work in cases where it would have had undefined results.
4850af69d88dSmrg    */
4851af69d88dSmrg
4852af69d88dSmrg   switch (target) {
4853af69d88dSmrg   case GL_TRANSFORM_FEEDBACK_BUFFER:
485401e04c3fSmrg      _mesa_bind_buffer_base_transform_feedback(ctx,
485501e04c3fSmrg                                                ctx->TransformFeedback.CurrentObject,
485601e04c3fSmrg                                                index, bufObj, false);
4857af69d88dSmrg      return;
4858af69d88dSmrg   case GL_UNIFORM_BUFFER:
4859af69d88dSmrg      bind_buffer_base_uniform_buffer(ctx, index, bufObj);
4860af69d88dSmrg      return;
486101e04c3fSmrg   case GL_SHADER_STORAGE_BUFFER:
486201e04c3fSmrg      bind_buffer_base_shader_storage_buffer(ctx, index, bufObj);
486301e04c3fSmrg      return;
4864af69d88dSmrg   case GL_ATOMIC_COUNTER_BUFFER:
486501e04c3fSmrg      bind_buffer_base_atomic_buffer(ctx, index, bufObj);
4866af69d88dSmrg      return;
4867af69d88dSmrg   default:
4868af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)");
4869af69d88dSmrg      return;
4870af69d88dSmrg   }
4871af69d88dSmrg}
4872af69d88dSmrg
4873af69d88dSmrgvoid GLAPIENTRY
4874af69d88dSmrg_mesa_BindBuffersRange(GLenum target, GLuint first, GLsizei count,
4875af69d88dSmrg                       const GLuint *buffers,
4876af69d88dSmrg                       const GLintptr *offsets, const GLsizeiptr *sizes)
4877af69d88dSmrg{
4878af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
4879af69d88dSmrg
488001e04c3fSmrg   if (MESA_VERBOSE & VERBOSE_API) {
488101e04c3fSmrg      _mesa_debug(ctx, "glBindBuffersRange(%s, %u, %d, %p, %p, %p)\n",
488201e04c3fSmrg                  _mesa_enum_to_string(target), first, count,
488301e04c3fSmrg                  buffers, offsets, sizes);
488401e04c3fSmrg   }
488501e04c3fSmrg
4886af69d88dSmrg   switch (target) {
4887af69d88dSmrg   case GL_TRANSFORM_FEEDBACK_BUFFER:
488801e04c3fSmrg      bind_xfb_buffers(ctx, first, count, buffers, true, offsets, sizes,
488901e04c3fSmrg                       "glBindBuffersRange");
4890af69d88dSmrg      return;
4891af69d88dSmrg   case GL_UNIFORM_BUFFER:
489201e04c3fSmrg      bind_uniform_buffers(ctx, first, count, buffers, true, offsets, sizes,
489301e04c3fSmrg                           "glBindBuffersRange");
489401e04c3fSmrg      return;
489501e04c3fSmrg   case GL_SHADER_STORAGE_BUFFER:
489601e04c3fSmrg      bind_shader_storage_buffers(ctx, first, count, buffers, true, offsets, sizes,
489701e04c3fSmrg                                  "glBindBuffersRange");
4898af69d88dSmrg      return;
4899af69d88dSmrg   case GL_ATOMIC_COUNTER_BUFFER:
490001e04c3fSmrg      bind_atomic_buffers(ctx, first, count, buffers, true, offsets, sizes,
490101e04c3fSmrg                          "glBindBuffersRange");
4902af69d88dSmrg      return;
4903af69d88dSmrg   default:
4904af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBindBuffersRange(target=%s)",
490501e04c3fSmrg                  _mesa_enum_to_string(target));
4906af69d88dSmrg      break;
4907af69d88dSmrg   }
4908af69d88dSmrg}
4909af69d88dSmrg
4910af69d88dSmrgvoid GLAPIENTRY
4911af69d88dSmrg_mesa_BindBuffersBase(GLenum target, GLuint first, GLsizei count,
4912af69d88dSmrg                      const GLuint *buffers)
4913af69d88dSmrg{
4914af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
4915af69d88dSmrg
491601e04c3fSmrg   if (MESA_VERBOSE & VERBOSE_API) {
491701e04c3fSmrg      _mesa_debug(ctx, "glBindBuffersBase(%s, %u, %d, %p)\n",
491801e04c3fSmrg                  _mesa_enum_to_string(target), first, count, buffers);
491901e04c3fSmrg   }
492001e04c3fSmrg
4921af69d88dSmrg   switch (target) {
4922af69d88dSmrg   case GL_TRANSFORM_FEEDBACK_BUFFER:
492301e04c3fSmrg      bind_xfb_buffers(ctx, first, count, buffers, false, NULL, NULL,
492401e04c3fSmrg                       "glBindBuffersBase");
4925af69d88dSmrg      return;
4926af69d88dSmrg   case GL_UNIFORM_BUFFER:
492701e04c3fSmrg      bind_uniform_buffers(ctx, first, count, buffers, false, NULL, NULL,
492801e04c3fSmrg                           "glBindBuffersBase");
492901e04c3fSmrg      return;
493001e04c3fSmrg   case GL_SHADER_STORAGE_BUFFER:
493101e04c3fSmrg      bind_shader_storage_buffers(ctx, first, count, buffers, false, NULL, NULL,
493201e04c3fSmrg                                  "glBindBuffersBase");
4933af69d88dSmrg      return;
4934af69d88dSmrg   case GL_ATOMIC_COUNTER_BUFFER:
493501e04c3fSmrg      bind_atomic_buffers(ctx, first, count, buffers, false, NULL, NULL,
493601e04c3fSmrg                          "glBindBuffersBase");
4937af69d88dSmrg      return;
4938af69d88dSmrg   default:
4939af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBindBuffersBase(target=%s)",
494001e04c3fSmrg                  _mesa_enum_to_string(target));
4941af69d88dSmrg      break;
4942af69d88dSmrg   }
4943af69d88dSmrg}
4944af69d88dSmrg
494501e04c3fSmrgstatic ALWAYS_INLINE void
494601e04c3fSmrginvalidate_buffer_subdata(struct gl_context *ctx,
494701e04c3fSmrg                          struct gl_buffer_object *bufObj, GLintptr offset,
494801e04c3fSmrg                          GLsizeiptr length)
494901e04c3fSmrg{
495001e04c3fSmrg   if (ctx->Driver.InvalidateBufferSubData)
495101e04c3fSmrg      ctx->Driver.InvalidateBufferSubData(ctx, bufObj, offset, length);
495201e04c3fSmrg}
495301e04c3fSmrg
495401e04c3fSmrgvoid GLAPIENTRY
495501e04c3fSmrg_mesa_InvalidateBufferSubData_no_error(GLuint buffer, GLintptr offset,
495601e04c3fSmrg                                       GLsizeiptr length)
495701e04c3fSmrg{
495801e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
495901e04c3fSmrg
496001e04c3fSmrg   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
496101e04c3fSmrg   invalidate_buffer_subdata(ctx, bufObj, offset, length);
496201e04c3fSmrg}
496301e04c3fSmrg
4964af69d88dSmrgvoid GLAPIENTRY
4965af69d88dSmrg_mesa_InvalidateBufferSubData(GLuint buffer, GLintptr offset,
4966af69d88dSmrg                              GLsizeiptr length)
4967af69d88dSmrg{
4968af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
4969af69d88dSmrg   struct gl_buffer_object *bufObj;
4970af69d88dSmrg   const GLintptr end = offset + length;
4971af69d88dSmrg
497201e04c3fSmrg   /* Section 6.5 (Invalidating Buffer Data) of the OpenGL 4.5 (Compatibility
497301e04c3fSmrg    * Profile) spec says:
497401e04c3fSmrg    *
497501e04c3fSmrg    *     "An INVALID_VALUE error is generated if buffer is zero or is not the
497601e04c3fSmrg    *     name of an existing buffer object."
497701e04c3fSmrg    */
4978af69d88dSmrg   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
497901e04c3fSmrg   if (!bufObj || bufObj == &DummyBufferObject) {
4980af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
498101e04c3fSmrg                  "glInvalidateBufferSubData(name = %u) invalid object",
4982af69d88dSmrg                  buffer);
4983af69d88dSmrg      return;
4984af69d88dSmrg   }
4985af69d88dSmrg
4986af69d88dSmrg   /* The GL_ARB_invalidate_subdata spec says:
4987af69d88dSmrg    *
4988af69d88dSmrg    *     "An INVALID_VALUE error is generated if <offset> or <length> is
4989af69d88dSmrg    *     negative, or if <offset> + <length> is greater than the value of
4990af69d88dSmrg    *     BUFFER_SIZE."
4991af69d88dSmrg    */
499201e04c3fSmrg   if (offset < 0 || length < 0 || end > bufObj->Size) {
4993af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
4994af69d88dSmrg                  "glInvalidateBufferSubData(invalid offset or length)");
4995af69d88dSmrg      return;
4996af69d88dSmrg   }
4997af69d88dSmrg
4998af69d88dSmrg   /* The OpenGL 4.4 (Core Profile) spec says:
4999af69d88dSmrg    *
5000af69d88dSmrg    *     "An INVALID_OPERATION error is generated if buffer is currently
5001af69d88dSmrg    *     mapped by MapBuffer or if the invalidate range intersects the range
5002af69d88dSmrg    *     currently mapped by MapBufferRange, unless it was mapped
5003af69d88dSmrg    *     with MAP_PERSISTENT_BIT set in the MapBufferRange access flags."
5004af69d88dSmrg    */
5005af69d88dSmrg   if (!(bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_PERSISTENT_BIT) &&
5006af69d88dSmrg       bufferobj_range_mapped(bufObj, offset, length)) {
5007af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
5008af69d88dSmrg                  "glInvalidateBufferSubData(intersection with mapped "
5009af69d88dSmrg                  "range)");
5010af69d88dSmrg      return;
5011af69d88dSmrg   }
5012af69d88dSmrg
501301e04c3fSmrg   invalidate_buffer_subdata(ctx, bufObj, offset, length);
501401e04c3fSmrg}
501501e04c3fSmrg
501601e04c3fSmrgvoid GLAPIENTRY
501701e04c3fSmrg_mesa_InvalidateBufferData_no_error(GLuint buffer)
501801e04c3fSmrg{
501901e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
502001e04c3fSmrg
502101e04c3fSmrg   struct gl_buffer_object *bufObj =_mesa_lookup_bufferobj(ctx, buffer);
502201e04c3fSmrg   invalidate_buffer_subdata(ctx, bufObj, 0, bufObj->Size);
5023af69d88dSmrg}
5024af69d88dSmrg
5025af69d88dSmrgvoid GLAPIENTRY
5026af69d88dSmrg_mesa_InvalidateBufferData(GLuint buffer)
5027af69d88dSmrg{
5028af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
5029af69d88dSmrg   struct gl_buffer_object *bufObj;
5030af69d88dSmrg
503101e04c3fSmrg   /* Section 6.5 (Invalidating Buffer Data) of the OpenGL 4.5 (Compatibility
503201e04c3fSmrg    * Profile) spec says:
503301e04c3fSmrg    *
503401e04c3fSmrg    *     "An INVALID_VALUE error is generated if buffer is zero or is not the
503501e04c3fSmrg    *     name of an existing buffer object."
503601e04c3fSmrg    */
5037af69d88dSmrg   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
503801e04c3fSmrg   if (!bufObj || bufObj == &DummyBufferObject) {
5039af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
504001e04c3fSmrg                  "glInvalidateBufferData(name = %u) invalid object",
5041af69d88dSmrg                  buffer);
5042af69d88dSmrg      return;
5043af69d88dSmrg   }
5044af69d88dSmrg
5045af69d88dSmrg   /* The OpenGL 4.4 (Core Profile) spec says:
5046af69d88dSmrg    *
5047af69d88dSmrg    *     "An INVALID_OPERATION error is generated if buffer is currently
5048af69d88dSmrg    *     mapped by MapBuffer or if the invalidate range intersects the range
5049af69d88dSmrg    *     currently mapped by MapBufferRange, unless it was mapped
5050af69d88dSmrg    *     with MAP_PERSISTENT_BIT set in the MapBufferRange access flags."
5051af69d88dSmrg    */
5052af69d88dSmrg   if (_mesa_check_disallowed_mapping(bufObj)) {
5053af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
5054af69d88dSmrg                  "glInvalidateBufferData(intersection with mapped "
5055af69d88dSmrg                  "range)");
5056af69d88dSmrg      return;
5057af69d88dSmrg   }
5058af69d88dSmrg
505901e04c3fSmrg   invalidate_buffer_subdata(ctx, bufObj, 0, bufObj->Size);
506001e04c3fSmrg}
506101e04c3fSmrg
506201e04c3fSmrgstatic void
506301e04c3fSmrgbuffer_page_commitment(struct gl_context *ctx,
506401e04c3fSmrg                       struct gl_buffer_object *bufferObj,
506501e04c3fSmrg                       GLintptr offset, GLsizeiptr size,
506601e04c3fSmrg                       GLboolean commit, const char *func)
506701e04c3fSmrg{
506801e04c3fSmrg   if (!(bufferObj->StorageFlags & GL_SPARSE_STORAGE_BIT_ARB)) {
506901e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(not a sparse buffer object)",
507001e04c3fSmrg                  func);
507101e04c3fSmrg      return;
507201e04c3fSmrg   }
507301e04c3fSmrg
507401e04c3fSmrg   if (size < 0 || size > bufferObj->Size ||
507501e04c3fSmrg       offset < 0 || offset > bufferObj->Size - size) {
507601e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(out of bounds)",
507701e04c3fSmrg                  func);
507801e04c3fSmrg      return;
507901e04c3fSmrg   }
508001e04c3fSmrg
508101e04c3fSmrg   /* The GL_ARB_sparse_buffer extension specification says:
508201e04c3fSmrg    *
508301e04c3fSmrg    *     "INVALID_VALUE is generated by BufferPageCommitmentARB if <offset> is
508401e04c3fSmrg    *     not an integer multiple of SPARSE_BUFFER_PAGE_SIZE_ARB, or if <size>
508501e04c3fSmrg    *     is not an integer multiple of SPARSE_BUFFER_PAGE_SIZE_ARB and does
508601e04c3fSmrg    *     not extend to the end of the buffer's data store."
5087af69d88dSmrg    */
508801e04c3fSmrg   if (offset % ctx->Const.SparseBufferPageSize != 0) {
508901e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset not aligned to page size)",
509001e04c3fSmrg                  func);
509101e04c3fSmrg      return;
509201e04c3fSmrg   }
509301e04c3fSmrg
509401e04c3fSmrg   if (size % ctx->Const.SparseBufferPageSize != 0 &&
509501e04c3fSmrg       offset + size != bufferObj->Size) {
509601e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(size not aligned to page size)",
509701e04c3fSmrg                  func);
509801e04c3fSmrg      return;
509901e04c3fSmrg   }
510001e04c3fSmrg
510101e04c3fSmrg   ctx->Driver.BufferPageCommitment(ctx, bufferObj, offset, size, commit);
510201e04c3fSmrg}
510301e04c3fSmrg
510401e04c3fSmrgvoid GLAPIENTRY
510501e04c3fSmrg_mesa_BufferPageCommitmentARB(GLenum target, GLintptr offset, GLsizeiptr size,
510601e04c3fSmrg                              GLboolean commit)
510701e04c3fSmrg{
510801e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
510901e04c3fSmrg   struct gl_buffer_object *bufferObj;
511001e04c3fSmrg
511101e04c3fSmrg   bufferObj = get_buffer(ctx, "glBufferPageCommitmentARB", target,
511201e04c3fSmrg                          GL_INVALID_ENUM);
511301e04c3fSmrg   if (!bufferObj)
511401e04c3fSmrg      return;
511501e04c3fSmrg
511601e04c3fSmrg   buffer_page_commitment(ctx, bufferObj, offset, size, commit,
511701e04c3fSmrg                          "glBufferPageCommitmentARB");
511801e04c3fSmrg}
511901e04c3fSmrg
512001e04c3fSmrgvoid GLAPIENTRY
512101e04c3fSmrg_mesa_NamedBufferPageCommitmentARB(GLuint buffer, GLintptr offset,
512201e04c3fSmrg                                   GLsizeiptr size, GLboolean commit)
512301e04c3fSmrg{
512401e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
512501e04c3fSmrg   struct gl_buffer_object *bufferObj;
512601e04c3fSmrg
512701e04c3fSmrg   bufferObj = _mesa_lookup_bufferobj(ctx, buffer);
512801e04c3fSmrg   if (!bufferObj || bufferObj == &DummyBufferObject) {
512901e04c3fSmrg      /* Note: the extension spec is not clear about the excpected error value. */
513001e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE,
513101e04c3fSmrg                  "glNamedBufferPageCommitmentARB(name = %u) invalid object",
513201e04c3fSmrg                  buffer);
513301e04c3fSmrg      return;
513401e04c3fSmrg   }
513501e04c3fSmrg
513601e04c3fSmrg   buffer_page_commitment(ctx, bufferObj, offset, size, commit,
513701e04c3fSmrg                          "glNamedBufferPageCommitmentARB");
5138af69d88dSmrg}
51397ec681f3Smrg
51407ec681f3Smrgvoid GLAPIENTRY
51417ec681f3Smrg_mesa_NamedBufferPageCommitmentEXT(GLuint buffer, GLintptr offset,
51427ec681f3Smrg                                   GLsizeiptr size, GLboolean commit)
51437ec681f3Smrg{
51447ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
51457ec681f3Smrg   struct gl_buffer_object *bufferObj;
51467ec681f3Smrg
51477ec681f3Smrg   /* Use NamedBuffer* functions logic from EXT_direct_state_access */
51487ec681f3Smrg   if (buffer != 0) {
51497ec681f3Smrg      bufferObj = _mesa_lookup_bufferobj(ctx, buffer);
51507ec681f3Smrg      if (!_mesa_handle_bind_buffer_gen(ctx, buffer, &bufferObj,
51517ec681f3Smrg                                        "glNamedBufferPageCommitmentEXT"))
51527ec681f3Smrg         return;
51537ec681f3Smrg   } else {
51547ec681f3Smrg      /* GL_EXT_direct_state_access says about NamedBuffer* functions:
51557ec681f3Smrg       *
51567ec681f3Smrg       *   There is no buffer corresponding to the name zero, these commands
51577ec681f3Smrg       *   generate the INVALID_OPERATION error if the buffer parameter is
51587ec681f3Smrg       *   zero.
51597ec681f3Smrg       */
51607ec681f3Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
51617ec681f3Smrg                  "glNamedBufferPageCommitmentEXT(buffer = 0)");
51627ec681f3Smrg      return;
51637ec681f3Smrg   }
51647ec681f3Smrg   buffer_page_commitment(ctx, bufferObj, offset, size, commit,
51657ec681f3Smrg                          "glNamedBufferPageCommitmentEXT");
51667ec681f3Smrg}
5167