1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Mesa 3-D graphics library
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5bf215546Sopenharmony_ci * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
6bf215546Sopenharmony_ci *
7bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
8bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
9bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
10bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
12bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included
15bf215546Sopenharmony_ci * in all copies or substantial portions of the Software.
16bf215546Sopenharmony_ci *
17bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21bf215546Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23bf215546Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
24bf215546Sopenharmony_ci */
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci/**
28bf215546Sopenharmony_ci * \file bufferobj.c
29bf215546Sopenharmony_ci * \brief Functions for the GL_ARB_vertex/pixel_buffer_object extensions.
30bf215546Sopenharmony_ci * \author Brian Paul, Ian Romanick
31bf215546Sopenharmony_ci */
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci#include <stdbool.h>
34bf215546Sopenharmony_ci#include <inttypes.h>  /* for PRId64 macro */
35bf215546Sopenharmony_ci#include "util/debug.h"
36bf215546Sopenharmony_ci#include "glheader.h"
37bf215546Sopenharmony_ci#include "enums.h"
38bf215546Sopenharmony_ci#include "hash.h"
39bf215546Sopenharmony_ci#include "context.h"
40bf215546Sopenharmony_ci#include "bufferobj.h"
41bf215546Sopenharmony_ci#include "externalobjects.h"
42bf215546Sopenharmony_ci#include "mtypes.h"
43bf215546Sopenharmony_ci#include "teximage.h"
44bf215546Sopenharmony_ci#include "glformats.h"
45bf215546Sopenharmony_ci#include "texstore.h"
46bf215546Sopenharmony_ci#include "transformfeedback.h"
47bf215546Sopenharmony_ci#include "varray.h"
48bf215546Sopenharmony_ci#include "util/u_atomic.h"
49bf215546Sopenharmony_ci#include "util/u_memory.h"
50bf215546Sopenharmony_ci#include "api_exec_decl.h"
51bf215546Sopenharmony_ci#include "util/set.h"
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_ci#include "state_tracker/st_debug.h"
54bf215546Sopenharmony_ci#include "state_tracker/st_atom.h"
55bf215546Sopenharmony_ci#include "frontend/api.h"
56bf215546Sopenharmony_ci
57bf215546Sopenharmony_ci#include "util/u_inlines.h"
58bf215546Sopenharmony_ci/* Debug flags */
59bf215546Sopenharmony_ci/*#define VBO_DEBUG*/
60bf215546Sopenharmony_ci/*#define BOUNDS_CHECK*/
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci
63bf215546Sopenharmony_ci/**
64bf215546Sopenharmony_ci * We count the number of buffer modification calls to check for
65bf215546Sopenharmony_ci * inefficient buffer use.  This is the number of such calls before we
66bf215546Sopenharmony_ci * issue a warning.
67bf215546Sopenharmony_ci */
68bf215546Sopenharmony_ci#define BUFFER_WARNING_CALL_COUNT 4
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci/**
72bf215546Sopenharmony_ci * Replace data in a subrange of buffer object.  If the data range
73bf215546Sopenharmony_ci * specified by size + offset extends beyond the end of the buffer or
74bf215546Sopenharmony_ci * if data is NULL, no copy is performed.
75bf215546Sopenharmony_ci * Called via glBufferSubDataARB().
76bf215546Sopenharmony_ci */
77bf215546Sopenharmony_civoid
78bf215546Sopenharmony_ci_mesa_bufferobj_subdata(struct gl_context *ctx,
79bf215546Sopenharmony_ci                        GLintptrARB offset,
80bf215546Sopenharmony_ci                        GLsizeiptrARB size,
81bf215546Sopenharmony_ci                        const void *data, struct gl_buffer_object *obj)
82bf215546Sopenharmony_ci{
83bf215546Sopenharmony_ci   /* we may be called from VBO code, so double-check params here */
84bf215546Sopenharmony_ci   assert(offset >= 0);
85bf215546Sopenharmony_ci   assert(size >= 0);
86bf215546Sopenharmony_ci   assert(offset + size <= obj->Size);
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_ci   if (!size)
89bf215546Sopenharmony_ci      return;
90bf215546Sopenharmony_ci
91bf215546Sopenharmony_ci   /*
92bf215546Sopenharmony_ci    * According to ARB_vertex_buffer_object specification, if data is null,
93bf215546Sopenharmony_ci    * then the contents of the buffer object's data store is undefined. We just
94bf215546Sopenharmony_ci    * ignore, and leave it unchanged.
95bf215546Sopenharmony_ci    */
96bf215546Sopenharmony_ci   if (!data)
97bf215546Sopenharmony_ci      return;
98bf215546Sopenharmony_ci
99bf215546Sopenharmony_ci   if (!obj->buffer) {
100bf215546Sopenharmony_ci      /* we probably ran out of memory during buffer allocation */
101bf215546Sopenharmony_ci      return;
102bf215546Sopenharmony_ci   }
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci   /* Now that transfers are per-context, we don't have to figure out
105bf215546Sopenharmony_ci    * flushing here.  Usually drivers won't need to flush in this case
106bf215546Sopenharmony_ci    * even if the buffer is currently referenced by hardware - they
107bf215546Sopenharmony_ci    * just queue the upload as dma rather than mapping the underlying
108bf215546Sopenharmony_ci    * buffer directly.
109bf215546Sopenharmony_ci    *
110bf215546Sopenharmony_ci    * If the buffer is mapped, suppress implicit buffer range invalidation
111bf215546Sopenharmony_ci    * by using PIPE_MAP_DIRECTLY.
112bf215546Sopenharmony_ci    */
113bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
114bf215546Sopenharmony_ci
115bf215546Sopenharmony_ci   pipe->buffer_subdata(pipe, obj->buffer,
116bf215546Sopenharmony_ci                        _mesa_bufferobj_mapped(obj, MAP_USER) ?
117bf215546Sopenharmony_ci                           PIPE_MAP_DIRECTLY : 0,
118bf215546Sopenharmony_ci                        offset, size, data);
119bf215546Sopenharmony_ci}
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_ci
122bf215546Sopenharmony_ci/**
123bf215546Sopenharmony_ci * Called via glGetBufferSubDataARB().
124bf215546Sopenharmony_ci */
125bf215546Sopenharmony_cistatic void
126bf215546Sopenharmony_cibufferobj_get_subdata(struct gl_context *ctx,
127bf215546Sopenharmony_ci                      GLintptrARB offset,
128bf215546Sopenharmony_ci                      GLsizeiptrARB size,
129bf215546Sopenharmony_ci                      void *data, struct gl_buffer_object *obj)
130bf215546Sopenharmony_ci{
131bf215546Sopenharmony_ci   /* we may be called from VBO code, so double-check params here */
132bf215546Sopenharmony_ci   assert(offset >= 0);
133bf215546Sopenharmony_ci   assert(size >= 0);
134bf215546Sopenharmony_ci   assert(offset + size <= obj->Size);
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ci   if (!size)
137bf215546Sopenharmony_ci      return;
138bf215546Sopenharmony_ci
139bf215546Sopenharmony_ci   if (!obj->buffer) {
140bf215546Sopenharmony_ci      /* we probably ran out of memory during buffer allocation */
141bf215546Sopenharmony_ci      return;
142bf215546Sopenharmony_ci   }
143bf215546Sopenharmony_ci
144bf215546Sopenharmony_ci   pipe_buffer_read(ctx->pipe, obj->buffer,
145bf215546Sopenharmony_ci                    offset, size, data);
146bf215546Sopenharmony_ci}
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_civoid
149bf215546Sopenharmony_ci_mesa_bufferobj_get_subdata(struct gl_context *ctx,
150bf215546Sopenharmony_ci                            GLintptrARB offset,
151bf215546Sopenharmony_ci                            GLsizeiptrARB size,
152bf215546Sopenharmony_ci                            void *data, struct gl_buffer_object *obj)
153bf215546Sopenharmony_ci{
154bf215546Sopenharmony_ci   bufferobj_get_subdata(ctx, offset, size, data, obj);
155bf215546Sopenharmony_ci}
156bf215546Sopenharmony_ci
157bf215546Sopenharmony_ci/**
158bf215546Sopenharmony_ci * Return bitmask of PIPE_BIND_x flags corresponding a GL buffer target.
159bf215546Sopenharmony_ci */
160bf215546Sopenharmony_cistatic unsigned
161bf215546Sopenharmony_cibuffer_target_to_bind_flags(GLenum target)
162bf215546Sopenharmony_ci{
163bf215546Sopenharmony_ci   switch (target) {
164bf215546Sopenharmony_ci   case GL_PIXEL_PACK_BUFFER_ARB:
165bf215546Sopenharmony_ci   case GL_PIXEL_UNPACK_BUFFER_ARB:
166bf215546Sopenharmony_ci      return PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
167bf215546Sopenharmony_ci   case GL_ARRAY_BUFFER_ARB:
168bf215546Sopenharmony_ci      return PIPE_BIND_VERTEX_BUFFER;
169bf215546Sopenharmony_ci   case GL_ELEMENT_ARRAY_BUFFER_ARB:
170bf215546Sopenharmony_ci      return PIPE_BIND_INDEX_BUFFER;
171bf215546Sopenharmony_ci   case GL_TEXTURE_BUFFER:
172bf215546Sopenharmony_ci      return PIPE_BIND_SAMPLER_VIEW;
173bf215546Sopenharmony_ci   case GL_TRANSFORM_FEEDBACK_BUFFER:
174bf215546Sopenharmony_ci      return PIPE_BIND_STREAM_OUTPUT;
175bf215546Sopenharmony_ci   case GL_UNIFORM_BUFFER:
176bf215546Sopenharmony_ci      return PIPE_BIND_CONSTANT_BUFFER;
177bf215546Sopenharmony_ci   case GL_DRAW_INDIRECT_BUFFER:
178bf215546Sopenharmony_ci   case GL_PARAMETER_BUFFER_ARB:
179bf215546Sopenharmony_ci      return PIPE_BIND_COMMAND_ARGS_BUFFER;
180bf215546Sopenharmony_ci   case GL_ATOMIC_COUNTER_BUFFER:
181bf215546Sopenharmony_ci   case GL_SHADER_STORAGE_BUFFER:
182bf215546Sopenharmony_ci      return PIPE_BIND_SHADER_BUFFER;
183bf215546Sopenharmony_ci   case GL_QUERY_BUFFER:
184bf215546Sopenharmony_ci      return PIPE_BIND_QUERY_BUFFER;
185bf215546Sopenharmony_ci   default:
186bf215546Sopenharmony_ci      return 0;
187bf215546Sopenharmony_ci   }
188bf215546Sopenharmony_ci}
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_ci
191bf215546Sopenharmony_ci/**
192bf215546Sopenharmony_ci * Return bitmask of PIPE_RESOURCE_x flags corresponding to GL_MAP_x flags.
193bf215546Sopenharmony_ci */
194bf215546Sopenharmony_cistatic unsigned
195bf215546Sopenharmony_cistorage_flags_to_buffer_flags(GLbitfield storageFlags)
196bf215546Sopenharmony_ci{
197bf215546Sopenharmony_ci   unsigned flags = 0;
198bf215546Sopenharmony_ci   if (storageFlags & GL_MAP_PERSISTENT_BIT)
199bf215546Sopenharmony_ci      flags |= PIPE_RESOURCE_FLAG_MAP_PERSISTENT;
200bf215546Sopenharmony_ci   if (storageFlags & GL_MAP_COHERENT_BIT)
201bf215546Sopenharmony_ci      flags |= PIPE_RESOURCE_FLAG_MAP_COHERENT;
202bf215546Sopenharmony_ci   if (storageFlags & GL_SPARSE_STORAGE_BIT_ARB)
203bf215546Sopenharmony_ci      flags |= PIPE_RESOURCE_FLAG_SPARSE;
204bf215546Sopenharmony_ci   return flags;
205bf215546Sopenharmony_ci}
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_ci
208bf215546Sopenharmony_ci/**
209bf215546Sopenharmony_ci * From a buffer object's target, immutability flag, storage flags and
210bf215546Sopenharmony_ci * usage hint, return a pipe_resource_usage value (PIPE_USAGE_DYNAMIC,
211bf215546Sopenharmony_ci * STREAM, etc).
212bf215546Sopenharmony_ci */
213bf215546Sopenharmony_cistatic enum pipe_resource_usage
214bf215546Sopenharmony_cibuffer_usage(GLenum target, GLboolean immutable,
215bf215546Sopenharmony_ci             GLbitfield storageFlags, GLenum usage)
216bf215546Sopenharmony_ci{
217bf215546Sopenharmony_ci   /* "immutable" means that "storageFlags" was set by the user and "usage"
218bf215546Sopenharmony_ci    * was guessed by Mesa. Otherwise, "usage" was set by the user and
219bf215546Sopenharmony_ci    * storageFlags was guessed by Mesa.
220bf215546Sopenharmony_ci    *
221bf215546Sopenharmony_ci    * Therefore, use storageFlags with immutable, else use "usage".
222bf215546Sopenharmony_ci    */
223bf215546Sopenharmony_ci   if (immutable) {
224bf215546Sopenharmony_ci      /* BufferStorage */
225bf215546Sopenharmony_ci      if (storageFlags & GL_MAP_READ_BIT)
226bf215546Sopenharmony_ci         return PIPE_USAGE_STAGING;
227bf215546Sopenharmony_ci      else if (storageFlags & GL_CLIENT_STORAGE_BIT)
228bf215546Sopenharmony_ci         return PIPE_USAGE_STREAM;
229bf215546Sopenharmony_ci      else
230bf215546Sopenharmony_ci         return PIPE_USAGE_DEFAULT;
231bf215546Sopenharmony_ci   }
232bf215546Sopenharmony_ci   else {
233bf215546Sopenharmony_ci      /* These are often read by the CPU, so enable CPU caches. */
234bf215546Sopenharmony_ci      if (target == GL_PIXEL_PACK_BUFFER ||
235bf215546Sopenharmony_ci          target == GL_PIXEL_UNPACK_BUFFER)
236bf215546Sopenharmony_ci         return PIPE_USAGE_STAGING;
237bf215546Sopenharmony_ci
238bf215546Sopenharmony_ci      /* BufferData */
239bf215546Sopenharmony_ci      switch (usage) {
240bf215546Sopenharmony_ci      case GL_DYNAMIC_DRAW:
241bf215546Sopenharmony_ci      case GL_DYNAMIC_COPY:
242bf215546Sopenharmony_ci         return PIPE_USAGE_DYNAMIC;
243bf215546Sopenharmony_ci      case GL_STREAM_DRAW:
244bf215546Sopenharmony_ci      case GL_STREAM_COPY:
245bf215546Sopenharmony_ci         return PIPE_USAGE_STREAM;
246bf215546Sopenharmony_ci      case GL_STATIC_READ:
247bf215546Sopenharmony_ci      case GL_DYNAMIC_READ:
248bf215546Sopenharmony_ci      case GL_STREAM_READ:
249bf215546Sopenharmony_ci         return PIPE_USAGE_STAGING;
250bf215546Sopenharmony_ci      case GL_STATIC_DRAW:
251bf215546Sopenharmony_ci      case GL_STATIC_COPY:
252bf215546Sopenharmony_ci      default:
253bf215546Sopenharmony_ci         return PIPE_USAGE_DEFAULT;
254bf215546Sopenharmony_ci      }
255bf215546Sopenharmony_ci   }
256bf215546Sopenharmony_ci}
257bf215546Sopenharmony_ci
258bf215546Sopenharmony_ci
259bf215546Sopenharmony_cistatic ALWAYS_INLINE GLboolean
260bf215546Sopenharmony_cibufferobj_data(struct gl_context *ctx,
261bf215546Sopenharmony_ci               GLenum target,
262bf215546Sopenharmony_ci               GLsizeiptrARB size,
263bf215546Sopenharmony_ci               const void *data,
264bf215546Sopenharmony_ci               struct gl_memory_object *memObj,
265bf215546Sopenharmony_ci               GLuint64 offset,
266bf215546Sopenharmony_ci               GLenum usage,
267bf215546Sopenharmony_ci               GLbitfield storageFlags,
268bf215546Sopenharmony_ci               struct gl_buffer_object *obj)
269bf215546Sopenharmony_ci{
270bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
271bf215546Sopenharmony_ci   struct pipe_screen *screen = pipe->screen;
272bf215546Sopenharmony_ci   bool is_mapped = _mesa_bufferobj_mapped(obj, MAP_USER);
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_ci   if (size > UINT32_MAX || offset > UINT32_MAX) {
275bf215546Sopenharmony_ci      /* pipe_resource.width0 is 32 bits only and increasing it
276bf215546Sopenharmony_ci       * to 64 bits doesn't make much sense since hw support
277bf215546Sopenharmony_ci       * for > 4GB resources is limited.
278bf215546Sopenharmony_ci       */
279bf215546Sopenharmony_ci      obj->Size = 0;
280bf215546Sopenharmony_ci      return GL_FALSE;
281bf215546Sopenharmony_ci   }
282bf215546Sopenharmony_ci
283bf215546Sopenharmony_ci   if (target != GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD &&
284bf215546Sopenharmony_ci       size && obj->buffer &&
285bf215546Sopenharmony_ci       obj->Size == size &&
286bf215546Sopenharmony_ci       obj->Usage == usage &&
287bf215546Sopenharmony_ci       obj->StorageFlags == storageFlags) {
288bf215546Sopenharmony_ci      if (data) {
289bf215546Sopenharmony_ci         /* Just discard the old contents and write new data.
290bf215546Sopenharmony_ci          * This should be the same as creating a new buffer, but we avoid
291bf215546Sopenharmony_ci          * a lot of validation in Mesa.
292bf215546Sopenharmony_ci          *
293bf215546Sopenharmony_ci          * If the buffer is mapped, we can't discard it.
294bf215546Sopenharmony_ci          *
295bf215546Sopenharmony_ci          * PIPE_MAP_DIRECTLY supresses implicit buffer range
296bf215546Sopenharmony_ci          * invalidation.
297bf215546Sopenharmony_ci          */
298bf215546Sopenharmony_ci         pipe->buffer_subdata(pipe, obj->buffer,
299bf215546Sopenharmony_ci                              is_mapped ? PIPE_MAP_DIRECTLY :
300bf215546Sopenharmony_ci                                          PIPE_MAP_DISCARD_WHOLE_RESOURCE,
301bf215546Sopenharmony_ci                              0, size, data);
302bf215546Sopenharmony_ci         return GL_TRUE;
303bf215546Sopenharmony_ci      } else if (is_mapped) {
304bf215546Sopenharmony_ci         return GL_TRUE; /* can't reallocate, nothing to do */
305bf215546Sopenharmony_ci      } else if (screen->get_param(screen, PIPE_CAP_INVALIDATE_BUFFER)) {
306bf215546Sopenharmony_ci         pipe->invalidate_resource(pipe, obj->buffer);
307bf215546Sopenharmony_ci         return GL_TRUE;
308bf215546Sopenharmony_ci      }
309bf215546Sopenharmony_ci   }
310bf215546Sopenharmony_ci
311bf215546Sopenharmony_ci   obj->Size = size;
312bf215546Sopenharmony_ci   obj->Usage = usage;
313bf215546Sopenharmony_ci   obj->StorageFlags = storageFlags;
314bf215546Sopenharmony_ci
315bf215546Sopenharmony_ci   _mesa_bufferobj_release_buffer(obj);
316bf215546Sopenharmony_ci
317bf215546Sopenharmony_ci   unsigned bindings = buffer_target_to_bind_flags(target);
318bf215546Sopenharmony_ci
319bf215546Sopenharmony_ci   if (storageFlags & MESA_GALLIUM_VERTEX_STATE_STORAGE)
320bf215546Sopenharmony_ci      bindings |= PIPE_BIND_VERTEX_STATE;
321bf215546Sopenharmony_ci
322bf215546Sopenharmony_ci   if (ST_DEBUG & DEBUG_BUFFER) {
323bf215546Sopenharmony_ci      debug_printf("Create buffer size %" PRId64 " bind 0x%x\n",
324bf215546Sopenharmony_ci                   (int64_t) size, bindings);
325bf215546Sopenharmony_ci   }
326bf215546Sopenharmony_ci
327bf215546Sopenharmony_ci   if (size != 0) {
328bf215546Sopenharmony_ci      struct pipe_resource buffer;
329bf215546Sopenharmony_ci
330bf215546Sopenharmony_ci      memset(&buffer, 0, sizeof buffer);
331bf215546Sopenharmony_ci      buffer.target = PIPE_BUFFER;
332bf215546Sopenharmony_ci      buffer.format = PIPE_FORMAT_R8_UNORM; /* want TYPELESS or similar */
333bf215546Sopenharmony_ci      buffer.bind = bindings;
334bf215546Sopenharmony_ci      buffer.usage =
335bf215546Sopenharmony_ci         buffer_usage(target, obj->Immutable, storageFlags, usage);
336bf215546Sopenharmony_ci      buffer.flags = storage_flags_to_buffer_flags(storageFlags);
337bf215546Sopenharmony_ci      buffer.width0 = size;
338bf215546Sopenharmony_ci      buffer.height0 = 1;
339bf215546Sopenharmony_ci      buffer.depth0 = 1;
340bf215546Sopenharmony_ci      buffer.array_size = 1;
341bf215546Sopenharmony_ci
342bf215546Sopenharmony_ci      if (memObj) {
343bf215546Sopenharmony_ci         obj->buffer = screen->resource_from_memobj(screen, &buffer,
344bf215546Sopenharmony_ci                                                    memObj->memory,
345bf215546Sopenharmony_ci                                                    offset);
346bf215546Sopenharmony_ci      }
347bf215546Sopenharmony_ci      else if (target == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD) {
348bf215546Sopenharmony_ci         obj->buffer =
349bf215546Sopenharmony_ci            screen->resource_from_user_memory(screen, &buffer, (void*)data);
350bf215546Sopenharmony_ci      }
351bf215546Sopenharmony_ci      else {
352bf215546Sopenharmony_ci         obj->buffer = screen->resource_create(screen, &buffer);
353bf215546Sopenharmony_ci
354bf215546Sopenharmony_ci         if (obj->buffer && data)
355bf215546Sopenharmony_ci            pipe_buffer_write(pipe, obj->buffer, 0, size, data);
356bf215546Sopenharmony_ci      }
357bf215546Sopenharmony_ci
358bf215546Sopenharmony_ci      if (!obj->buffer) {
359bf215546Sopenharmony_ci         /* out of memory */
360bf215546Sopenharmony_ci         obj->Size = 0;
361bf215546Sopenharmony_ci         return GL_FALSE;
362bf215546Sopenharmony_ci      }
363bf215546Sopenharmony_ci
364bf215546Sopenharmony_ci      obj->private_refcount_ctx = ctx;
365bf215546Sopenharmony_ci   }
366bf215546Sopenharmony_ci
367bf215546Sopenharmony_ci   /* The current buffer may be bound, so we have to revalidate all atoms that
368bf215546Sopenharmony_ci    * might be using it.
369bf215546Sopenharmony_ci    */
370bf215546Sopenharmony_ci   if (obj->UsageHistory & USAGE_ARRAY_BUFFER)
371bf215546Sopenharmony_ci      ctx->NewDriverState |= ST_NEW_VERTEX_ARRAYS;
372bf215546Sopenharmony_ci   if (obj->UsageHistory & USAGE_UNIFORM_BUFFER)
373bf215546Sopenharmony_ci      ctx->NewDriverState |= ST_NEW_UNIFORM_BUFFER;
374bf215546Sopenharmony_ci   if (obj->UsageHistory & USAGE_SHADER_STORAGE_BUFFER)
375bf215546Sopenharmony_ci      ctx->NewDriverState |= ST_NEW_STORAGE_BUFFER;
376bf215546Sopenharmony_ci   if (obj->UsageHistory & USAGE_TEXTURE_BUFFER)
377bf215546Sopenharmony_ci      ctx->NewDriverState |= ST_NEW_SAMPLER_VIEWS | ST_NEW_IMAGE_UNITS;
378bf215546Sopenharmony_ci   if (obj->UsageHistory & USAGE_ATOMIC_COUNTER_BUFFER)
379bf215546Sopenharmony_ci      ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer;
380bf215546Sopenharmony_ci
381bf215546Sopenharmony_ci   return GL_TRUE;
382bf215546Sopenharmony_ci}
383bf215546Sopenharmony_ci
384bf215546Sopenharmony_ci/**
385bf215546Sopenharmony_ci * Allocate space for and store data in a buffer object.  Any data that was
386bf215546Sopenharmony_ci * previously stored in the buffer object is lost.  If data is NULL,
387bf215546Sopenharmony_ci * memory will be allocated, but no copy will occur.
388bf215546Sopenharmony_ci * Called via ctx->Driver.BufferData().
389bf215546Sopenharmony_ci * \return GL_TRUE for success, GL_FALSE if out of memory
390bf215546Sopenharmony_ci */
391bf215546Sopenharmony_ciGLboolean
392bf215546Sopenharmony_ci_mesa_bufferobj_data(struct gl_context *ctx,
393bf215546Sopenharmony_ci                  GLenum target,
394bf215546Sopenharmony_ci                  GLsizeiptrARB size,
395bf215546Sopenharmony_ci                  const void *data,
396bf215546Sopenharmony_ci                  GLenum usage,
397bf215546Sopenharmony_ci                  GLbitfield storageFlags,
398bf215546Sopenharmony_ci                  struct gl_buffer_object *obj)
399bf215546Sopenharmony_ci{
400bf215546Sopenharmony_ci   return bufferobj_data(ctx, target, size, data, NULL, 0, usage, storageFlags, obj);
401bf215546Sopenharmony_ci}
402bf215546Sopenharmony_ci
403bf215546Sopenharmony_cistatic GLboolean
404bf215546Sopenharmony_cibufferobj_data_mem(struct gl_context *ctx,
405bf215546Sopenharmony_ci                   GLenum target,
406bf215546Sopenharmony_ci                   GLsizeiptrARB size,
407bf215546Sopenharmony_ci                   struct gl_memory_object *memObj,
408bf215546Sopenharmony_ci                   GLuint64 offset,
409bf215546Sopenharmony_ci                   GLenum usage,
410bf215546Sopenharmony_ci                   struct gl_buffer_object *bufObj)
411bf215546Sopenharmony_ci{
412bf215546Sopenharmony_ci   return bufferobj_data(ctx, target, size, NULL, memObj, offset, usage, GL_DYNAMIC_STORAGE_BIT, bufObj);
413bf215546Sopenharmony_ci}
414bf215546Sopenharmony_ci
415bf215546Sopenharmony_ci/**
416bf215546Sopenharmony_ci * Convert GLbitfield of GL_MAP_x flags to gallium pipe_map_flags flags.
417bf215546Sopenharmony_ci * \param wholeBuffer  is the whole buffer being mapped?
418bf215546Sopenharmony_ci */
419bf215546Sopenharmony_cienum pipe_map_flags
420bf215546Sopenharmony_ci_mesa_access_flags_to_transfer_flags(GLbitfield access, bool wholeBuffer)
421bf215546Sopenharmony_ci{
422bf215546Sopenharmony_ci   enum pipe_map_flags flags = 0;
423bf215546Sopenharmony_ci
424bf215546Sopenharmony_ci   if (access & GL_MAP_WRITE_BIT)
425bf215546Sopenharmony_ci      flags |= PIPE_MAP_WRITE;
426bf215546Sopenharmony_ci
427bf215546Sopenharmony_ci   if (access & GL_MAP_READ_BIT)
428bf215546Sopenharmony_ci      flags |= PIPE_MAP_READ;
429bf215546Sopenharmony_ci
430bf215546Sopenharmony_ci   if (access & GL_MAP_FLUSH_EXPLICIT_BIT)
431bf215546Sopenharmony_ci      flags |= PIPE_MAP_FLUSH_EXPLICIT;
432bf215546Sopenharmony_ci
433bf215546Sopenharmony_ci   if (access & GL_MAP_INVALIDATE_BUFFER_BIT) {
434bf215546Sopenharmony_ci      flags |= PIPE_MAP_DISCARD_WHOLE_RESOURCE;
435bf215546Sopenharmony_ci   }
436bf215546Sopenharmony_ci   else if (access & GL_MAP_INVALIDATE_RANGE_BIT) {
437bf215546Sopenharmony_ci      if (wholeBuffer)
438bf215546Sopenharmony_ci         flags |= PIPE_MAP_DISCARD_WHOLE_RESOURCE;
439bf215546Sopenharmony_ci      else
440bf215546Sopenharmony_ci         flags |= PIPE_MAP_DISCARD_RANGE;
441bf215546Sopenharmony_ci   }
442bf215546Sopenharmony_ci
443bf215546Sopenharmony_ci   if (access & GL_MAP_UNSYNCHRONIZED_BIT)
444bf215546Sopenharmony_ci      flags |= PIPE_MAP_UNSYNCHRONIZED;
445bf215546Sopenharmony_ci
446bf215546Sopenharmony_ci   if (access & GL_MAP_PERSISTENT_BIT)
447bf215546Sopenharmony_ci      flags |= PIPE_MAP_PERSISTENT;
448bf215546Sopenharmony_ci
449bf215546Sopenharmony_ci   if (access & GL_MAP_COHERENT_BIT)
450bf215546Sopenharmony_ci      flags |= PIPE_MAP_COHERENT;
451bf215546Sopenharmony_ci
452bf215546Sopenharmony_ci   /* ... other flags ...
453bf215546Sopenharmony_ci   */
454bf215546Sopenharmony_ci
455bf215546Sopenharmony_ci   if (access & MESA_MAP_NOWAIT_BIT)
456bf215546Sopenharmony_ci      flags |= PIPE_MAP_DONTBLOCK;
457bf215546Sopenharmony_ci   if (access & MESA_MAP_THREAD_SAFE_BIT)
458bf215546Sopenharmony_ci      flags |= PIPE_MAP_THREAD_SAFE;
459bf215546Sopenharmony_ci   if (access & MESA_MAP_ONCE)
460bf215546Sopenharmony_ci      flags |= PIPE_MAP_ONCE;
461bf215546Sopenharmony_ci
462bf215546Sopenharmony_ci   return flags;
463bf215546Sopenharmony_ci}
464bf215546Sopenharmony_ci
465bf215546Sopenharmony_ci
466bf215546Sopenharmony_ci/**
467bf215546Sopenharmony_ci * Called via glMapBufferRange().
468bf215546Sopenharmony_ci */
469bf215546Sopenharmony_civoid *
470bf215546Sopenharmony_ci_mesa_bufferobj_map_range(struct gl_context *ctx,
471bf215546Sopenharmony_ci                           GLintptr offset, GLsizeiptr length, GLbitfield access,
472bf215546Sopenharmony_ci                           struct gl_buffer_object *obj,
473bf215546Sopenharmony_ci                           gl_map_buffer_index index)
474bf215546Sopenharmony_ci{
475bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
476bf215546Sopenharmony_ci
477bf215546Sopenharmony_ci   assert(offset >= 0);
478bf215546Sopenharmony_ci   assert(length >= 0);
479bf215546Sopenharmony_ci   assert(offset < obj->Size);
480bf215546Sopenharmony_ci   assert(offset + length <= obj->Size);
481bf215546Sopenharmony_ci
482bf215546Sopenharmony_ci   enum pipe_map_flags transfer_flags =
483bf215546Sopenharmony_ci      _mesa_access_flags_to_transfer_flags(access,
484bf215546Sopenharmony_ci                                           offset == 0 && length == obj->Size);
485bf215546Sopenharmony_ci
486bf215546Sopenharmony_ci   /* Sometimes games do silly things like MapBufferRange(UNSYNC|DISCARD_RANGE)
487bf215546Sopenharmony_ci    * In this case, the the UNSYNC is a bit redundant, but the games rely
488bf215546Sopenharmony_ci    * on the driver rebinding/replacing the backing storage rather than
489bf215546Sopenharmony_ci    * going down the UNSYNC path (ie. honoring DISCARD_x first before UNSYNC).
490bf215546Sopenharmony_ci    */
491bf215546Sopenharmony_ci   if (unlikely(ctx->st_opts->ignore_map_unsynchronized)) {
492bf215546Sopenharmony_ci      if (transfer_flags & (PIPE_MAP_DISCARD_RANGE | PIPE_MAP_DISCARD_WHOLE_RESOURCE))
493bf215546Sopenharmony_ci         transfer_flags &= ~PIPE_MAP_UNSYNCHRONIZED;
494bf215546Sopenharmony_ci   }
495bf215546Sopenharmony_ci
496bf215546Sopenharmony_ci   if (ctx->Const.ForceMapBufferSynchronized)
497bf215546Sopenharmony_ci      transfer_flags &= ~PIPE_MAP_UNSYNCHRONIZED;
498bf215546Sopenharmony_ci
499bf215546Sopenharmony_ci   obj->Mappings[index].Pointer = pipe_buffer_map_range(pipe,
500bf215546Sopenharmony_ci                                                        obj->buffer,
501bf215546Sopenharmony_ci                                                        offset, length,
502bf215546Sopenharmony_ci                                                        transfer_flags,
503bf215546Sopenharmony_ci                                                        &obj->transfer[index]);
504bf215546Sopenharmony_ci   if (obj->Mappings[index].Pointer) {
505bf215546Sopenharmony_ci      obj->Mappings[index].Offset = offset;
506bf215546Sopenharmony_ci      obj->Mappings[index].Length = length;
507bf215546Sopenharmony_ci      obj->Mappings[index].AccessFlags = access;
508bf215546Sopenharmony_ci   }
509bf215546Sopenharmony_ci   else {
510bf215546Sopenharmony_ci      obj->transfer[index] = NULL;
511bf215546Sopenharmony_ci   }
512bf215546Sopenharmony_ci
513bf215546Sopenharmony_ci   return obj->Mappings[index].Pointer;
514bf215546Sopenharmony_ci}
515bf215546Sopenharmony_ci
516bf215546Sopenharmony_ci
517bf215546Sopenharmony_civoid
518bf215546Sopenharmony_ci_mesa_bufferobj_flush_mapped_range(struct gl_context *ctx,
519bf215546Sopenharmony_ci                                   GLintptr offset, GLsizeiptr length,
520bf215546Sopenharmony_ci                                   struct gl_buffer_object *obj,
521bf215546Sopenharmony_ci                                   gl_map_buffer_index index)
522bf215546Sopenharmony_ci{
523bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
524bf215546Sopenharmony_ci
525bf215546Sopenharmony_ci   /* Subrange is relative to mapped range */
526bf215546Sopenharmony_ci   assert(offset >= 0);
527bf215546Sopenharmony_ci   assert(length >= 0);
528bf215546Sopenharmony_ci   assert(offset + length <= obj->Mappings[index].Length);
529bf215546Sopenharmony_ci   assert(obj->Mappings[index].Pointer);
530bf215546Sopenharmony_ci
531bf215546Sopenharmony_ci   if (!length)
532bf215546Sopenharmony_ci      return;
533bf215546Sopenharmony_ci
534bf215546Sopenharmony_ci   pipe_buffer_flush_mapped_range(pipe, obj->transfer[index],
535bf215546Sopenharmony_ci                                  obj->Mappings[index].Offset + offset,
536bf215546Sopenharmony_ci                                  length);
537bf215546Sopenharmony_ci}
538bf215546Sopenharmony_ci
539bf215546Sopenharmony_ci
540bf215546Sopenharmony_ci/**
541bf215546Sopenharmony_ci * Called via glUnmapBufferARB().
542bf215546Sopenharmony_ci */
543bf215546Sopenharmony_ciGLboolean
544bf215546Sopenharmony_ci_mesa_bufferobj_unmap(struct gl_context *ctx, struct gl_buffer_object *obj,
545bf215546Sopenharmony_ci                      gl_map_buffer_index index)
546bf215546Sopenharmony_ci{
547bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
548bf215546Sopenharmony_ci
549bf215546Sopenharmony_ci   if (obj->Mappings[index].Length)
550bf215546Sopenharmony_ci      pipe_buffer_unmap(pipe, obj->transfer[index]);
551bf215546Sopenharmony_ci
552bf215546Sopenharmony_ci   obj->transfer[index] = NULL;
553bf215546Sopenharmony_ci   obj->Mappings[index].Pointer = NULL;
554bf215546Sopenharmony_ci   obj->Mappings[index].Offset = 0;
555bf215546Sopenharmony_ci   obj->Mappings[index].Length = 0;
556bf215546Sopenharmony_ci   return GL_TRUE;
557bf215546Sopenharmony_ci}
558bf215546Sopenharmony_ci
559bf215546Sopenharmony_ci
560bf215546Sopenharmony_ci/**
561bf215546Sopenharmony_ci * Called via glCopyBufferSubData().
562bf215546Sopenharmony_ci */
563bf215546Sopenharmony_cistatic void
564bf215546Sopenharmony_cibufferobj_copy_subdata(struct gl_context *ctx,
565bf215546Sopenharmony_ci                       struct gl_buffer_object *src,
566bf215546Sopenharmony_ci                       struct gl_buffer_object *dst,
567bf215546Sopenharmony_ci                       GLintptr readOffset, GLintptr writeOffset,
568bf215546Sopenharmony_ci                       GLsizeiptr size)
569bf215546Sopenharmony_ci{
570bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
571bf215546Sopenharmony_ci   struct pipe_box box;
572bf215546Sopenharmony_ci
573bf215546Sopenharmony_ci   dst->MinMaxCacheDirty = true;
574bf215546Sopenharmony_ci   if (!size)
575bf215546Sopenharmony_ci      return;
576bf215546Sopenharmony_ci
577bf215546Sopenharmony_ci   /* buffer should not already be mapped */
578bf215546Sopenharmony_ci   assert(!_mesa_check_disallowed_mapping(src));
579bf215546Sopenharmony_ci   /* dst can be mapped, just not the same range as the target range */
580bf215546Sopenharmony_ci
581bf215546Sopenharmony_ci   u_box_1d(readOffset, size, &box);
582bf215546Sopenharmony_ci
583bf215546Sopenharmony_ci   pipe->resource_copy_region(pipe, dst->buffer, 0, writeOffset, 0, 0,
584bf215546Sopenharmony_ci                              src->buffer, 0, &box);
585bf215546Sopenharmony_ci}
586bf215546Sopenharmony_ci
587bf215546Sopenharmony_cistatic void
588bf215546Sopenharmony_ciclear_buffer_subdata_sw(struct gl_context *ctx,
589bf215546Sopenharmony_ci                        GLintptr offset, GLsizeiptr size,
590bf215546Sopenharmony_ci                        const GLvoid *clearValue,
591bf215546Sopenharmony_ci                        GLsizeiptr clearValueSize,
592bf215546Sopenharmony_ci                        struct gl_buffer_object *bufObj)
593bf215546Sopenharmony_ci{
594bf215546Sopenharmony_ci   GLsizeiptr i;
595bf215546Sopenharmony_ci   GLubyte *dest;
596bf215546Sopenharmony_ci
597bf215546Sopenharmony_ci   dest = _mesa_bufferobj_map_range(ctx, offset, size,
598bf215546Sopenharmony_ci                                    GL_MAP_WRITE_BIT |
599bf215546Sopenharmony_ci                                    GL_MAP_INVALIDATE_RANGE_BIT,
600bf215546Sopenharmony_ci                                    bufObj, MAP_INTERNAL);
601bf215546Sopenharmony_ci
602bf215546Sopenharmony_ci   if (!dest) {
603bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClearBuffer[Sub]Data");
604bf215546Sopenharmony_ci      return;
605bf215546Sopenharmony_ci   }
606bf215546Sopenharmony_ci
607bf215546Sopenharmony_ci   if (clearValue == NULL) {
608bf215546Sopenharmony_ci      /* Clear with zeros, per the spec */
609bf215546Sopenharmony_ci      memset(dest, 0, size);
610bf215546Sopenharmony_ci      _mesa_bufferobj_unmap(ctx, bufObj, MAP_INTERNAL);
611bf215546Sopenharmony_ci      return;
612bf215546Sopenharmony_ci   }
613bf215546Sopenharmony_ci
614bf215546Sopenharmony_ci   for (i = 0; i < size/clearValueSize; ++i) {
615bf215546Sopenharmony_ci      memcpy(dest, clearValue, clearValueSize);
616bf215546Sopenharmony_ci      dest += clearValueSize;
617bf215546Sopenharmony_ci   }
618bf215546Sopenharmony_ci
619bf215546Sopenharmony_ci   _mesa_bufferobj_unmap(ctx, bufObj, MAP_INTERNAL);
620bf215546Sopenharmony_ci}
621bf215546Sopenharmony_ci
622bf215546Sopenharmony_ci/**
623bf215546Sopenharmony_ci * Helper to warn of possible performance issues, such as frequently
624bf215546Sopenharmony_ci * updating a buffer created with GL_STATIC_DRAW.  Called via the macro
625bf215546Sopenharmony_ci * below.
626bf215546Sopenharmony_ci */
627bf215546Sopenharmony_cistatic void
628bf215546Sopenharmony_cibuffer_usage_warning(struct gl_context *ctx, GLuint *id, const char *fmt, ...)
629bf215546Sopenharmony_ci{
630bf215546Sopenharmony_ci   va_list args;
631bf215546Sopenharmony_ci
632bf215546Sopenharmony_ci   va_start(args, fmt);
633bf215546Sopenharmony_ci   _mesa_gl_vdebugf(ctx, id,
634bf215546Sopenharmony_ci                    MESA_DEBUG_SOURCE_API,
635bf215546Sopenharmony_ci                    MESA_DEBUG_TYPE_PERFORMANCE,
636bf215546Sopenharmony_ci                    MESA_DEBUG_SEVERITY_MEDIUM,
637bf215546Sopenharmony_ci                    fmt, args);
638bf215546Sopenharmony_ci   va_end(args);
639bf215546Sopenharmony_ci}
640bf215546Sopenharmony_ci
641bf215546Sopenharmony_ci#define BUFFER_USAGE_WARNING(CTX, FMT, ...) \
642bf215546Sopenharmony_ci   do { \
643bf215546Sopenharmony_ci      static GLuint id = 0; \
644bf215546Sopenharmony_ci      buffer_usage_warning(CTX, &id, FMT, ##__VA_ARGS__); \
645bf215546Sopenharmony_ci   } while (0)
646bf215546Sopenharmony_ci
647bf215546Sopenharmony_ci
648bf215546Sopenharmony_ci/**
649bf215546Sopenharmony_ci * Used as a placeholder for buffer objects between glGenBuffers() and
650bf215546Sopenharmony_ci * glBindBuffer() so that glIsBuffer() can work correctly.
651bf215546Sopenharmony_ci */
652bf215546Sopenharmony_cistatic struct gl_buffer_object DummyBufferObject = {
653bf215546Sopenharmony_ci   .MinMaxCacheMutex = _SIMPLE_MTX_INITIALIZER_NP,
654bf215546Sopenharmony_ci   .RefCount = 1000*1000*1000,  /* never delete */
655bf215546Sopenharmony_ci};
656bf215546Sopenharmony_ci
657bf215546Sopenharmony_ci
658bf215546Sopenharmony_ci/**
659bf215546Sopenharmony_ci * Return pointer to address of a buffer object target.
660bf215546Sopenharmony_ci * \param ctx  the GL context
661bf215546Sopenharmony_ci * \param target  the buffer object target to be retrieved.
662bf215546Sopenharmony_ci * \return   pointer to pointer to the buffer object bound to \c target in the
663bf215546Sopenharmony_ci *           specified context or \c NULL if \c target is invalid.
664bf215546Sopenharmony_ci */
665bf215546Sopenharmony_cistatic inline struct gl_buffer_object **
666bf215546Sopenharmony_ciget_buffer_target(struct gl_context *ctx, GLenum target)
667bf215546Sopenharmony_ci{
668bf215546Sopenharmony_ci   /* Other targets are only supported in desktop OpenGL and OpenGL ES 3.0. */
669bf215546Sopenharmony_ci   if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx)) {
670bf215546Sopenharmony_ci      switch (target) {
671bf215546Sopenharmony_ci      case GL_ARRAY_BUFFER:
672bf215546Sopenharmony_ci      case GL_ELEMENT_ARRAY_BUFFER:
673bf215546Sopenharmony_ci         break;
674bf215546Sopenharmony_ci      case GL_PIXEL_PACK_BUFFER:
675bf215546Sopenharmony_ci      case GL_PIXEL_UNPACK_BUFFER:
676bf215546Sopenharmony_ci         if (!ctx->Extensions.EXT_pixel_buffer_object)
677bf215546Sopenharmony_ci            return NULL;
678bf215546Sopenharmony_ci         break;
679bf215546Sopenharmony_ci      default:
680bf215546Sopenharmony_ci         return NULL;
681bf215546Sopenharmony_ci      }
682bf215546Sopenharmony_ci   }
683bf215546Sopenharmony_ci
684bf215546Sopenharmony_ci   switch (target) {
685bf215546Sopenharmony_ci   case GL_ARRAY_BUFFER_ARB:
686bf215546Sopenharmony_ci      return &ctx->Array.ArrayBufferObj;
687bf215546Sopenharmony_ci   case GL_ELEMENT_ARRAY_BUFFER_ARB:
688bf215546Sopenharmony_ci      return &ctx->Array.VAO->IndexBufferObj;
689bf215546Sopenharmony_ci   case GL_PIXEL_PACK_BUFFER_EXT:
690bf215546Sopenharmony_ci      return &ctx->Pack.BufferObj;
691bf215546Sopenharmony_ci   case GL_PIXEL_UNPACK_BUFFER_EXT:
692bf215546Sopenharmony_ci      return &ctx->Unpack.BufferObj;
693bf215546Sopenharmony_ci   case GL_COPY_READ_BUFFER:
694bf215546Sopenharmony_ci      return &ctx->CopyReadBuffer;
695bf215546Sopenharmony_ci   case GL_COPY_WRITE_BUFFER:
696bf215546Sopenharmony_ci      return &ctx->CopyWriteBuffer;
697bf215546Sopenharmony_ci   case GL_QUERY_BUFFER:
698bf215546Sopenharmony_ci      if (_mesa_has_ARB_query_buffer_object(ctx))
699bf215546Sopenharmony_ci         return &ctx->QueryBuffer;
700bf215546Sopenharmony_ci      break;
701bf215546Sopenharmony_ci   case GL_DRAW_INDIRECT_BUFFER:
702bf215546Sopenharmony_ci      if ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_draw_indirect) ||
703bf215546Sopenharmony_ci           _mesa_is_gles31(ctx)) {
704bf215546Sopenharmony_ci         return &ctx->DrawIndirectBuffer;
705bf215546Sopenharmony_ci      }
706bf215546Sopenharmony_ci      break;
707bf215546Sopenharmony_ci   case GL_PARAMETER_BUFFER_ARB:
708bf215546Sopenharmony_ci      if (_mesa_has_ARB_indirect_parameters(ctx)) {
709bf215546Sopenharmony_ci         return &ctx->ParameterBuffer;
710bf215546Sopenharmony_ci      }
711bf215546Sopenharmony_ci      break;
712bf215546Sopenharmony_ci   case GL_DISPATCH_INDIRECT_BUFFER:
713bf215546Sopenharmony_ci      if (_mesa_has_compute_shaders(ctx)) {
714bf215546Sopenharmony_ci         return &ctx->DispatchIndirectBuffer;
715bf215546Sopenharmony_ci      }
716bf215546Sopenharmony_ci      break;
717bf215546Sopenharmony_ci   case GL_TRANSFORM_FEEDBACK_BUFFER:
718bf215546Sopenharmony_ci      if (ctx->Extensions.EXT_transform_feedback) {
719bf215546Sopenharmony_ci         return &ctx->TransformFeedback.CurrentBuffer;
720bf215546Sopenharmony_ci      }
721bf215546Sopenharmony_ci      break;
722bf215546Sopenharmony_ci   case GL_TEXTURE_BUFFER:
723bf215546Sopenharmony_ci      if (_mesa_has_ARB_texture_buffer_object(ctx) ||
724bf215546Sopenharmony_ci          _mesa_has_OES_texture_buffer(ctx)) {
725bf215546Sopenharmony_ci         return &ctx->Texture.BufferObject;
726bf215546Sopenharmony_ci      }
727bf215546Sopenharmony_ci      break;
728bf215546Sopenharmony_ci   case GL_UNIFORM_BUFFER:
729bf215546Sopenharmony_ci      if (ctx->Extensions.ARB_uniform_buffer_object) {
730bf215546Sopenharmony_ci         return &ctx->UniformBuffer;
731bf215546Sopenharmony_ci      }
732bf215546Sopenharmony_ci      break;
733bf215546Sopenharmony_ci   case GL_SHADER_STORAGE_BUFFER:
734bf215546Sopenharmony_ci      if (ctx->Extensions.ARB_shader_storage_buffer_object || _mesa_is_gles31(ctx)) {
735bf215546Sopenharmony_ci         return &ctx->ShaderStorageBuffer;
736bf215546Sopenharmony_ci      }
737bf215546Sopenharmony_ci      break;
738bf215546Sopenharmony_ci   case GL_ATOMIC_COUNTER_BUFFER:
739bf215546Sopenharmony_ci      if (ctx->Extensions.ARB_shader_atomic_counters || _mesa_is_gles31(ctx)) {
740bf215546Sopenharmony_ci         return &ctx->AtomicBuffer;
741bf215546Sopenharmony_ci      }
742bf215546Sopenharmony_ci      break;
743bf215546Sopenharmony_ci   case GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD:
744bf215546Sopenharmony_ci      if (ctx->Extensions.AMD_pinned_memory) {
745bf215546Sopenharmony_ci         return &ctx->ExternalVirtualMemoryBuffer;
746bf215546Sopenharmony_ci      }
747bf215546Sopenharmony_ci      break;
748bf215546Sopenharmony_ci   default:
749bf215546Sopenharmony_ci      return NULL;
750bf215546Sopenharmony_ci   }
751bf215546Sopenharmony_ci   return NULL;
752bf215546Sopenharmony_ci}
753bf215546Sopenharmony_ci
754bf215546Sopenharmony_ci
755bf215546Sopenharmony_ci/**
756bf215546Sopenharmony_ci * Get the buffer object bound to the specified target in a GL context.
757bf215546Sopenharmony_ci * \param ctx  the GL context
758bf215546Sopenharmony_ci * \param target  the buffer object target to be retrieved.
759bf215546Sopenharmony_ci * \param error  the GL error to record if target is illegal.
760bf215546Sopenharmony_ci * \return   pointer to the buffer object bound to \c target in the
761bf215546Sopenharmony_ci *           specified context or \c NULL if \c target is invalid.
762bf215546Sopenharmony_ci */
763bf215546Sopenharmony_cistatic inline struct gl_buffer_object *
764bf215546Sopenharmony_ciget_buffer(struct gl_context *ctx, const char *func, GLenum target,
765bf215546Sopenharmony_ci           GLenum error)
766bf215546Sopenharmony_ci{
767bf215546Sopenharmony_ci   struct gl_buffer_object **bufObj = get_buffer_target(ctx, target);
768bf215546Sopenharmony_ci
769bf215546Sopenharmony_ci   if (!bufObj) {
770bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
771bf215546Sopenharmony_ci      return NULL;
772bf215546Sopenharmony_ci   }
773bf215546Sopenharmony_ci
774bf215546Sopenharmony_ci   if (!*bufObj) {
775bf215546Sopenharmony_ci      _mesa_error(ctx, error, "%s(no buffer bound)", func);
776bf215546Sopenharmony_ci      return NULL;
777bf215546Sopenharmony_ci   }
778bf215546Sopenharmony_ci
779bf215546Sopenharmony_ci   return *bufObj;
780bf215546Sopenharmony_ci}
781bf215546Sopenharmony_ci
782bf215546Sopenharmony_ci
783bf215546Sopenharmony_ci/**
784bf215546Sopenharmony_ci * Convert a GLbitfield describing the mapped buffer access flags
785bf215546Sopenharmony_ci * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY.
786bf215546Sopenharmony_ci */
787bf215546Sopenharmony_cistatic GLenum
788bf215546Sopenharmony_cisimplified_access_mode(struct gl_context *ctx, GLbitfield access)
789bf215546Sopenharmony_ci{
790bf215546Sopenharmony_ci   const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
791bf215546Sopenharmony_ci   if ((access & rwFlags) == rwFlags)
792bf215546Sopenharmony_ci      return GL_READ_WRITE;
793bf215546Sopenharmony_ci   if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT)
794bf215546Sopenharmony_ci      return GL_READ_ONLY;
795bf215546Sopenharmony_ci   if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT)
796bf215546Sopenharmony_ci      return GL_WRITE_ONLY;
797bf215546Sopenharmony_ci
798bf215546Sopenharmony_ci   /* Otherwise, AccessFlags is zero (the default state).
799bf215546Sopenharmony_ci    *
800bf215546Sopenharmony_ci    * Table 2.6 on page 31 (page 44 of the PDF) of the OpenGL 1.5 spec says:
801bf215546Sopenharmony_ci    *
802bf215546Sopenharmony_ci    * Name           Type  Initial Value  Legal Values
803bf215546Sopenharmony_ci    * ...            ...   ...            ...
804bf215546Sopenharmony_ci    * BUFFER_ACCESS  enum  READ_WRITE     READ_ONLY, WRITE_ONLY
805bf215546Sopenharmony_ci    *                                     READ_WRITE
806bf215546Sopenharmony_ci    *
807bf215546Sopenharmony_ci    * However, table 6.8 in the GL_OES_mapbuffer extension says:
808bf215546Sopenharmony_ci    *
809bf215546Sopenharmony_ci    * Get Value         Type Get Command          Value          Description
810bf215546Sopenharmony_ci    * ---------         ---- -----------          -----          -----------
811bf215546Sopenharmony_ci    * BUFFER_ACCESS_OES Z1   GetBufferParameteriv WRITE_ONLY_OES buffer map flag
812bf215546Sopenharmony_ci    *
813bf215546Sopenharmony_ci    * The difference is because GL_OES_mapbuffer only supports mapping buffers
814bf215546Sopenharmony_ci    * write-only.
815bf215546Sopenharmony_ci    */
816bf215546Sopenharmony_ci   assert(access == 0);
817bf215546Sopenharmony_ci
818bf215546Sopenharmony_ci   return _mesa_is_gles(ctx) ? GL_WRITE_ONLY : GL_READ_WRITE;
819bf215546Sopenharmony_ci}
820bf215546Sopenharmony_ci
821bf215546Sopenharmony_ci
822bf215546Sopenharmony_ci/**
823bf215546Sopenharmony_ci * Test if the buffer is mapped, and if so, if the mapped range overlaps the
824bf215546Sopenharmony_ci * given range.
825bf215546Sopenharmony_ci * The regions do not overlap if and only if the end of the given
826bf215546Sopenharmony_ci * region is before the mapped region or the start of the given region
827bf215546Sopenharmony_ci * is after the mapped region.
828bf215546Sopenharmony_ci *
829bf215546Sopenharmony_ci * \param obj     Buffer object target on which to operate.
830bf215546Sopenharmony_ci * \param offset  Offset of the first byte of the subdata range.
831bf215546Sopenharmony_ci * \param size    Size, in bytes, of the subdata range.
832bf215546Sopenharmony_ci * \return   true if ranges overlap, false otherwise
833bf215546Sopenharmony_ci *
834bf215546Sopenharmony_ci */
835bf215546Sopenharmony_cistatic bool
836bf215546Sopenharmony_cibufferobj_range_mapped(const struct gl_buffer_object *obj,
837bf215546Sopenharmony_ci                       GLintptr offset, GLsizeiptr size)
838bf215546Sopenharmony_ci{
839bf215546Sopenharmony_ci   if (_mesa_bufferobj_mapped(obj, MAP_USER)) {
840bf215546Sopenharmony_ci      const GLintptr end = offset + size;
841bf215546Sopenharmony_ci      const GLintptr mapEnd = obj->Mappings[MAP_USER].Offset +
842bf215546Sopenharmony_ci                              obj->Mappings[MAP_USER].Length;
843bf215546Sopenharmony_ci
844bf215546Sopenharmony_ci      if (!(end <= obj->Mappings[MAP_USER].Offset || offset >= mapEnd)) {
845bf215546Sopenharmony_ci         return true;
846bf215546Sopenharmony_ci      }
847bf215546Sopenharmony_ci   }
848bf215546Sopenharmony_ci   return false;
849bf215546Sopenharmony_ci}
850bf215546Sopenharmony_ci
851bf215546Sopenharmony_ci
852bf215546Sopenharmony_ci/**
853bf215546Sopenharmony_ci * Tests the subdata range parameters and sets the GL error code for
854bf215546Sopenharmony_ci * \c glBufferSubDataARB, \c glGetBufferSubDataARB and
855bf215546Sopenharmony_ci * \c glClearBufferSubData.
856bf215546Sopenharmony_ci *
857bf215546Sopenharmony_ci * \param ctx     GL context.
858bf215546Sopenharmony_ci * \param bufObj  The buffer object.
859bf215546Sopenharmony_ci * \param offset  Offset of the first byte of the subdata range.
860bf215546Sopenharmony_ci * \param size    Size, in bytes, of the subdata range.
861bf215546Sopenharmony_ci * \param mappedRange  If true, checks if an overlapping range is mapped.
862bf215546Sopenharmony_ci *                     If false, checks if buffer is mapped.
863bf215546Sopenharmony_ci * \param caller  Name of calling function for recording errors.
864bf215546Sopenharmony_ci * \return   false if error, true otherwise
865bf215546Sopenharmony_ci *
866bf215546Sopenharmony_ci * \sa glBufferSubDataARB, glGetBufferSubDataARB, glClearBufferSubData
867bf215546Sopenharmony_ci */
868bf215546Sopenharmony_cistatic bool
869bf215546Sopenharmony_cibuffer_object_subdata_range_good(struct gl_context *ctx,
870bf215546Sopenharmony_ci                                 const struct gl_buffer_object *bufObj,
871bf215546Sopenharmony_ci                                 GLintptr offset, GLsizeiptr size,
872bf215546Sopenharmony_ci                                 bool mappedRange, const char *caller)
873bf215546Sopenharmony_ci{
874bf215546Sopenharmony_ci   if (size < 0) {
875bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller);
876bf215546Sopenharmony_ci      return false;
877bf215546Sopenharmony_ci   }
878bf215546Sopenharmony_ci
879bf215546Sopenharmony_ci   if (offset < 0) {
880bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller);
881bf215546Sopenharmony_ci      return false;
882bf215546Sopenharmony_ci   }
883bf215546Sopenharmony_ci
884bf215546Sopenharmony_ci   if (offset + size > bufObj->Size) {
885bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
886bf215546Sopenharmony_ci                  "%s(offset %lu + size %lu > buffer size %lu)", caller,
887bf215546Sopenharmony_ci                  (unsigned long) offset,
888bf215546Sopenharmony_ci                  (unsigned long) size,
889bf215546Sopenharmony_ci                  (unsigned long) bufObj->Size);
890bf215546Sopenharmony_ci      return false;
891bf215546Sopenharmony_ci   }
892bf215546Sopenharmony_ci
893bf215546Sopenharmony_ci   if (bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_PERSISTENT_BIT)
894bf215546Sopenharmony_ci      return true;
895bf215546Sopenharmony_ci
896bf215546Sopenharmony_ci   if (mappedRange) {
897bf215546Sopenharmony_ci      if (bufferobj_range_mapped(bufObj, offset, size)) {
898bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
899bf215546Sopenharmony_ci                     "%s(range is mapped without persistent bit)",
900bf215546Sopenharmony_ci                     caller);
901bf215546Sopenharmony_ci         return false;
902bf215546Sopenharmony_ci      }
903bf215546Sopenharmony_ci   }
904bf215546Sopenharmony_ci   else {
905bf215546Sopenharmony_ci      if (_mesa_bufferobj_mapped(bufObj, MAP_USER)) {
906bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
907bf215546Sopenharmony_ci                     "%s(buffer is mapped without persistent bit)",
908bf215546Sopenharmony_ci                     caller);
909bf215546Sopenharmony_ci         return false;
910bf215546Sopenharmony_ci      }
911bf215546Sopenharmony_ci   }
912bf215546Sopenharmony_ci
913bf215546Sopenharmony_ci   return true;
914bf215546Sopenharmony_ci}
915bf215546Sopenharmony_ci
916bf215546Sopenharmony_ci
917bf215546Sopenharmony_ci/**
918bf215546Sopenharmony_ci * Test the format and type parameters and set the GL error code for
919bf215546Sopenharmony_ci * \c glClearBufferData, \c glClearNamedBufferData, \c glClearBufferSubData
920bf215546Sopenharmony_ci * and \c glClearNamedBufferSubData.
921bf215546Sopenharmony_ci *
922bf215546Sopenharmony_ci * \param ctx             GL context.
923bf215546Sopenharmony_ci * \param internalformat  Format to which the data is to be converted.
924bf215546Sopenharmony_ci * \param format          Format of the supplied data.
925bf215546Sopenharmony_ci * \param type            Type of the supplied data.
926bf215546Sopenharmony_ci * \param caller          Name of calling function for recording errors.
927bf215546Sopenharmony_ci * \return   If internalformat, format and type are legal the mesa_format
928bf215546Sopenharmony_ci *           corresponding to internalformat, otherwise MESA_FORMAT_NONE.
929bf215546Sopenharmony_ci *
930bf215546Sopenharmony_ci * \sa glClearBufferData, glClearNamedBufferData, glClearBufferSubData and
931bf215546Sopenharmony_ci *     glClearNamedBufferSubData.
932bf215546Sopenharmony_ci */
933bf215546Sopenharmony_cistatic mesa_format
934bf215546Sopenharmony_civalidate_clear_buffer_format(struct gl_context *ctx,
935bf215546Sopenharmony_ci                             GLenum internalformat,
936bf215546Sopenharmony_ci                             GLenum format, GLenum type,
937bf215546Sopenharmony_ci                             const char *caller)
938bf215546Sopenharmony_ci{
939bf215546Sopenharmony_ci   mesa_format mesaFormat;
940bf215546Sopenharmony_ci   GLenum errorFormatType;
941bf215546Sopenharmony_ci
942bf215546Sopenharmony_ci   mesaFormat = _mesa_validate_texbuffer_format(ctx, internalformat);
943bf215546Sopenharmony_ci   if (mesaFormat == MESA_FORMAT_NONE) {
944bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM,
945bf215546Sopenharmony_ci                  "%s(invalid internalformat)", caller);
946bf215546Sopenharmony_ci      return MESA_FORMAT_NONE;
947bf215546Sopenharmony_ci   }
948bf215546Sopenharmony_ci
949bf215546Sopenharmony_ci   /* NOTE: not mentioned in ARB_clear_buffer_object but according to
950bf215546Sopenharmony_ci    * EXT_texture_integer there is no conversion between integer and
951bf215546Sopenharmony_ci    * non-integer formats
952bf215546Sopenharmony_ci   */
953bf215546Sopenharmony_ci   if (_mesa_is_enum_format_signed_int(format) !=
954bf215546Sopenharmony_ci       _mesa_is_format_integer_color(mesaFormat)) {
955bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
956bf215546Sopenharmony_ci                  "%s(integer vs non-integer)", caller);
957bf215546Sopenharmony_ci      return MESA_FORMAT_NONE;
958bf215546Sopenharmony_ci   }
959bf215546Sopenharmony_ci
960bf215546Sopenharmony_ci   if (!_mesa_is_color_format(format)) {
961bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
962bf215546Sopenharmony_ci                  "%s(format is not a color format)", caller);
963bf215546Sopenharmony_ci      return MESA_FORMAT_NONE;
964bf215546Sopenharmony_ci   }
965bf215546Sopenharmony_ci
966bf215546Sopenharmony_ci   errorFormatType = _mesa_error_check_format_and_type(ctx, format, type);
967bf215546Sopenharmony_ci   if (errorFormatType != GL_NO_ERROR) {
968bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
969bf215546Sopenharmony_ci                  "%s(invalid format or type)", caller);
970bf215546Sopenharmony_ci      return MESA_FORMAT_NONE;
971bf215546Sopenharmony_ci   }
972bf215546Sopenharmony_ci
973bf215546Sopenharmony_ci   return mesaFormat;
974bf215546Sopenharmony_ci}
975bf215546Sopenharmony_ci
976bf215546Sopenharmony_ci
977bf215546Sopenharmony_ci/**
978bf215546Sopenharmony_ci * Convert user-specified clear value to the specified internal format.
979bf215546Sopenharmony_ci *
980bf215546Sopenharmony_ci * \param ctx             GL context.
981bf215546Sopenharmony_ci * \param internalformat  Format to which the data is converted.
982bf215546Sopenharmony_ci * \param clearValue      Points to the converted clear value.
983bf215546Sopenharmony_ci * \param format          Format of the supplied data.
984bf215546Sopenharmony_ci * \param type            Type of the supplied data.
985bf215546Sopenharmony_ci * \param data            Data which is to be converted to internalformat.
986bf215546Sopenharmony_ci * \param caller          Name of calling function for recording errors.
987bf215546Sopenharmony_ci * \return   true if data could be converted, false otherwise.
988bf215546Sopenharmony_ci *
989bf215546Sopenharmony_ci * \sa glClearBufferData, glClearBufferSubData
990bf215546Sopenharmony_ci */
991bf215546Sopenharmony_cistatic bool
992bf215546Sopenharmony_ciconvert_clear_buffer_data(struct gl_context *ctx,
993bf215546Sopenharmony_ci                          mesa_format internalformat,
994bf215546Sopenharmony_ci                          GLubyte *clearValue, GLenum format, GLenum type,
995bf215546Sopenharmony_ci                          const GLvoid *data, const char *caller)
996bf215546Sopenharmony_ci{
997bf215546Sopenharmony_ci   GLenum internalformatBase = _mesa_get_format_base_format(internalformat);
998bf215546Sopenharmony_ci
999bf215546Sopenharmony_ci   if (_mesa_texstore(ctx, 1, internalformatBase, internalformat,
1000bf215546Sopenharmony_ci                      0, &clearValue, 1, 1, 1,
1001bf215546Sopenharmony_ci                      format, type, data, &ctx->Unpack)) {
1002bf215546Sopenharmony_ci      return true;
1003bf215546Sopenharmony_ci   }
1004bf215546Sopenharmony_ci   else {
1005bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller);
1006bf215546Sopenharmony_ci      return false;
1007bf215546Sopenharmony_ci   }
1008bf215546Sopenharmony_ci}
1009bf215546Sopenharmony_ci
1010bf215546Sopenharmony_civoid
1011bf215546Sopenharmony_ci_mesa_bufferobj_release_buffer(struct gl_buffer_object *obj)
1012bf215546Sopenharmony_ci{
1013bf215546Sopenharmony_ci   if (!obj->buffer)
1014bf215546Sopenharmony_ci      return;
1015bf215546Sopenharmony_ci
1016bf215546Sopenharmony_ci   /* Subtract the remaining private references before unreferencing
1017bf215546Sopenharmony_ci    * the buffer. See the header file for explanation.
1018bf215546Sopenharmony_ci    */
1019bf215546Sopenharmony_ci   if (obj->private_refcount) {
1020bf215546Sopenharmony_ci      assert(obj->private_refcount > 0);
1021bf215546Sopenharmony_ci      p_atomic_add(&obj->buffer->reference.count,
1022bf215546Sopenharmony_ci                   -obj->private_refcount);
1023bf215546Sopenharmony_ci      obj->private_refcount = 0;
1024bf215546Sopenharmony_ci   }
1025bf215546Sopenharmony_ci   obj->private_refcount_ctx = NULL;
1026bf215546Sopenharmony_ci
1027bf215546Sopenharmony_ci   pipe_resource_reference(&obj->buffer, NULL);
1028bf215546Sopenharmony_ci}
1029bf215546Sopenharmony_ci
1030bf215546Sopenharmony_ci/**
1031bf215546Sopenharmony_ci * Delete a buffer object.
1032bf215546Sopenharmony_ci *
1033bf215546Sopenharmony_ci * Default callback for the \c dd_function_table::DeleteBuffer() hook.
1034bf215546Sopenharmony_ci */
1035bf215546Sopenharmony_civoid
1036bf215546Sopenharmony_ci_mesa_delete_buffer_object(struct gl_context *ctx,
1037bf215546Sopenharmony_ci                           struct gl_buffer_object *bufObj)
1038bf215546Sopenharmony_ci{
1039bf215546Sopenharmony_ci   assert(bufObj->RefCount == 0);
1040bf215546Sopenharmony_ci   _mesa_buffer_unmap_all_mappings(ctx, bufObj);
1041bf215546Sopenharmony_ci   _mesa_bufferobj_release_buffer(bufObj);
1042bf215546Sopenharmony_ci
1043bf215546Sopenharmony_ci   vbo_delete_minmax_cache(bufObj);
1044bf215546Sopenharmony_ci   align_free(bufObj->Data);
1045bf215546Sopenharmony_ci
1046bf215546Sopenharmony_ci   /* assign strange values here to help w/ debugging */
1047bf215546Sopenharmony_ci   bufObj->RefCount = -1000;
1048bf215546Sopenharmony_ci   bufObj->Name = ~0;
1049bf215546Sopenharmony_ci
1050bf215546Sopenharmony_ci   simple_mtx_destroy(&bufObj->MinMaxCacheMutex);
1051bf215546Sopenharmony_ci   free(bufObj->Label);
1052bf215546Sopenharmony_ci   free(bufObj);
1053bf215546Sopenharmony_ci}
1054bf215546Sopenharmony_ci
1055bf215546Sopenharmony_ci
1056bf215546Sopenharmony_ci
1057bf215546Sopenharmony_ci/**
1058bf215546Sopenharmony_ci * Set ptr to bufObj w/ reference counting.
1059bf215546Sopenharmony_ci * This is normally only called from the _mesa_reference_buffer_object() macro
1060bf215546Sopenharmony_ci * when there's a real pointer change.
1061bf215546Sopenharmony_ci */
1062bf215546Sopenharmony_civoid
1063bf215546Sopenharmony_ci_mesa_reference_buffer_object_(struct gl_context *ctx,
1064bf215546Sopenharmony_ci                               struct gl_buffer_object **ptr,
1065bf215546Sopenharmony_ci                               struct gl_buffer_object *bufObj,
1066bf215546Sopenharmony_ci                               bool shared_binding)
1067bf215546Sopenharmony_ci{
1068bf215546Sopenharmony_ci   if (*ptr) {
1069bf215546Sopenharmony_ci      /* Unreference the old buffer */
1070bf215546Sopenharmony_ci      struct gl_buffer_object *oldObj = *ptr;
1071bf215546Sopenharmony_ci
1072bf215546Sopenharmony_ci      assert(oldObj->RefCount >= 1);
1073bf215546Sopenharmony_ci
1074bf215546Sopenharmony_ci      /* Count references only if the context doesn't own the buffer or if
1075bf215546Sopenharmony_ci       * ptr is a binding point shared by multiple contexts (such as a texture
1076bf215546Sopenharmony_ci       * buffer object being a buffer bound within a texture object).
1077bf215546Sopenharmony_ci       */
1078bf215546Sopenharmony_ci      if (shared_binding || ctx != oldObj->Ctx) {
1079bf215546Sopenharmony_ci         if (p_atomic_dec_zero(&oldObj->RefCount)) {
1080bf215546Sopenharmony_ci            _mesa_delete_buffer_object(ctx, oldObj);
1081bf215546Sopenharmony_ci         }
1082bf215546Sopenharmony_ci      } else if (ctx == oldObj->Ctx) {
1083bf215546Sopenharmony_ci         /* Update the private ref count. */
1084bf215546Sopenharmony_ci         assert(oldObj->CtxRefCount >= 1);
1085bf215546Sopenharmony_ci         oldObj->CtxRefCount--;
1086bf215546Sopenharmony_ci      }
1087bf215546Sopenharmony_ci
1088bf215546Sopenharmony_ci      *ptr = NULL;
1089bf215546Sopenharmony_ci   }
1090bf215546Sopenharmony_ci   assert(!*ptr);
1091bf215546Sopenharmony_ci
1092bf215546Sopenharmony_ci   if (bufObj) {
1093bf215546Sopenharmony_ci      /* reference new buffer */
1094bf215546Sopenharmony_ci      if (shared_binding || ctx != bufObj->Ctx)
1095bf215546Sopenharmony_ci         p_atomic_inc(&bufObj->RefCount);
1096bf215546Sopenharmony_ci      else if (ctx == bufObj->Ctx)
1097bf215546Sopenharmony_ci         bufObj->CtxRefCount++;
1098bf215546Sopenharmony_ci
1099bf215546Sopenharmony_ci      *ptr = bufObj;
1100bf215546Sopenharmony_ci   }
1101bf215546Sopenharmony_ci}
1102bf215546Sopenharmony_ci
1103bf215546Sopenharmony_ci
1104bf215546Sopenharmony_ci/**
1105bf215546Sopenharmony_ci * Get the value of MESA_NO_MINMAX_CACHE.
1106bf215546Sopenharmony_ci */
1107bf215546Sopenharmony_cistatic bool
1108bf215546Sopenharmony_ciget_no_minmax_cache()
1109bf215546Sopenharmony_ci{
1110bf215546Sopenharmony_ci   static bool read = false;
1111bf215546Sopenharmony_ci   static bool disable = false;
1112bf215546Sopenharmony_ci
1113bf215546Sopenharmony_ci   if (!read) {
1114bf215546Sopenharmony_ci      disable = env_var_as_boolean("MESA_NO_MINMAX_CACHE", false);
1115bf215546Sopenharmony_ci      read = true;
1116bf215546Sopenharmony_ci   }
1117bf215546Sopenharmony_ci
1118bf215546Sopenharmony_ci   return disable;
1119bf215546Sopenharmony_ci}
1120bf215546Sopenharmony_ci
1121bf215546Sopenharmony_ci/**
1122bf215546Sopenharmony_ci * Callback called from _mesa_HashWalk()
1123bf215546Sopenharmony_ci */
1124bf215546Sopenharmony_cistatic void
1125bf215546Sopenharmony_cicount_buffer_size(void *data, void *userData)
1126bf215546Sopenharmony_ci{
1127bf215546Sopenharmony_ci   const struct gl_buffer_object *bufObj =
1128bf215546Sopenharmony_ci      (const struct gl_buffer_object *) data;
1129bf215546Sopenharmony_ci   GLuint *total = (GLuint *) userData;
1130bf215546Sopenharmony_ci
1131bf215546Sopenharmony_ci   *total = *total + bufObj->Size;
1132bf215546Sopenharmony_ci}
1133bf215546Sopenharmony_ci
1134bf215546Sopenharmony_ci
1135bf215546Sopenharmony_ci/**
1136bf215546Sopenharmony_ci * Compute total size (in bytes) of all buffer objects for the given context.
1137bf215546Sopenharmony_ci * For debugging purposes.
1138bf215546Sopenharmony_ci */
1139bf215546Sopenharmony_ciGLuint
1140bf215546Sopenharmony_ci_mesa_total_buffer_object_memory(struct gl_context *ctx)
1141bf215546Sopenharmony_ci{
1142bf215546Sopenharmony_ci   GLuint total = 0;
1143bf215546Sopenharmony_ci
1144bf215546Sopenharmony_ci   _mesa_HashWalkMaybeLocked(ctx->Shared->BufferObjects, count_buffer_size,
1145bf215546Sopenharmony_ci                             &total, ctx->BufferObjectsLocked);
1146bf215546Sopenharmony_ci
1147bf215546Sopenharmony_ci   return total;
1148bf215546Sopenharmony_ci}
1149bf215546Sopenharmony_ci
1150bf215546Sopenharmony_ci/**
1151bf215546Sopenharmony_ci * Initialize the state associated with buffer objects
1152bf215546Sopenharmony_ci */
1153bf215546Sopenharmony_civoid
1154bf215546Sopenharmony_ci_mesa_init_buffer_objects( struct gl_context *ctx )
1155bf215546Sopenharmony_ci{
1156bf215546Sopenharmony_ci   GLuint i;
1157bf215546Sopenharmony_ci
1158bf215546Sopenharmony_ci   for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) {
1159bf215546Sopenharmony_ci      _mesa_reference_buffer_object(ctx,
1160bf215546Sopenharmony_ci				    &ctx->UniformBufferBindings[i].BufferObject,
1161bf215546Sopenharmony_ci				    NULL);
1162bf215546Sopenharmony_ci      ctx->UniformBufferBindings[i].Offset = -1;
1163bf215546Sopenharmony_ci      ctx->UniformBufferBindings[i].Size = -1;
1164bf215546Sopenharmony_ci   }
1165bf215546Sopenharmony_ci
1166bf215546Sopenharmony_ci   for (i = 0; i < MAX_COMBINED_SHADER_STORAGE_BUFFERS; i++) {
1167bf215546Sopenharmony_ci      _mesa_reference_buffer_object(ctx,
1168bf215546Sopenharmony_ci                                    &ctx->ShaderStorageBufferBindings[i].BufferObject,
1169bf215546Sopenharmony_ci                                    NULL);
1170bf215546Sopenharmony_ci      ctx->ShaderStorageBufferBindings[i].Offset = -1;
1171bf215546Sopenharmony_ci      ctx->ShaderStorageBufferBindings[i].Size = -1;
1172bf215546Sopenharmony_ci   }
1173bf215546Sopenharmony_ci
1174bf215546Sopenharmony_ci   for (i = 0; i < MAX_COMBINED_ATOMIC_BUFFERS; i++) {
1175bf215546Sopenharmony_ci      _mesa_reference_buffer_object(ctx,
1176bf215546Sopenharmony_ci				    &ctx->AtomicBufferBindings[i].BufferObject,
1177bf215546Sopenharmony_ci				    NULL);
1178bf215546Sopenharmony_ci      ctx->AtomicBufferBindings[i].Offset = 0;
1179bf215546Sopenharmony_ci      ctx->AtomicBufferBindings[i].Size = 0;
1180bf215546Sopenharmony_ci   }
1181bf215546Sopenharmony_ci}
1182bf215546Sopenharmony_ci
1183bf215546Sopenharmony_ci/**
1184bf215546Sopenharmony_ci * Detach the context from the buffer to re-enable buffer reference counting
1185bf215546Sopenharmony_ci * for this context.
1186bf215546Sopenharmony_ci */
1187bf215546Sopenharmony_cistatic void
1188bf215546Sopenharmony_cidetach_ctx_from_buffer(struct gl_context *ctx, struct gl_buffer_object *buf)
1189bf215546Sopenharmony_ci{
1190bf215546Sopenharmony_ci   assert(buf->Ctx == ctx);
1191bf215546Sopenharmony_ci
1192bf215546Sopenharmony_ci   /* Move private non-atomic context references to the global ref count. */
1193bf215546Sopenharmony_ci   p_atomic_add(&buf->RefCount, buf->CtxRefCount);
1194bf215546Sopenharmony_ci   buf->CtxRefCount = 0;
1195bf215546Sopenharmony_ci   buf->Ctx = NULL;
1196bf215546Sopenharmony_ci
1197bf215546Sopenharmony_ci   /* Remove the context reference where the context holds one
1198bf215546Sopenharmony_ci    * reference for the lifetime of the buffer ID to skip refcount
1199bf215546Sopenharmony_ci    * atomics instead of each binding point holding the reference.
1200bf215546Sopenharmony_ci    */
1201bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &buf, NULL);
1202bf215546Sopenharmony_ci}
1203bf215546Sopenharmony_ci
1204bf215546Sopenharmony_ci/**
1205bf215546Sopenharmony_ci * Zombie buffers are buffers that were created by one context and deleted
1206bf215546Sopenharmony_ci * by another context. The creating context holds a global reference for each
1207bf215546Sopenharmony_ci * buffer it created that can't be unreferenced when another context deletes
1208bf215546Sopenharmony_ci * it. Such a buffer becomes a zombie, which means that it's no longer usable
1209bf215546Sopenharmony_ci * by OpenGL, but the creating context still holds its global reference of
1210bf215546Sopenharmony_ci * the buffer. Only the creating context can remove the reference, which is
1211bf215546Sopenharmony_ci * what this function does.
1212bf215546Sopenharmony_ci *
1213bf215546Sopenharmony_ci * For all zombie buffers, decrement the reference count if the current
1214bf215546Sopenharmony_ci * context owns the buffer.
1215bf215546Sopenharmony_ci */
1216bf215546Sopenharmony_cistatic void
1217bf215546Sopenharmony_ciunreference_zombie_buffers_for_ctx(struct gl_context *ctx)
1218bf215546Sopenharmony_ci{
1219bf215546Sopenharmony_ci   /* It's assumed that the mutex of Shared->BufferObjects is locked. */
1220bf215546Sopenharmony_ci   set_foreach(ctx->Shared->ZombieBufferObjects, entry) {
1221bf215546Sopenharmony_ci      struct gl_buffer_object *buf = (struct gl_buffer_object *)entry->key;
1222bf215546Sopenharmony_ci
1223bf215546Sopenharmony_ci      if (buf->Ctx == ctx) {
1224bf215546Sopenharmony_ci         _mesa_set_remove(ctx->Shared->ZombieBufferObjects, entry);
1225bf215546Sopenharmony_ci         detach_ctx_from_buffer(ctx, buf);
1226bf215546Sopenharmony_ci      }
1227bf215546Sopenharmony_ci   }
1228bf215546Sopenharmony_ci}
1229bf215546Sopenharmony_ci
1230bf215546Sopenharmony_ci/**
1231bf215546Sopenharmony_ci * When a context creates buffers, it holds a global buffer reference count
1232bf215546Sopenharmony_ci * for each buffer and doesn't update their RefCount. When the context is
1233bf215546Sopenharmony_ci * destroyed before the buffers are destroyed, the context must remove
1234bf215546Sopenharmony_ci * its global reference from the buffers, so that the buffers can live
1235bf215546Sopenharmony_ci * on their own.
1236bf215546Sopenharmony_ci *
1237bf215546Sopenharmony_ci * At this point, the buffers shouldn't be bound in any bounding point owned
1238bf215546Sopenharmony_ci * by the context. (it would crash if they did)
1239bf215546Sopenharmony_ci */
1240bf215546Sopenharmony_cistatic void
1241bf215546Sopenharmony_cidetach_unrefcounted_buffer_from_ctx(void *data, void *userData)
1242bf215546Sopenharmony_ci{
1243bf215546Sopenharmony_ci   struct gl_context *ctx = (struct gl_context *)userData;
1244bf215546Sopenharmony_ci   struct gl_buffer_object *buf = (struct gl_buffer_object *)data;
1245bf215546Sopenharmony_ci
1246bf215546Sopenharmony_ci   if (buf->Ctx == ctx) {
1247bf215546Sopenharmony_ci      /* Detach the current context from live objects. There should be no
1248bf215546Sopenharmony_ci       * bound buffer in the context at this point, therefore we can just
1249bf215546Sopenharmony_ci       * unreference the global reference. Other contexts and texture objects
1250bf215546Sopenharmony_ci       * might still be using the buffer.
1251bf215546Sopenharmony_ci       */
1252bf215546Sopenharmony_ci      assert(buf->CtxRefCount == 0);
1253bf215546Sopenharmony_ci      buf->Ctx = NULL;
1254bf215546Sopenharmony_ci      _mesa_reference_buffer_object(ctx, &buf, NULL);
1255bf215546Sopenharmony_ci   }
1256bf215546Sopenharmony_ci}
1257bf215546Sopenharmony_ci
1258bf215546Sopenharmony_civoid
1259bf215546Sopenharmony_ci_mesa_free_buffer_objects( struct gl_context *ctx )
1260bf215546Sopenharmony_ci{
1261bf215546Sopenharmony_ci   GLuint i;
1262bf215546Sopenharmony_ci
1263bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL);
1264bf215546Sopenharmony_ci
1265bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, NULL);
1266bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, NULL);
1267bf215546Sopenharmony_ci
1268bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, NULL);
1269bf215546Sopenharmony_ci
1270bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer, NULL);
1271bf215546Sopenharmony_ci
1272bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, NULL);
1273bf215546Sopenharmony_ci
1274bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &ctx->DrawIndirectBuffer, NULL);
1275bf215546Sopenharmony_ci
1276bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &ctx->ParameterBuffer, NULL);
1277bf215546Sopenharmony_ci
1278bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &ctx->DispatchIndirectBuffer, NULL);
1279bf215546Sopenharmony_ci
1280bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &ctx->QueryBuffer, NULL);
1281bf215546Sopenharmony_ci
1282bf215546Sopenharmony_ci   for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) {
1283bf215546Sopenharmony_ci      _mesa_reference_buffer_object(ctx,
1284bf215546Sopenharmony_ci				    &ctx->UniformBufferBindings[i].BufferObject,
1285bf215546Sopenharmony_ci				    NULL);
1286bf215546Sopenharmony_ci   }
1287bf215546Sopenharmony_ci
1288bf215546Sopenharmony_ci   for (i = 0; i < MAX_COMBINED_SHADER_STORAGE_BUFFERS; i++) {
1289bf215546Sopenharmony_ci      _mesa_reference_buffer_object(ctx,
1290bf215546Sopenharmony_ci                                    &ctx->ShaderStorageBufferBindings[i].BufferObject,
1291bf215546Sopenharmony_ci                                    NULL);
1292bf215546Sopenharmony_ci   }
1293bf215546Sopenharmony_ci
1294bf215546Sopenharmony_ci   for (i = 0; i < MAX_COMBINED_ATOMIC_BUFFERS; i++) {
1295bf215546Sopenharmony_ci      _mesa_reference_buffer_object(ctx,
1296bf215546Sopenharmony_ci				    &ctx->AtomicBufferBindings[i].BufferObject,
1297bf215546Sopenharmony_ci				    NULL);
1298bf215546Sopenharmony_ci   }
1299bf215546Sopenharmony_ci
1300bf215546Sopenharmony_ci   _mesa_HashLockMutex(ctx->Shared->BufferObjects);
1301bf215546Sopenharmony_ci   unreference_zombie_buffers_for_ctx(ctx);
1302bf215546Sopenharmony_ci   _mesa_HashWalkLocked(ctx->Shared->BufferObjects,
1303bf215546Sopenharmony_ci                        detach_unrefcounted_buffer_from_ctx, ctx);
1304bf215546Sopenharmony_ci   _mesa_HashUnlockMutex(ctx->Shared->BufferObjects);
1305bf215546Sopenharmony_ci}
1306bf215546Sopenharmony_ci
1307bf215546Sopenharmony_cistruct gl_buffer_object *
1308bf215546Sopenharmony_ci_mesa_bufferobj_alloc(struct gl_context *ctx, GLuint id)
1309bf215546Sopenharmony_ci{
1310bf215546Sopenharmony_ci   struct gl_buffer_object *buf = CALLOC_STRUCT(gl_buffer_object);
1311bf215546Sopenharmony_ci   if (!buf)
1312bf215546Sopenharmony_ci      return NULL;
1313bf215546Sopenharmony_ci
1314bf215546Sopenharmony_ci   buf->RefCount = 1;
1315bf215546Sopenharmony_ci   buf->Name = id;
1316bf215546Sopenharmony_ci   buf->Usage = GL_STATIC_DRAW_ARB;
1317bf215546Sopenharmony_ci
1318bf215546Sopenharmony_ci   simple_mtx_init(&buf->MinMaxCacheMutex, mtx_plain);
1319bf215546Sopenharmony_ci   if (get_no_minmax_cache())
1320bf215546Sopenharmony_ci      buf->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
1321bf215546Sopenharmony_ci   return buf;
1322bf215546Sopenharmony_ci}
1323bf215546Sopenharmony_ci/**
1324bf215546Sopenharmony_ci * Create a buffer object that will be backed by an OpenGL buffer ID
1325bf215546Sopenharmony_ci * where the creating context will hold one global buffer reference instead
1326bf215546Sopenharmony_ci * of updating buffer RefCount for every binding point.
1327bf215546Sopenharmony_ci *
1328bf215546Sopenharmony_ci * This shouldn't be used for internal buffers.
1329bf215546Sopenharmony_ci */
1330bf215546Sopenharmony_cistatic struct gl_buffer_object *
1331bf215546Sopenharmony_cinew_gl_buffer_object(struct gl_context *ctx, GLuint id)
1332bf215546Sopenharmony_ci{
1333bf215546Sopenharmony_ci   struct gl_buffer_object *buf = _mesa_bufferobj_alloc(ctx, id);
1334bf215546Sopenharmony_ci
1335bf215546Sopenharmony_ci   buf->Ctx = ctx;
1336bf215546Sopenharmony_ci   buf->RefCount++; /* global buffer reference held by the context */
1337bf215546Sopenharmony_ci   return buf;
1338bf215546Sopenharmony_ci}
1339bf215546Sopenharmony_ci
1340bf215546Sopenharmony_cibool
1341bf215546Sopenharmony_ci_mesa_handle_bind_buffer_gen(struct gl_context *ctx,
1342bf215546Sopenharmony_ci                             GLuint buffer,
1343bf215546Sopenharmony_ci                             struct gl_buffer_object **buf_handle,
1344bf215546Sopenharmony_ci                             const char *caller, bool no_error)
1345bf215546Sopenharmony_ci{
1346bf215546Sopenharmony_ci   struct gl_buffer_object *buf = *buf_handle;
1347bf215546Sopenharmony_ci
1348bf215546Sopenharmony_ci   if (!no_error && !buf && (ctx->API == API_OPENGL_CORE)) {
1349bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", caller);
1350bf215546Sopenharmony_ci      return false;
1351bf215546Sopenharmony_ci   }
1352bf215546Sopenharmony_ci
1353bf215546Sopenharmony_ci   if (!buf || buf == &DummyBufferObject) {
1354bf215546Sopenharmony_ci      /* If this is a new buffer object id, or one which was generated but
1355bf215546Sopenharmony_ci       * never used before, allocate a buffer object now.
1356bf215546Sopenharmony_ci       */
1357bf215546Sopenharmony_ci      *buf_handle = new_gl_buffer_object(ctx, buffer);
1358bf215546Sopenharmony_ci      if (!*buf_handle) {
1359bf215546Sopenharmony_ci	 _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller);
1360bf215546Sopenharmony_ci	 return false;
1361bf215546Sopenharmony_ci      }
1362bf215546Sopenharmony_ci      _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects,
1363bf215546Sopenharmony_ci                                ctx->BufferObjectsLocked);
1364bf215546Sopenharmony_ci      _mesa_HashInsertLocked(ctx->Shared->BufferObjects, buffer,
1365bf215546Sopenharmony_ci                             *buf_handle, buf != NULL);
1366bf215546Sopenharmony_ci      /* If one context only creates buffers and another context only deletes
1367bf215546Sopenharmony_ci       * buffers, buffers don't get released because it only produces zombie
1368bf215546Sopenharmony_ci       * buffers. Only the context that has created the buffers can release
1369bf215546Sopenharmony_ci       * them. Thus, when we create buffers, we prune the list of zombie
1370bf215546Sopenharmony_ci       * buffers.
1371bf215546Sopenharmony_ci       */
1372bf215546Sopenharmony_ci      unreference_zombie_buffers_for_ctx(ctx);
1373bf215546Sopenharmony_ci      _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects,
1374bf215546Sopenharmony_ci                                  ctx->BufferObjectsLocked);
1375bf215546Sopenharmony_ci   }
1376bf215546Sopenharmony_ci
1377bf215546Sopenharmony_ci   return true;
1378bf215546Sopenharmony_ci}
1379bf215546Sopenharmony_ci
1380bf215546Sopenharmony_ci/**
1381bf215546Sopenharmony_ci * Bind the specified target to buffer for the specified context.
1382bf215546Sopenharmony_ci * Called by glBindBuffer() and other functions.
1383bf215546Sopenharmony_ci */
1384bf215546Sopenharmony_cistatic void
1385bf215546Sopenharmony_cibind_buffer_object(struct gl_context *ctx,
1386bf215546Sopenharmony_ci                   struct gl_buffer_object **bindTarget, GLuint buffer,
1387bf215546Sopenharmony_ci                   bool no_error)
1388bf215546Sopenharmony_ci{
1389bf215546Sopenharmony_ci   struct gl_buffer_object *oldBufObj;
1390bf215546Sopenharmony_ci   struct gl_buffer_object *newBufObj = NULL;
1391bf215546Sopenharmony_ci
1392bf215546Sopenharmony_ci   assert(bindTarget);
1393bf215546Sopenharmony_ci
1394bf215546Sopenharmony_ci   /* Get pointer to old buffer object (to be unbound) */
1395bf215546Sopenharmony_ci   oldBufObj = *bindTarget;
1396bf215546Sopenharmony_ci   if ((oldBufObj && oldBufObj->Name == buffer && !oldBufObj->DeletePending) ||
1397bf215546Sopenharmony_ci       (!oldBufObj && buffer == 0))
1398bf215546Sopenharmony_ci      return;   /* rebinding the same buffer object- no change */
1399bf215546Sopenharmony_ci
1400bf215546Sopenharmony_ci   /*
1401bf215546Sopenharmony_ci    * Get pointer to new buffer object (newBufObj)
1402bf215546Sopenharmony_ci    */
1403bf215546Sopenharmony_ci   if (buffer != 0) {
1404bf215546Sopenharmony_ci      /* non-default buffer object */
1405bf215546Sopenharmony_ci      newBufObj = _mesa_lookup_bufferobj(ctx, buffer);
1406bf215546Sopenharmony_ci      if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
1407bf215546Sopenharmony_ci                                        &newBufObj, "glBindBuffer",
1408bf215546Sopenharmony_ci                                        no_error))
1409bf215546Sopenharmony_ci         return;
1410bf215546Sopenharmony_ci   }
1411bf215546Sopenharmony_ci
1412bf215546Sopenharmony_ci   /* bind new buffer */
1413bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, bindTarget, newBufObj);
1414bf215546Sopenharmony_ci}
1415bf215546Sopenharmony_ci
1416bf215546Sopenharmony_ci
1417bf215546Sopenharmony_ci/**
1418bf215546Sopenharmony_ci * Update the default buffer objects in the given context to reference those
1419bf215546Sopenharmony_ci * specified in the shared state and release those referencing the old
1420bf215546Sopenharmony_ci * shared state.
1421bf215546Sopenharmony_ci */
1422bf215546Sopenharmony_civoid
1423bf215546Sopenharmony_ci_mesa_update_default_objects_buffer_objects(struct gl_context *ctx)
1424bf215546Sopenharmony_ci{
1425bf215546Sopenharmony_ci   /* Bind 0 to remove references to those in the shared context hash table. */
1426bf215546Sopenharmony_ci   bind_buffer_object(ctx, &ctx->Array.ArrayBufferObj, 0, false);
1427bf215546Sopenharmony_ci   bind_buffer_object(ctx, &ctx->Array.VAO->IndexBufferObj, 0, false);
1428bf215546Sopenharmony_ci   bind_buffer_object(ctx, &ctx->Pack.BufferObj, 0, false);
1429bf215546Sopenharmony_ci   bind_buffer_object(ctx, &ctx->Unpack.BufferObj, 0, false);
1430bf215546Sopenharmony_ci}
1431bf215546Sopenharmony_ci
1432bf215546Sopenharmony_ci
1433bf215546Sopenharmony_ci
1434bf215546Sopenharmony_ci/**
1435bf215546Sopenharmony_ci * Return the gl_buffer_object for the given ID.
1436bf215546Sopenharmony_ci * Always return NULL for ID 0.
1437bf215546Sopenharmony_ci */
1438bf215546Sopenharmony_cistruct gl_buffer_object *
1439bf215546Sopenharmony_ci_mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer)
1440bf215546Sopenharmony_ci{
1441bf215546Sopenharmony_ci   if (buffer == 0)
1442bf215546Sopenharmony_ci      return NULL;
1443bf215546Sopenharmony_ci   else
1444bf215546Sopenharmony_ci      return (struct gl_buffer_object *)
1445bf215546Sopenharmony_ci         _mesa_HashLookupMaybeLocked(ctx->Shared->BufferObjects, buffer,
1446bf215546Sopenharmony_ci                                     ctx->BufferObjectsLocked);
1447bf215546Sopenharmony_ci}
1448bf215546Sopenharmony_ci
1449bf215546Sopenharmony_ci
1450bf215546Sopenharmony_cistruct gl_buffer_object *
1451bf215546Sopenharmony_ci_mesa_lookup_bufferobj_locked(struct gl_context *ctx, GLuint buffer)
1452bf215546Sopenharmony_ci{
1453bf215546Sopenharmony_ci   if (buffer == 0)
1454bf215546Sopenharmony_ci      return NULL;
1455bf215546Sopenharmony_ci   else
1456bf215546Sopenharmony_ci      return (struct gl_buffer_object *)
1457bf215546Sopenharmony_ci         _mesa_HashLookupLocked(ctx->Shared->BufferObjects, buffer);
1458bf215546Sopenharmony_ci}
1459bf215546Sopenharmony_ci
1460bf215546Sopenharmony_ci/**
1461bf215546Sopenharmony_ci * A convenience function for direct state access functions that throws
1462bf215546Sopenharmony_ci * GL_INVALID_OPERATION if buffer is not the name of an existing
1463bf215546Sopenharmony_ci * buffer object.
1464bf215546Sopenharmony_ci */
1465bf215546Sopenharmony_cistruct gl_buffer_object *
1466bf215546Sopenharmony_ci_mesa_lookup_bufferobj_err(struct gl_context *ctx, GLuint buffer,
1467bf215546Sopenharmony_ci                           const char *caller)
1468bf215546Sopenharmony_ci{
1469bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
1470bf215546Sopenharmony_ci
1471bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
1472bf215546Sopenharmony_ci   if (!bufObj || bufObj == &DummyBufferObject) {
1473bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
1474bf215546Sopenharmony_ci                  "%s(non-existent buffer object %u)", caller, buffer);
1475bf215546Sopenharmony_ci      return NULL;
1476bf215546Sopenharmony_ci   }
1477bf215546Sopenharmony_ci
1478bf215546Sopenharmony_ci   return bufObj;
1479bf215546Sopenharmony_ci}
1480bf215546Sopenharmony_ci
1481bf215546Sopenharmony_ci
1482bf215546Sopenharmony_ci/**
1483bf215546Sopenharmony_ci * Look up a buffer object for a multi-bind function.
1484bf215546Sopenharmony_ci *
1485bf215546Sopenharmony_ci * Unlike _mesa_lookup_bufferobj(), this function also takes care
1486bf215546Sopenharmony_ci * of generating an error if the buffer ID is not zero or the name
1487bf215546Sopenharmony_ci * of an existing buffer object.
1488bf215546Sopenharmony_ci *
1489bf215546Sopenharmony_ci * If the buffer ID refers to an existing buffer object, a pointer
1490bf215546Sopenharmony_ci * to the buffer object is returned.  If the ID is zero, NULL is returned.
1491bf215546Sopenharmony_ci * If the ID is not zero and does not refer to a valid buffer object, this
1492bf215546Sopenharmony_ci * function returns NULL.
1493bf215546Sopenharmony_ci *
1494bf215546Sopenharmony_ci * This function assumes that the caller has already locked the
1495bf215546Sopenharmony_ci * hash table mutex by calling
1496bf215546Sopenharmony_ci * _mesa_HashLockMutex(ctx->Shared->BufferObjects).
1497bf215546Sopenharmony_ci */
1498bf215546Sopenharmony_cistruct gl_buffer_object *
1499bf215546Sopenharmony_ci_mesa_multi_bind_lookup_bufferobj(struct gl_context *ctx,
1500bf215546Sopenharmony_ci                                  const GLuint *buffers,
1501bf215546Sopenharmony_ci                                  GLuint index, const char *caller,
1502bf215546Sopenharmony_ci                                  bool *error)
1503bf215546Sopenharmony_ci{
1504bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj = NULL;
1505bf215546Sopenharmony_ci
1506bf215546Sopenharmony_ci   *error = false;
1507bf215546Sopenharmony_ci
1508bf215546Sopenharmony_ci   if (buffers[index] != 0) {
1509bf215546Sopenharmony_ci      bufObj = _mesa_lookup_bufferobj_locked(ctx, buffers[index]);
1510bf215546Sopenharmony_ci
1511bf215546Sopenharmony_ci      /* The multi-bind functions don't create the buffer objects
1512bf215546Sopenharmony_ci         when they don't exist. */
1513bf215546Sopenharmony_ci      if (bufObj == &DummyBufferObject)
1514bf215546Sopenharmony_ci         bufObj = NULL;
1515bf215546Sopenharmony_ci
1516bf215546Sopenharmony_ci      if (!bufObj) {
1517bf215546Sopenharmony_ci         /* The ARB_multi_bind spec says:
1518bf215546Sopenharmony_ci          *
1519bf215546Sopenharmony_ci          *    "An INVALID_OPERATION error is generated if any value
1520bf215546Sopenharmony_ci          *     in <buffers> is not zero or the name of an existing
1521bf215546Sopenharmony_ci          *     buffer object (per binding)."
1522bf215546Sopenharmony_ci          */
1523bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
1524bf215546Sopenharmony_ci                     "%s(buffers[%u]=%u is not zero or the name "
1525bf215546Sopenharmony_ci                     "of an existing buffer object)",
1526bf215546Sopenharmony_ci                     caller, index, buffers[index]);
1527bf215546Sopenharmony_ci         *error = true;
1528bf215546Sopenharmony_ci      }
1529bf215546Sopenharmony_ci   }
1530bf215546Sopenharmony_ci
1531bf215546Sopenharmony_ci   return bufObj;
1532bf215546Sopenharmony_ci}
1533bf215546Sopenharmony_ci
1534bf215546Sopenharmony_ci
1535bf215546Sopenharmony_ci/**
1536bf215546Sopenharmony_ci * If *ptr points to obj, set ptr = the Null/default buffer object.
1537bf215546Sopenharmony_ci * This is a helper for buffer object deletion.
1538bf215546Sopenharmony_ci * The GL spec says that deleting a buffer object causes it to get
1539bf215546Sopenharmony_ci * unbound from all arrays in the current context.
1540bf215546Sopenharmony_ci */
1541bf215546Sopenharmony_cistatic void
1542bf215546Sopenharmony_ciunbind(struct gl_context *ctx,
1543bf215546Sopenharmony_ci       struct gl_vertex_array_object *vao, unsigned index,
1544bf215546Sopenharmony_ci       struct gl_buffer_object *obj)
1545bf215546Sopenharmony_ci{
1546bf215546Sopenharmony_ci   if (vao->BufferBinding[index].BufferObj == obj) {
1547bf215546Sopenharmony_ci      _mesa_bind_vertex_buffer(ctx, vao, index, NULL,
1548bf215546Sopenharmony_ci                               vao->BufferBinding[index].Offset,
1549bf215546Sopenharmony_ci                               vao->BufferBinding[index].Stride, true, false);
1550bf215546Sopenharmony_ci   }
1551bf215546Sopenharmony_ci}
1552bf215546Sopenharmony_ci
1553bf215546Sopenharmony_civoid
1554bf215546Sopenharmony_ci_mesa_buffer_unmap_all_mappings(struct gl_context *ctx,
1555bf215546Sopenharmony_ci                                struct gl_buffer_object *bufObj)
1556bf215546Sopenharmony_ci{
1557bf215546Sopenharmony_ci   for (int i = 0; i < MAP_COUNT; i++) {
1558bf215546Sopenharmony_ci      if (_mesa_bufferobj_mapped(bufObj, i)) {
1559bf215546Sopenharmony_ci         _mesa_bufferobj_unmap(ctx, bufObj, i);
1560bf215546Sopenharmony_ci         assert(bufObj->Mappings[i].Pointer == NULL);
1561bf215546Sopenharmony_ci         bufObj->Mappings[i].AccessFlags = 0;
1562bf215546Sopenharmony_ci      }
1563bf215546Sopenharmony_ci   }
1564bf215546Sopenharmony_ci}
1565bf215546Sopenharmony_ci
1566bf215546Sopenharmony_ci
1567bf215546Sopenharmony_ci/**********************************************************************/
1568bf215546Sopenharmony_ci/* API Functions                                                      */
1569bf215546Sopenharmony_ci/**********************************************************************/
1570bf215546Sopenharmony_ci
1571bf215546Sopenharmony_civoid GLAPIENTRY
1572bf215546Sopenharmony_ci_mesa_BindBuffer_no_error(GLenum target, GLuint buffer)
1573bf215546Sopenharmony_ci{
1574bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1575bf215546Sopenharmony_ci
1576bf215546Sopenharmony_ci   struct gl_buffer_object **bindTarget = get_buffer_target(ctx, target);
1577bf215546Sopenharmony_ci   bind_buffer_object(ctx, bindTarget, buffer, true);
1578bf215546Sopenharmony_ci}
1579bf215546Sopenharmony_ci
1580bf215546Sopenharmony_ci
1581bf215546Sopenharmony_civoid GLAPIENTRY
1582bf215546Sopenharmony_ci_mesa_BindBuffer(GLenum target, GLuint buffer)
1583bf215546Sopenharmony_ci{
1584bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1585bf215546Sopenharmony_ci
1586bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API) {
1587bf215546Sopenharmony_ci      _mesa_debug(ctx, "glBindBuffer(%s, %u)\n",
1588bf215546Sopenharmony_ci                  _mesa_enum_to_string(target), buffer);
1589bf215546Sopenharmony_ci   }
1590bf215546Sopenharmony_ci
1591bf215546Sopenharmony_ci   struct gl_buffer_object **bindTarget = get_buffer_target(ctx, target);
1592bf215546Sopenharmony_ci   if (!bindTarget) {
1593bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target %s)",
1594bf215546Sopenharmony_ci                  _mesa_enum_to_string(target));
1595bf215546Sopenharmony_ci      return;
1596bf215546Sopenharmony_ci   }
1597bf215546Sopenharmony_ci
1598bf215546Sopenharmony_ci   bind_buffer_object(ctx, bindTarget, buffer, false);
1599bf215546Sopenharmony_ci}
1600bf215546Sopenharmony_ci
1601bf215546Sopenharmony_civoid
1602bf215546Sopenharmony_ci_mesa_InternalBindElementBuffer(struct gl_context *ctx,
1603bf215546Sopenharmony_ci                                struct gl_buffer_object *buf)
1604bf215546Sopenharmony_ci{
1605bf215546Sopenharmony_ci   struct gl_buffer_object **bindTarget =
1606bf215546Sopenharmony_ci      get_buffer_target(ctx, GL_ELEMENT_ARRAY_BUFFER);
1607bf215546Sopenharmony_ci
1608bf215546Sopenharmony_ci   /* Move the buffer reference from the parameter to the bind point. */
1609bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, bindTarget, NULL);
1610bf215546Sopenharmony_ci   if (buf)
1611bf215546Sopenharmony_ci      *bindTarget = buf;
1612bf215546Sopenharmony_ci}
1613bf215546Sopenharmony_ci
1614bf215546Sopenharmony_ci/**
1615bf215546Sopenharmony_ci * Binds a buffer object to a binding point.
1616bf215546Sopenharmony_ci *
1617bf215546Sopenharmony_ci * The caller is responsible for validating the offset,
1618bf215546Sopenharmony_ci * flushing the vertices and updating NewDriverState.
1619bf215546Sopenharmony_ci */
1620bf215546Sopenharmony_cistatic void
1621bf215546Sopenharmony_ciset_buffer_binding(struct gl_context *ctx,
1622bf215546Sopenharmony_ci                   struct gl_buffer_binding *binding,
1623bf215546Sopenharmony_ci                   struct gl_buffer_object *bufObj,
1624bf215546Sopenharmony_ci                   GLintptr offset,
1625bf215546Sopenharmony_ci                   GLsizeiptr size,
1626bf215546Sopenharmony_ci                   bool autoSize, gl_buffer_usage usage)
1627bf215546Sopenharmony_ci{
1628bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj);
1629bf215546Sopenharmony_ci
1630bf215546Sopenharmony_ci   binding->Offset = offset;
1631bf215546Sopenharmony_ci   binding->Size = size;
1632bf215546Sopenharmony_ci   binding->AutomaticSize = autoSize;
1633bf215546Sopenharmony_ci
1634bf215546Sopenharmony_ci   /* If this is a real buffer object, mark it has having been used
1635bf215546Sopenharmony_ci    * at some point as an atomic counter buffer.
1636bf215546Sopenharmony_ci    */
1637bf215546Sopenharmony_ci   if (size >= 0)
1638bf215546Sopenharmony_ci      bufObj->UsageHistory |= usage;
1639bf215546Sopenharmony_ci}
1640bf215546Sopenharmony_ci
1641bf215546Sopenharmony_cistatic void
1642bf215546Sopenharmony_ciset_buffer_multi_binding(struct gl_context *ctx,
1643bf215546Sopenharmony_ci                         const GLuint *buffers,
1644bf215546Sopenharmony_ci                         int idx,
1645bf215546Sopenharmony_ci                         const char *caller,
1646bf215546Sopenharmony_ci                         struct gl_buffer_binding *binding,
1647bf215546Sopenharmony_ci                         GLintptr offset,
1648bf215546Sopenharmony_ci                         GLsizeiptr size,
1649bf215546Sopenharmony_ci                         bool range,
1650bf215546Sopenharmony_ci                         gl_buffer_usage usage)
1651bf215546Sopenharmony_ci{
1652bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
1653bf215546Sopenharmony_ci
1654bf215546Sopenharmony_ci   if (binding->BufferObject && binding->BufferObject->Name == buffers[idx])
1655bf215546Sopenharmony_ci      bufObj = binding->BufferObject;
1656bf215546Sopenharmony_ci   else {
1657bf215546Sopenharmony_ci      bool error;
1658bf215546Sopenharmony_ci      bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, idx, caller,
1659bf215546Sopenharmony_ci                                                 &error);
1660bf215546Sopenharmony_ci      if (error)
1661bf215546Sopenharmony_ci         return;
1662bf215546Sopenharmony_ci   }
1663bf215546Sopenharmony_ci
1664bf215546Sopenharmony_ci   if (!bufObj)
1665bf215546Sopenharmony_ci      set_buffer_binding(ctx, binding, bufObj, -1, -1, !range, usage);
1666bf215546Sopenharmony_ci   else
1667bf215546Sopenharmony_ci      set_buffer_binding(ctx, binding, bufObj, offset, size, !range, usage);
1668bf215546Sopenharmony_ci}
1669bf215546Sopenharmony_ci
1670bf215546Sopenharmony_cistatic void
1671bf215546Sopenharmony_cibind_buffer(struct gl_context *ctx,
1672bf215546Sopenharmony_ci            struct gl_buffer_binding *binding,
1673bf215546Sopenharmony_ci            struct gl_buffer_object *bufObj,
1674bf215546Sopenharmony_ci            GLintptr offset,
1675bf215546Sopenharmony_ci            GLsizeiptr size,
1676bf215546Sopenharmony_ci            GLboolean autoSize,
1677bf215546Sopenharmony_ci            uint64_t driver_state,
1678bf215546Sopenharmony_ci            gl_buffer_usage usage)
1679bf215546Sopenharmony_ci{
1680bf215546Sopenharmony_ci   if (binding->BufferObject == bufObj &&
1681bf215546Sopenharmony_ci       binding->Offset == offset &&
1682bf215546Sopenharmony_ci       binding->Size == size &&
1683bf215546Sopenharmony_ci       binding->AutomaticSize == autoSize) {
1684bf215546Sopenharmony_ci      return;
1685bf215546Sopenharmony_ci   }
1686bf215546Sopenharmony_ci
1687bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, 0, 0);
1688bf215546Sopenharmony_ci   ctx->NewDriverState |= driver_state;
1689bf215546Sopenharmony_ci
1690bf215546Sopenharmony_ci   set_buffer_binding(ctx, binding, bufObj, offset, size, autoSize, usage);
1691bf215546Sopenharmony_ci}
1692bf215546Sopenharmony_ci
1693bf215546Sopenharmony_ci/**
1694bf215546Sopenharmony_ci * Binds a buffer object to a uniform buffer binding point.
1695bf215546Sopenharmony_ci *
1696bf215546Sopenharmony_ci * Unlike set_buffer_binding(), this function also flushes vertices
1697bf215546Sopenharmony_ci * and updates NewDriverState.  It also checks if the binding
1698bf215546Sopenharmony_ci * has actually changed before updating it.
1699bf215546Sopenharmony_ci */
1700bf215546Sopenharmony_cistatic void
1701bf215546Sopenharmony_cibind_uniform_buffer(struct gl_context *ctx,
1702bf215546Sopenharmony_ci                    GLuint index,
1703bf215546Sopenharmony_ci                    struct gl_buffer_object *bufObj,
1704bf215546Sopenharmony_ci                    GLintptr offset,
1705bf215546Sopenharmony_ci                    GLsizeiptr size,
1706bf215546Sopenharmony_ci                    GLboolean autoSize)
1707bf215546Sopenharmony_ci{
1708bf215546Sopenharmony_ci   bind_buffer(ctx, &ctx->UniformBufferBindings[index],
1709bf215546Sopenharmony_ci               bufObj, offset, size, autoSize,
1710bf215546Sopenharmony_ci               ST_NEW_UNIFORM_BUFFER,
1711bf215546Sopenharmony_ci               USAGE_UNIFORM_BUFFER);
1712bf215546Sopenharmony_ci}
1713bf215546Sopenharmony_ci
1714bf215546Sopenharmony_ci/**
1715bf215546Sopenharmony_ci * Binds a buffer object to a shader storage buffer binding point.
1716bf215546Sopenharmony_ci *
1717bf215546Sopenharmony_ci * Unlike set_ssbo_binding(), this function also flushes vertices
1718bf215546Sopenharmony_ci * and updates NewDriverState.  It also checks if the binding
1719bf215546Sopenharmony_ci * has actually changed before updating it.
1720bf215546Sopenharmony_ci */
1721bf215546Sopenharmony_cistatic void
1722bf215546Sopenharmony_cibind_shader_storage_buffer(struct gl_context *ctx,
1723bf215546Sopenharmony_ci                           GLuint index,
1724bf215546Sopenharmony_ci                           struct gl_buffer_object *bufObj,
1725bf215546Sopenharmony_ci                           GLintptr offset,
1726bf215546Sopenharmony_ci                           GLsizeiptr size,
1727bf215546Sopenharmony_ci                           GLboolean autoSize)
1728bf215546Sopenharmony_ci{
1729bf215546Sopenharmony_ci   bind_buffer(ctx, &ctx->ShaderStorageBufferBindings[index],
1730bf215546Sopenharmony_ci               bufObj, offset, size, autoSize,
1731bf215546Sopenharmony_ci               ST_NEW_STORAGE_BUFFER,
1732bf215546Sopenharmony_ci               USAGE_SHADER_STORAGE_BUFFER);
1733bf215546Sopenharmony_ci}
1734bf215546Sopenharmony_ci
1735bf215546Sopenharmony_ci/**
1736bf215546Sopenharmony_ci * Binds a buffer object to an atomic buffer binding point.
1737bf215546Sopenharmony_ci *
1738bf215546Sopenharmony_ci * Unlike set_atomic_binding(), this function also flushes vertices
1739bf215546Sopenharmony_ci * and updates NewDriverState.  It also checks if the binding
1740bf215546Sopenharmony_ci * has actually changed before updating it.
1741bf215546Sopenharmony_ci */
1742bf215546Sopenharmony_cistatic void
1743bf215546Sopenharmony_cibind_atomic_buffer(struct gl_context *ctx, unsigned index,
1744bf215546Sopenharmony_ci                   struct gl_buffer_object *bufObj, GLintptr offset,
1745bf215546Sopenharmony_ci                   GLsizeiptr size, GLboolean autoSize)
1746bf215546Sopenharmony_ci{
1747bf215546Sopenharmony_ci   bind_buffer(ctx, &ctx->AtomicBufferBindings[index],
1748bf215546Sopenharmony_ci               bufObj, offset, size, autoSize,
1749bf215546Sopenharmony_ci               ctx->DriverFlags.NewAtomicBuffer,
1750bf215546Sopenharmony_ci               USAGE_ATOMIC_COUNTER_BUFFER);
1751bf215546Sopenharmony_ci}
1752bf215546Sopenharmony_ci
1753bf215546Sopenharmony_ci/**
1754bf215546Sopenharmony_ci * Bind a buffer object to a uniform block binding point.
1755bf215546Sopenharmony_ci * As above, but offset = 0.
1756bf215546Sopenharmony_ci */
1757bf215546Sopenharmony_cistatic void
1758bf215546Sopenharmony_cibind_buffer_base_uniform_buffer(struct gl_context *ctx,
1759bf215546Sopenharmony_ci				GLuint index,
1760bf215546Sopenharmony_ci				struct gl_buffer_object *bufObj)
1761bf215546Sopenharmony_ci{
1762bf215546Sopenharmony_ci   if (index >= ctx->Const.MaxUniformBufferBindings) {
1763bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index);
1764bf215546Sopenharmony_ci      return;
1765bf215546Sopenharmony_ci   }
1766bf215546Sopenharmony_ci
1767bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj);
1768bf215546Sopenharmony_ci
1769bf215546Sopenharmony_ci   if (!bufObj)
1770bf215546Sopenharmony_ci      bind_uniform_buffer(ctx, index, bufObj, -1, -1, GL_TRUE);
1771bf215546Sopenharmony_ci   else
1772bf215546Sopenharmony_ci      bind_uniform_buffer(ctx, index, bufObj, 0, 0, GL_TRUE);
1773bf215546Sopenharmony_ci}
1774bf215546Sopenharmony_ci
1775bf215546Sopenharmony_ci/**
1776bf215546Sopenharmony_ci * Bind a buffer object to a shader storage block binding point.
1777bf215546Sopenharmony_ci * As above, but offset = 0.
1778bf215546Sopenharmony_ci */
1779bf215546Sopenharmony_cistatic void
1780bf215546Sopenharmony_cibind_buffer_base_shader_storage_buffer(struct gl_context *ctx,
1781bf215546Sopenharmony_ci                                       GLuint index,
1782bf215546Sopenharmony_ci                                       struct gl_buffer_object *bufObj)
1783bf215546Sopenharmony_ci{
1784bf215546Sopenharmony_ci   if (index >= ctx->Const.MaxShaderStorageBufferBindings) {
1785bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index);
1786bf215546Sopenharmony_ci      return;
1787bf215546Sopenharmony_ci   }
1788bf215546Sopenharmony_ci
1789bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer, bufObj);
1790bf215546Sopenharmony_ci
1791bf215546Sopenharmony_ci   if (!bufObj)
1792bf215546Sopenharmony_ci      bind_shader_storage_buffer(ctx, index, bufObj, -1, -1, GL_TRUE);
1793bf215546Sopenharmony_ci   else
1794bf215546Sopenharmony_ci      bind_shader_storage_buffer(ctx, index, bufObj, 0, 0, GL_TRUE);
1795bf215546Sopenharmony_ci}
1796bf215546Sopenharmony_ci
1797bf215546Sopenharmony_ci/**
1798bf215546Sopenharmony_ci * Bind a buffer object to a shader storage block binding point.
1799bf215546Sopenharmony_ci * As above, but offset = 0.
1800bf215546Sopenharmony_ci */
1801bf215546Sopenharmony_cistatic void
1802bf215546Sopenharmony_cibind_buffer_base_atomic_buffer(struct gl_context *ctx,
1803bf215546Sopenharmony_ci                               GLuint index,
1804bf215546Sopenharmony_ci                               struct gl_buffer_object *bufObj)
1805bf215546Sopenharmony_ci{
1806bf215546Sopenharmony_ci   if (index >= ctx->Const.MaxAtomicBufferBindings) {
1807bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index);
1808bf215546Sopenharmony_ci      return;
1809bf215546Sopenharmony_ci   }
1810bf215546Sopenharmony_ci
1811bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, bufObj);
1812bf215546Sopenharmony_ci
1813bf215546Sopenharmony_ci   if (!bufObj)
1814bf215546Sopenharmony_ci      bind_atomic_buffer(ctx, index, bufObj, -1, -1, GL_TRUE);
1815bf215546Sopenharmony_ci   else
1816bf215546Sopenharmony_ci      bind_atomic_buffer(ctx, index, bufObj, 0, 0, GL_TRUE);
1817bf215546Sopenharmony_ci}
1818bf215546Sopenharmony_ci
1819bf215546Sopenharmony_ci/**
1820bf215546Sopenharmony_ci * Delete a set of buffer objects.
1821bf215546Sopenharmony_ci *
1822bf215546Sopenharmony_ci * \param n      Number of buffer objects to delete.
1823bf215546Sopenharmony_ci * \param ids    Array of \c n buffer object IDs.
1824bf215546Sopenharmony_ci */
1825bf215546Sopenharmony_cistatic void
1826bf215546Sopenharmony_cidelete_buffers(struct gl_context *ctx, GLsizei n, const GLuint *ids)
1827bf215546Sopenharmony_ci{
1828bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, 0, 0);
1829bf215546Sopenharmony_ci
1830bf215546Sopenharmony_ci   _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects,
1831bf215546Sopenharmony_ci                             ctx->BufferObjectsLocked);
1832bf215546Sopenharmony_ci   unreference_zombie_buffers_for_ctx(ctx);
1833bf215546Sopenharmony_ci
1834bf215546Sopenharmony_ci   for (GLsizei i = 0; i < n; i++) {
1835bf215546Sopenharmony_ci      struct gl_buffer_object *bufObj =
1836bf215546Sopenharmony_ci         _mesa_lookup_bufferobj_locked(ctx, ids[i]);
1837bf215546Sopenharmony_ci      if (bufObj) {
1838bf215546Sopenharmony_ci         struct gl_vertex_array_object *vao = ctx->Array.VAO;
1839bf215546Sopenharmony_ci         GLuint j;
1840bf215546Sopenharmony_ci
1841bf215546Sopenharmony_ci         assert(bufObj->Name == ids[i] || bufObj == &DummyBufferObject);
1842bf215546Sopenharmony_ci
1843bf215546Sopenharmony_ci         _mesa_buffer_unmap_all_mappings(ctx, bufObj);
1844bf215546Sopenharmony_ci
1845bf215546Sopenharmony_ci         /* unbind any vertex pointers bound to this buffer */
1846bf215546Sopenharmony_ci         for (j = 0; j < ARRAY_SIZE(vao->BufferBinding); j++) {
1847bf215546Sopenharmony_ci            unbind(ctx, vao, j, bufObj);
1848bf215546Sopenharmony_ci         }
1849bf215546Sopenharmony_ci
1850bf215546Sopenharmony_ci         if (ctx->Array.ArrayBufferObj == bufObj) {
1851bf215546Sopenharmony_ci            bind_buffer_object(ctx, &ctx->Array.ArrayBufferObj, 0, false);
1852bf215546Sopenharmony_ci         }
1853bf215546Sopenharmony_ci         if (vao->IndexBufferObj == bufObj) {
1854bf215546Sopenharmony_ci            bind_buffer_object(ctx, &vao->IndexBufferObj, 0, false);
1855bf215546Sopenharmony_ci         }
1856bf215546Sopenharmony_ci
1857bf215546Sopenharmony_ci         /* unbind ARB_draw_indirect binding point */
1858bf215546Sopenharmony_ci         if (ctx->DrawIndirectBuffer == bufObj) {
1859bf215546Sopenharmony_ci            bind_buffer_object(ctx, &ctx->DrawIndirectBuffer, 0, false);
1860bf215546Sopenharmony_ci         }
1861bf215546Sopenharmony_ci
1862bf215546Sopenharmony_ci         /* unbind ARB_indirect_parameters binding point */
1863bf215546Sopenharmony_ci         if (ctx->ParameterBuffer == bufObj) {
1864bf215546Sopenharmony_ci            bind_buffer_object(ctx, &ctx->ParameterBuffer, 0, false);
1865bf215546Sopenharmony_ci         }
1866bf215546Sopenharmony_ci
1867bf215546Sopenharmony_ci         /* unbind ARB_compute_shader binding point */
1868bf215546Sopenharmony_ci         if (ctx->DispatchIndirectBuffer == bufObj) {
1869bf215546Sopenharmony_ci            bind_buffer_object(ctx, &ctx->DispatchIndirectBuffer, 0, false);
1870bf215546Sopenharmony_ci         }
1871bf215546Sopenharmony_ci
1872bf215546Sopenharmony_ci         /* unbind ARB_copy_buffer binding points */
1873bf215546Sopenharmony_ci         if (ctx->CopyReadBuffer == bufObj) {
1874bf215546Sopenharmony_ci            bind_buffer_object(ctx, &ctx->CopyReadBuffer, 0, false);
1875bf215546Sopenharmony_ci         }
1876bf215546Sopenharmony_ci         if (ctx->CopyWriteBuffer == bufObj) {
1877bf215546Sopenharmony_ci            bind_buffer_object(ctx, &ctx->CopyWriteBuffer, 0, false);
1878bf215546Sopenharmony_ci         }
1879bf215546Sopenharmony_ci
1880bf215546Sopenharmony_ci         /* unbind transform feedback binding points */
1881bf215546Sopenharmony_ci         if (ctx->TransformFeedback.CurrentBuffer == bufObj) {
1882bf215546Sopenharmony_ci            bind_buffer_object(ctx, &ctx->TransformFeedback.CurrentBuffer, 0, false);
1883bf215546Sopenharmony_ci         }
1884bf215546Sopenharmony_ci         for (j = 0; j < MAX_FEEDBACK_BUFFERS; j++) {
1885bf215546Sopenharmony_ci            if (ctx->TransformFeedback.CurrentObject->Buffers[j] == bufObj) {
1886bf215546Sopenharmony_ci               _mesa_bind_buffer_base_transform_feedback(ctx,
1887bf215546Sopenharmony_ci                                           ctx->TransformFeedback.CurrentObject,
1888bf215546Sopenharmony_ci                                           j, NULL, false);
1889bf215546Sopenharmony_ci            }
1890bf215546Sopenharmony_ci         }
1891bf215546Sopenharmony_ci
1892bf215546Sopenharmony_ci         /* unbind UBO binding points */
1893bf215546Sopenharmony_ci         for (j = 0; j < ctx->Const.MaxUniformBufferBindings; j++) {
1894bf215546Sopenharmony_ci            if (ctx->UniformBufferBindings[j].BufferObject == bufObj) {
1895bf215546Sopenharmony_ci               bind_buffer_base_uniform_buffer(ctx, j, NULL);
1896bf215546Sopenharmony_ci            }
1897bf215546Sopenharmony_ci         }
1898bf215546Sopenharmony_ci
1899bf215546Sopenharmony_ci         if (ctx->UniformBuffer == bufObj) {
1900bf215546Sopenharmony_ci            bind_buffer_object(ctx, &ctx->UniformBuffer, 0, false);
1901bf215546Sopenharmony_ci         }
1902bf215546Sopenharmony_ci
1903bf215546Sopenharmony_ci         /* unbind SSBO binding points */
1904bf215546Sopenharmony_ci         for (j = 0; j < ctx->Const.MaxShaderStorageBufferBindings; j++) {
1905bf215546Sopenharmony_ci            if (ctx->ShaderStorageBufferBindings[j].BufferObject == bufObj) {
1906bf215546Sopenharmony_ci               bind_buffer_base_shader_storage_buffer(ctx, j, NULL);
1907bf215546Sopenharmony_ci            }
1908bf215546Sopenharmony_ci         }
1909bf215546Sopenharmony_ci
1910bf215546Sopenharmony_ci         if (ctx->ShaderStorageBuffer == bufObj) {
1911bf215546Sopenharmony_ci            bind_buffer_object(ctx, &ctx->ShaderStorageBuffer, 0, false);
1912bf215546Sopenharmony_ci         }
1913bf215546Sopenharmony_ci
1914bf215546Sopenharmony_ci         /* unbind Atomci Buffer binding points */
1915bf215546Sopenharmony_ci         for (j = 0; j < ctx->Const.MaxAtomicBufferBindings; j++) {
1916bf215546Sopenharmony_ci            if (ctx->AtomicBufferBindings[j].BufferObject == bufObj) {
1917bf215546Sopenharmony_ci               bind_buffer_base_atomic_buffer(ctx, j, NULL);
1918bf215546Sopenharmony_ci            }
1919bf215546Sopenharmony_ci         }
1920bf215546Sopenharmony_ci
1921bf215546Sopenharmony_ci         if (ctx->AtomicBuffer == bufObj) {
1922bf215546Sopenharmony_ci            bind_buffer_object(ctx, &ctx->AtomicBuffer, 0, false);
1923bf215546Sopenharmony_ci         }
1924bf215546Sopenharmony_ci
1925bf215546Sopenharmony_ci         /* unbind any pixel pack/unpack pointers bound to this buffer */
1926bf215546Sopenharmony_ci         if (ctx->Pack.BufferObj == bufObj) {
1927bf215546Sopenharmony_ci            bind_buffer_object(ctx, &ctx->Pack.BufferObj, 0, false);
1928bf215546Sopenharmony_ci         }
1929bf215546Sopenharmony_ci         if (ctx->Unpack.BufferObj == bufObj) {
1930bf215546Sopenharmony_ci            bind_buffer_object(ctx, &ctx->Unpack.BufferObj, 0, false);
1931bf215546Sopenharmony_ci         }
1932bf215546Sopenharmony_ci
1933bf215546Sopenharmony_ci         if (ctx->Texture.BufferObject == bufObj) {
1934bf215546Sopenharmony_ci            bind_buffer_object(ctx, &ctx->Texture.BufferObject, 0, false);
1935bf215546Sopenharmony_ci         }
1936bf215546Sopenharmony_ci
1937bf215546Sopenharmony_ci         if (ctx->ExternalVirtualMemoryBuffer == bufObj) {
1938bf215546Sopenharmony_ci            bind_buffer_object(ctx, &ctx->ExternalVirtualMemoryBuffer, 0, false);
1939bf215546Sopenharmony_ci         }
1940bf215546Sopenharmony_ci
1941bf215546Sopenharmony_ci         /* unbind query buffer binding point */
1942bf215546Sopenharmony_ci         if (ctx->QueryBuffer == bufObj) {
1943bf215546Sopenharmony_ci            bind_buffer_object(ctx, &ctx->QueryBuffer, 0, false);
1944bf215546Sopenharmony_ci         }
1945bf215546Sopenharmony_ci
1946bf215546Sopenharmony_ci         /* The ID is immediately freed for re-use */
1947bf215546Sopenharmony_ci         _mesa_HashRemoveLocked(ctx->Shared->BufferObjects, ids[i]);
1948bf215546Sopenharmony_ci         /* Make sure we do not run into the classic ABA problem on bind.
1949bf215546Sopenharmony_ci          * We don't want to allow re-binding a buffer object that's been
1950bf215546Sopenharmony_ci          * "deleted" by glDeleteBuffers().
1951bf215546Sopenharmony_ci          *
1952bf215546Sopenharmony_ci          * The explicit rebinding to the default object in the current context
1953bf215546Sopenharmony_ci          * prevents the above in the current context, but another context
1954bf215546Sopenharmony_ci          * sharing the same objects might suffer from this problem.
1955bf215546Sopenharmony_ci          * The alternative would be to do the hash lookup in any case on bind
1956bf215546Sopenharmony_ci          * which would introduce more runtime overhead than this.
1957bf215546Sopenharmony_ci          */
1958bf215546Sopenharmony_ci         bufObj->DeletePending = GL_TRUE;
1959bf215546Sopenharmony_ci
1960bf215546Sopenharmony_ci         /* The GLuint ID holds one reference and the context that created
1961bf215546Sopenharmony_ci          * the buffer holds the other one.
1962bf215546Sopenharmony_ci          */
1963bf215546Sopenharmony_ci         assert(p_atomic_read(&bufObj->RefCount) >= (bufObj->Ctx ? 2 : 1));
1964bf215546Sopenharmony_ci
1965bf215546Sopenharmony_ci         if (bufObj->Ctx == ctx) {
1966bf215546Sopenharmony_ci            detach_ctx_from_buffer(ctx, bufObj);
1967bf215546Sopenharmony_ci         } else if (bufObj->Ctx) {
1968bf215546Sopenharmony_ci            /* Only the context holding it can release it. */
1969bf215546Sopenharmony_ci            _mesa_set_add(ctx->Shared->ZombieBufferObjects, bufObj);
1970bf215546Sopenharmony_ci         }
1971bf215546Sopenharmony_ci
1972bf215546Sopenharmony_ci         _mesa_reference_buffer_object(ctx, &bufObj, NULL);
1973bf215546Sopenharmony_ci      }
1974bf215546Sopenharmony_ci   }
1975bf215546Sopenharmony_ci
1976bf215546Sopenharmony_ci   _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects,
1977bf215546Sopenharmony_ci                               ctx->BufferObjectsLocked);
1978bf215546Sopenharmony_ci}
1979bf215546Sopenharmony_ci
1980bf215546Sopenharmony_ci
1981bf215546Sopenharmony_civoid GLAPIENTRY
1982bf215546Sopenharmony_ci_mesa_DeleteBuffers_no_error(GLsizei n, const GLuint *ids)
1983bf215546Sopenharmony_ci{
1984bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1985bf215546Sopenharmony_ci   delete_buffers(ctx, n, ids);
1986bf215546Sopenharmony_ci}
1987bf215546Sopenharmony_ci
1988bf215546Sopenharmony_ci
1989bf215546Sopenharmony_civoid GLAPIENTRY
1990bf215546Sopenharmony_ci_mesa_DeleteBuffers(GLsizei n, const GLuint *ids)
1991bf215546Sopenharmony_ci{
1992bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1993bf215546Sopenharmony_ci
1994bf215546Sopenharmony_ci   if (n < 0) {
1995bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)");
1996bf215546Sopenharmony_ci      return;
1997bf215546Sopenharmony_ci   }
1998bf215546Sopenharmony_ci
1999bf215546Sopenharmony_ci   delete_buffers(ctx, n, ids);
2000bf215546Sopenharmony_ci}
2001bf215546Sopenharmony_ci
2002bf215546Sopenharmony_ci
2003bf215546Sopenharmony_ci/**
2004bf215546Sopenharmony_ci * This is the implementation for glGenBuffers and glCreateBuffers. It is not
2005bf215546Sopenharmony_ci * exposed to the rest of Mesa to encourage the use of nameless buffers in
2006bf215546Sopenharmony_ci * driver internals.
2007bf215546Sopenharmony_ci */
2008bf215546Sopenharmony_cistatic void
2009bf215546Sopenharmony_cicreate_buffers(struct gl_context *ctx, GLsizei n, GLuint *buffers, bool dsa)
2010bf215546Sopenharmony_ci{
2011bf215546Sopenharmony_ci   struct gl_buffer_object *buf;
2012bf215546Sopenharmony_ci
2013bf215546Sopenharmony_ci   if (!buffers)
2014bf215546Sopenharmony_ci      return;
2015bf215546Sopenharmony_ci
2016bf215546Sopenharmony_ci   /*
2017bf215546Sopenharmony_ci    * This must be atomic (generation and allocation of buffer object IDs)
2018bf215546Sopenharmony_ci    */
2019bf215546Sopenharmony_ci   _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects,
2020bf215546Sopenharmony_ci                             ctx->BufferObjectsLocked);
2021bf215546Sopenharmony_ci   /* If one context only creates buffers and another context only deletes
2022bf215546Sopenharmony_ci    * buffers, buffers don't get released because it only produces zombie
2023bf215546Sopenharmony_ci    * buffers. Only the context that has created the buffers can release
2024bf215546Sopenharmony_ci    * them. Thus, when we create buffers, we prune the list of zombie
2025bf215546Sopenharmony_ci    * buffers.
2026bf215546Sopenharmony_ci    */
2027bf215546Sopenharmony_ci   unreference_zombie_buffers_for_ctx(ctx);
2028bf215546Sopenharmony_ci
2029bf215546Sopenharmony_ci   _mesa_HashFindFreeKeys(ctx->Shared->BufferObjects, buffers, n);
2030bf215546Sopenharmony_ci
2031bf215546Sopenharmony_ci   /* Insert the ID and pointer into the hash table. If non-DSA, insert a
2032bf215546Sopenharmony_ci    * DummyBufferObject.  Otherwise, create a new buffer object and insert
2033bf215546Sopenharmony_ci    * it.
2034bf215546Sopenharmony_ci    */
2035bf215546Sopenharmony_ci   for (int i = 0; i < n; i++) {
2036bf215546Sopenharmony_ci      if (dsa) {
2037bf215546Sopenharmony_ci         buf = new_gl_buffer_object(ctx, buffers[i]);
2038bf215546Sopenharmony_ci         if (!buf) {
2039bf215546Sopenharmony_ci            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCreateBuffers");
2040bf215546Sopenharmony_ci            _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects,
2041bf215546Sopenharmony_ci                                        ctx->BufferObjectsLocked);
2042bf215546Sopenharmony_ci            return;
2043bf215546Sopenharmony_ci         }
2044bf215546Sopenharmony_ci      }
2045bf215546Sopenharmony_ci      else
2046bf215546Sopenharmony_ci         buf = &DummyBufferObject;
2047bf215546Sopenharmony_ci
2048bf215546Sopenharmony_ci      _mesa_HashInsertLocked(ctx->Shared->BufferObjects, buffers[i], buf, true);
2049bf215546Sopenharmony_ci   }
2050bf215546Sopenharmony_ci
2051bf215546Sopenharmony_ci   _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects,
2052bf215546Sopenharmony_ci                               ctx->BufferObjectsLocked);
2053bf215546Sopenharmony_ci}
2054bf215546Sopenharmony_ci
2055bf215546Sopenharmony_ci
2056bf215546Sopenharmony_cistatic void
2057bf215546Sopenharmony_cicreate_buffers_err(struct gl_context *ctx, GLsizei n, GLuint *buffers, bool dsa)
2058bf215546Sopenharmony_ci{
2059bf215546Sopenharmony_ci   const char *func = dsa ? "glCreateBuffers" : "glGenBuffers";
2060bf215546Sopenharmony_ci
2061bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
2062bf215546Sopenharmony_ci      _mesa_debug(ctx, "%s(%d)\n", func, n);
2063bf215546Sopenharmony_ci
2064bf215546Sopenharmony_ci   if (n < 0) {
2065bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n %d < 0)", func, n);
2066bf215546Sopenharmony_ci      return;
2067bf215546Sopenharmony_ci   }
2068bf215546Sopenharmony_ci
2069bf215546Sopenharmony_ci   create_buffers(ctx, n, buffers, dsa);
2070bf215546Sopenharmony_ci}
2071bf215546Sopenharmony_ci
2072bf215546Sopenharmony_ci/**
2073bf215546Sopenharmony_ci * Generate a set of unique buffer object IDs and store them in \c buffers.
2074bf215546Sopenharmony_ci *
2075bf215546Sopenharmony_ci * \param n        Number of IDs to generate.
2076bf215546Sopenharmony_ci * \param buffers  Array of \c n locations to store the IDs.
2077bf215546Sopenharmony_ci */
2078bf215546Sopenharmony_civoid GLAPIENTRY
2079bf215546Sopenharmony_ci_mesa_GenBuffers_no_error(GLsizei n, GLuint *buffers)
2080bf215546Sopenharmony_ci{
2081bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2082bf215546Sopenharmony_ci   create_buffers(ctx, n, buffers, false);
2083bf215546Sopenharmony_ci}
2084bf215546Sopenharmony_ci
2085bf215546Sopenharmony_ci
2086bf215546Sopenharmony_civoid GLAPIENTRY
2087bf215546Sopenharmony_ci_mesa_GenBuffers(GLsizei n, GLuint *buffers)
2088bf215546Sopenharmony_ci{
2089bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2090bf215546Sopenharmony_ci   create_buffers_err(ctx, n, buffers, false);
2091bf215546Sopenharmony_ci}
2092bf215546Sopenharmony_ci
2093bf215546Sopenharmony_ci/**
2094bf215546Sopenharmony_ci * Create a set of buffer objects and store their unique IDs in \c buffers.
2095bf215546Sopenharmony_ci *
2096bf215546Sopenharmony_ci * \param n        Number of IDs to generate.
2097bf215546Sopenharmony_ci * \param buffers  Array of \c n locations to store the IDs.
2098bf215546Sopenharmony_ci */
2099bf215546Sopenharmony_civoid GLAPIENTRY
2100bf215546Sopenharmony_ci_mesa_CreateBuffers_no_error(GLsizei n, GLuint *buffers)
2101bf215546Sopenharmony_ci{
2102bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2103bf215546Sopenharmony_ci   create_buffers(ctx, n, buffers, true);
2104bf215546Sopenharmony_ci}
2105bf215546Sopenharmony_ci
2106bf215546Sopenharmony_ci
2107bf215546Sopenharmony_civoid GLAPIENTRY
2108bf215546Sopenharmony_ci_mesa_CreateBuffers(GLsizei n, GLuint *buffers)
2109bf215546Sopenharmony_ci{
2110bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2111bf215546Sopenharmony_ci   create_buffers_err(ctx, n, buffers, true);
2112bf215546Sopenharmony_ci}
2113bf215546Sopenharmony_ci
2114bf215546Sopenharmony_ci
2115bf215546Sopenharmony_ci/**
2116bf215546Sopenharmony_ci * Determine if ID is the name of a buffer object.
2117bf215546Sopenharmony_ci *
2118bf215546Sopenharmony_ci * \param id  ID of the potential buffer object.
2119bf215546Sopenharmony_ci * \return  \c GL_TRUE if \c id is the name of a buffer object,
2120bf215546Sopenharmony_ci *          \c GL_FALSE otherwise.
2121bf215546Sopenharmony_ci */
2122bf215546Sopenharmony_ciGLboolean GLAPIENTRY
2123bf215546Sopenharmony_ci_mesa_IsBuffer(GLuint id)
2124bf215546Sopenharmony_ci{
2125bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
2126bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2127bf215546Sopenharmony_ci   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
2128bf215546Sopenharmony_ci
2129bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj(ctx, id);
2130bf215546Sopenharmony_ci
2131bf215546Sopenharmony_ci   return bufObj && bufObj != &DummyBufferObject;
2132bf215546Sopenharmony_ci}
2133bf215546Sopenharmony_ci
2134bf215546Sopenharmony_ci
2135bf215546Sopenharmony_cistatic bool
2136bf215546Sopenharmony_civalidate_buffer_storage(struct gl_context *ctx,
2137bf215546Sopenharmony_ci                        struct gl_buffer_object *bufObj, GLsizeiptr size,
2138bf215546Sopenharmony_ci                        GLbitfield flags, const char *func)
2139bf215546Sopenharmony_ci{
2140bf215546Sopenharmony_ci   if (size <= 0) {
2141bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(size <= 0)", func);
2142bf215546Sopenharmony_ci      return false;
2143bf215546Sopenharmony_ci   }
2144bf215546Sopenharmony_ci
2145bf215546Sopenharmony_ci   GLbitfield valid_flags = GL_MAP_READ_BIT |
2146bf215546Sopenharmony_ci                            GL_MAP_WRITE_BIT |
2147bf215546Sopenharmony_ci                            GL_MAP_PERSISTENT_BIT |
2148bf215546Sopenharmony_ci                            GL_MAP_COHERENT_BIT |
2149bf215546Sopenharmony_ci                            GL_DYNAMIC_STORAGE_BIT |
2150bf215546Sopenharmony_ci                            GL_CLIENT_STORAGE_BIT;
2151bf215546Sopenharmony_ci
2152bf215546Sopenharmony_ci   if (ctx->Extensions.ARB_sparse_buffer)
2153bf215546Sopenharmony_ci      valid_flags |= GL_SPARSE_STORAGE_BIT_ARB;
2154bf215546Sopenharmony_ci
2155bf215546Sopenharmony_ci   if (flags & ~valid_flags) {
2156bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid flag bits set)", func);
2157bf215546Sopenharmony_ci      return false;
2158bf215546Sopenharmony_ci   }
2159bf215546Sopenharmony_ci
2160bf215546Sopenharmony_ci   /* The Errors section of the GL_ARB_sparse_buffer spec says:
2161bf215546Sopenharmony_ci    *
2162bf215546Sopenharmony_ci    *    "INVALID_VALUE is generated by BufferStorage if <flags> contains
2163bf215546Sopenharmony_ci    *     SPARSE_STORAGE_BIT_ARB and <flags> also contains any combination of
2164bf215546Sopenharmony_ci    *     MAP_READ_BIT or MAP_WRITE_BIT."
2165bf215546Sopenharmony_ci    */
2166bf215546Sopenharmony_ci   if (flags & GL_SPARSE_STORAGE_BIT_ARB &&
2167bf215546Sopenharmony_ci       flags & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) {
2168bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(SPARSE_STORAGE and READ/WRITE)", func);
2169bf215546Sopenharmony_ci      return false;
2170bf215546Sopenharmony_ci   }
2171bf215546Sopenharmony_ci
2172bf215546Sopenharmony_ci   if (flags & GL_MAP_PERSISTENT_BIT &&
2173bf215546Sopenharmony_ci       !(flags & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT))) {
2174bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
2175bf215546Sopenharmony_ci                  "%s(PERSISTENT and flags!=READ/WRITE)", func);
2176bf215546Sopenharmony_ci      return false;
2177bf215546Sopenharmony_ci   }
2178bf215546Sopenharmony_ci
2179bf215546Sopenharmony_ci   if (flags & GL_MAP_COHERENT_BIT && !(flags & GL_MAP_PERSISTENT_BIT)) {
2180bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
2181bf215546Sopenharmony_ci                  "%s(COHERENT and flags!=PERSISTENT)", func);
2182bf215546Sopenharmony_ci      return false;
2183bf215546Sopenharmony_ci   }
2184bf215546Sopenharmony_ci
2185bf215546Sopenharmony_ci   if (bufObj->Immutable || bufObj->HandleAllocated) {
2186bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(immutable)", func);
2187bf215546Sopenharmony_ci      return false;
2188bf215546Sopenharmony_ci   }
2189bf215546Sopenharmony_ci
2190bf215546Sopenharmony_ci   return true;
2191bf215546Sopenharmony_ci}
2192bf215546Sopenharmony_ci
2193bf215546Sopenharmony_ci
2194bf215546Sopenharmony_cistatic void
2195bf215546Sopenharmony_cibuffer_storage(struct gl_context *ctx, struct gl_buffer_object *bufObj,
2196bf215546Sopenharmony_ci               struct gl_memory_object *memObj, GLenum target,
2197bf215546Sopenharmony_ci               GLsizeiptr size, const GLvoid *data, GLbitfield flags,
2198bf215546Sopenharmony_ci               GLuint64 offset, const char *func)
2199bf215546Sopenharmony_ci{
2200bf215546Sopenharmony_ci   GLboolean res;
2201bf215546Sopenharmony_ci
2202bf215546Sopenharmony_ci   /* Unmap the existing buffer.  We'll replace it now.  Not an error. */
2203bf215546Sopenharmony_ci   _mesa_buffer_unmap_all_mappings(ctx, bufObj);
2204bf215546Sopenharmony_ci
2205bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, 0, 0);
2206bf215546Sopenharmony_ci
2207bf215546Sopenharmony_ci   bufObj->Written = GL_TRUE;
2208bf215546Sopenharmony_ci   bufObj->Immutable = GL_TRUE;
2209bf215546Sopenharmony_ci   bufObj->MinMaxCacheDirty = true;
2210bf215546Sopenharmony_ci
2211bf215546Sopenharmony_ci   if (memObj) {
2212bf215546Sopenharmony_ci      res = bufferobj_data_mem(ctx, target, size, memObj, offset,
2213bf215546Sopenharmony_ci                               GL_DYNAMIC_DRAW, bufObj);
2214bf215546Sopenharmony_ci   }
2215bf215546Sopenharmony_ci   else {
2216bf215546Sopenharmony_ci      res = _mesa_bufferobj_data(ctx, target, size, data, GL_DYNAMIC_DRAW,
2217bf215546Sopenharmony_ci                                 flags, bufObj);
2218bf215546Sopenharmony_ci   }
2219bf215546Sopenharmony_ci
2220bf215546Sopenharmony_ci   if (!res) {
2221bf215546Sopenharmony_ci      if (target == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD) {
2222bf215546Sopenharmony_ci         /* Even though the interaction between AMD_pinned_memory and
2223bf215546Sopenharmony_ci          * glBufferStorage is not described in the spec, Graham Sellers
2224bf215546Sopenharmony_ci          * said that it should behave the same as glBufferData.
2225bf215546Sopenharmony_ci          */
2226bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func);
2227bf215546Sopenharmony_ci      }
2228bf215546Sopenharmony_ci      else {
2229bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
2230bf215546Sopenharmony_ci      }
2231bf215546Sopenharmony_ci   }
2232bf215546Sopenharmony_ci}
2233bf215546Sopenharmony_ci
2234bf215546Sopenharmony_ci
2235bf215546Sopenharmony_cistatic ALWAYS_INLINE void
2236bf215546Sopenharmony_ciinlined_buffer_storage(GLenum target, GLuint buffer, GLsizeiptr size,
2237bf215546Sopenharmony_ci                       const GLvoid *data, GLbitfield flags,
2238bf215546Sopenharmony_ci                       GLuint memory, GLuint64 offset,
2239bf215546Sopenharmony_ci                       bool dsa, bool mem, bool no_error, const char *func)
2240bf215546Sopenharmony_ci{
2241bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2242bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
2243bf215546Sopenharmony_ci   struct gl_memory_object *memObj = NULL;
2244bf215546Sopenharmony_ci
2245bf215546Sopenharmony_ci   if (mem) {
2246bf215546Sopenharmony_ci      if (!no_error) {
2247bf215546Sopenharmony_ci         if (!ctx->Extensions.EXT_memory_object) {
2248bf215546Sopenharmony_ci            _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
2249bf215546Sopenharmony_ci            return;
2250bf215546Sopenharmony_ci         }
2251bf215546Sopenharmony_ci
2252bf215546Sopenharmony_ci         /* From the EXT_external_objects spec:
2253bf215546Sopenharmony_ci          *
2254bf215546Sopenharmony_ci          *   "An INVALID_VALUE error is generated by BufferStorageMemEXT and
2255bf215546Sopenharmony_ci          *   NamedBufferStorageMemEXT if <memory> is 0, or ..."
2256bf215546Sopenharmony_ci          */
2257bf215546Sopenharmony_ci         if (memory == 0) {
2258bf215546Sopenharmony_ci            _mesa_error(ctx, GL_INVALID_VALUE, "%s(memory == 0)", func);
2259bf215546Sopenharmony_ci         }
2260bf215546Sopenharmony_ci      }
2261bf215546Sopenharmony_ci
2262bf215546Sopenharmony_ci      memObj = _mesa_lookup_memory_object(ctx, memory);
2263bf215546Sopenharmony_ci      if (!memObj)
2264bf215546Sopenharmony_ci         return;
2265bf215546Sopenharmony_ci
2266bf215546Sopenharmony_ci      /* From the EXT_external_objects spec:
2267bf215546Sopenharmony_ci       *
2268bf215546Sopenharmony_ci       *   "An INVALID_OPERATION error is generated if <memory> names a
2269bf215546Sopenharmony_ci       *   valid memory object which has no associated memory."
2270bf215546Sopenharmony_ci       */
2271bf215546Sopenharmony_ci      if (!no_error && !memObj->Immutable) {
2272bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(no associated memory)",
2273bf215546Sopenharmony_ci                     func);
2274bf215546Sopenharmony_ci         return;
2275bf215546Sopenharmony_ci      }
2276bf215546Sopenharmony_ci   }
2277bf215546Sopenharmony_ci
2278bf215546Sopenharmony_ci   if (dsa) {
2279bf215546Sopenharmony_ci      if (no_error) {
2280bf215546Sopenharmony_ci         bufObj = _mesa_lookup_bufferobj(ctx, buffer);
2281bf215546Sopenharmony_ci      } else {
2282bf215546Sopenharmony_ci         bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, func);
2283bf215546Sopenharmony_ci         if (!bufObj)
2284bf215546Sopenharmony_ci            return;
2285bf215546Sopenharmony_ci      }
2286bf215546Sopenharmony_ci   } else {
2287bf215546Sopenharmony_ci      if (no_error) {
2288bf215546Sopenharmony_ci         struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target);
2289bf215546Sopenharmony_ci         bufObj = *bufObjPtr;
2290bf215546Sopenharmony_ci      } else {
2291bf215546Sopenharmony_ci         bufObj = get_buffer(ctx, func, target, GL_INVALID_OPERATION);
2292bf215546Sopenharmony_ci         if (!bufObj)
2293bf215546Sopenharmony_ci            return;
2294bf215546Sopenharmony_ci      }
2295bf215546Sopenharmony_ci   }
2296bf215546Sopenharmony_ci
2297bf215546Sopenharmony_ci   if (no_error || validate_buffer_storage(ctx, bufObj, size, flags, func))
2298bf215546Sopenharmony_ci      buffer_storage(ctx, bufObj, memObj, target, size, data, flags, offset, func);
2299bf215546Sopenharmony_ci}
2300bf215546Sopenharmony_ci
2301bf215546Sopenharmony_ci
2302bf215546Sopenharmony_civoid GLAPIENTRY
2303bf215546Sopenharmony_ci_mesa_BufferStorage_no_error(GLenum target, GLsizeiptr size,
2304bf215546Sopenharmony_ci                             const GLvoid *data, GLbitfield flags)
2305bf215546Sopenharmony_ci{
2306bf215546Sopenharmony_ci   inlined_buffer_storage(target, 0, size, data, flags, GL_NONE, 0,
2307bf215546Sopenharmony_ci                          false, false, true, "glBufferStorage");
2308bf215546Sopenharmony_ci}
2309bf215546Sopenharmony_ci
2310bf215546Sopenharmony_ci
2311bf215546Sopenharmony_civoid GLAPIENTRY
2312bf215546Sopenharmony_ci_mesa_BufferStorage(GLenum target, GLsizeiptr size, const GLvoid *data,
2313bf215546Sopenharmony_ci                    GLbitfield flags)
2314bf215546Sopenharmony_ci{
2315bf215546Sopenharmony_ci   inlined_buffer_storage(target, 0, size, data, flags, GL_NONE, 0,
2316bf215546Sopenharmony_ci                          false, false, false, "glBufferStorage");
2317bf215546Sopenharmony_ci}
2318bf215546Sopenharmony_ci
2319bf215546Sopenharmony_civoid GLAPIENTRY
2320bf215546Sopenharmony_ci_mesa_NamedBufferStorageEXT(GLuint buffer, GLsizeiptr size,
2321bf215546Sopenharmony_ci                            const GLvoid *data, GLbitfield flags)
2322bf215546Sopenharmony_ci{
2323bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2324bf215546Sopenharmony_ci
2325bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
2326bf215546Sopenharmony_ci   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
2327bf215546Sopenharmony_ci                                     &bufObj, "glNamedBufferStorageEXT", false))
2328bf215546Sopenharmony_ci      return;
2329bf215546Sopenharmony_ci
2330bf215546Sopenharmony_ci   inlined_buffer_storage(GL_NONE, buffer, size, data, flags, GL_NONE, 0,
2331bf215546Sopenharmony_ci                          true, false, false, "glNamedBufferStorageEXT");
2332bf215546Sopenharmony_ci}
2333bf215546Sopenharmony_ci
2334bf215546Sopenharmony_ci
2335bf215546Sopenharmony_civoid GLAPIENTRY
2336bf215546Sopenharmony_ci_mesa_BufferStorageMemEXT(GLenum target, GLsizeiptr size,
2337bf215546Sopenharmony_ci                          GLuint memory, GLuint64 offset)
2338bf215546Sopenharmony_ci{
2339bf215546Sopenharmony_ci   inlined_buffer_storage(target, 0, size, NULL, 0, memory, offset,
2340bf215546Sopenharmony_ci                          false, true, false, "glBufferStorageMemEXT");
2341bf215546Sopenharmony_ci}
2342bf215546Sopenharmony_ci
2343bf215546Sopenharmony_ci
2344bf215546Sopenharmony_civoid GLAPIENTRY
2345bf215546Sopenharmony_ci_mesa_BufferStorageMemEXT_no_error(GLenum target, GLsizeiptr size,
2346bf215546Sopenharmony_ci                                   GLuint memory, GLuint64 offset)
2347bf215546Sopenharmony_ci{
2348bf215546Sopenharmony_ci   inlined_buffer_storage(target, 0, size, NULL, 0, memory, offset,
2349bf215546Sopenharmony_ci                          false, true, true, "glBufferStorageMemEXT");
2350bf215546Sopenharmony_ci}
2351bf215546Sopenharmony_ci
2352bf215546Sopenharmony_ci
2353bf215546Sopenharmony_civoid GLAPIENTRY
2354bf215546Sopenharmony_ci_mesa_NamedBufferStorage_no_error(GLuint buffer, GLsizeiptr size,
2355bf215546Sopenharmony_ci                                  const GLvoid *data, GLbitfield flags)
2356bf215546Sopenharmony_ci{
2357bf215546Sopenharmony_ci   /* In direct state access, buffer objects have an unspecified target
2358bf215546Sopenharmony_ci    * since they are not required to be bound.
2359bf215546Sopenharmony_ci    */
2360bf215546Sopenharmony_ci   inlined_buffer_storage(GL_NONE, buffer, size, data, flags, GL_NONE, 0,
2361bf215546Sopenharmony_ci                          true, false, true, "glNamedBufferStorage");
2362bf215546Sopenharmony_ci}
2363bf215546Sopenharmony_ci
2364bf215546Sopenharmony_ci
2365bf215546Sopenharmony_civoid GLAPIENTRY
2366bf215546Sopenharmony_ci_mesa_NamedBufferStorage(GLuint buffer, GLsizeiptr size, const GLvoid *data,
2367bf215546Sopenharmony_ci                         GLbitfield flags)
2368bf215546Sopenharmony_ci{
2369bf215546Sopenharmony_ci   /* In direct state access, buffer objects have an unspecified target
2370bf215546Sopenharmony_ci    * since they are not required to be bound.
2371bf215546Sopenharmony_ci    */
2372bf215546Sopenharmony_ci   inlined_buffer_storage(GL_NONE, buffer, size, data, flags, GL_NONE, 0,
2373bf215546Sopenharmony_ci                          true, false, false, "glNamedBufferStorage");
2374bf215546Sopenharmony_ci}
2375bf215546Sopenharmony_ci
2376bf215546Sopenharmony_civoid GLAPIENTRY
2377bf215546Sopenharmony_ci_mesa_NamedBufferStorageMemEXT(GLuint buffer, GLsizeiptr size,
2378bf215546Sopenharmony_ci                               GLuint memory, GLuint64 offset)
2379bf215546Sopenharmony_ci{
2380bf215546Sopenharmony_ci   inlined_buffer_storage(GL_NONE, buffer, size, NULL, 0, memory, offset,
2381bf215546Sopenharmony_ci                          true, true, false, "glNamedBufferStorageMemEXT");
2382bf215546Sopenharmony_ci}
2383bf215546Sopenharmony_ci
2384bf215546Sopenharmony_ci
2385bf215546Sopenharmony_civoid GLAPIENTRY
2386bf215546Sopenharmony_ci_mesa_NamedBufferStorageMemEXT_no_error(GLuint buffer, GLsizeiptr size,
2387bf215546Sopenharmony_ci                                        GLuint memory, GLuint64 offset)
2388bf215546Sopenharmony_ci{
2389bf215546Sopenharmony_ci   inlined_buffer_storage(GL_NONE, buffer, size, NULL, 0, memory, offset,
2390bf215546Sopenharmony_ci                          true, true, true, "glNamedBufferStorageMemEXT");
2391bf215546Sopenharmony_ci}
2392bf215546Sopenharmony_ci
2393bf215546Sopenharmony_ci
2394bf215546Sopenharmony_cistatic ALWAYS_INLINE void
2395bf215546Sopenharmony_cibuffer_data(struct gl_context *ctx, struct gl_buffer_object *bufObj,
2396bf215546Sopenharmony_ci            GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage,
2397bf215546Sopenharmony_ci            const char *func, bool no_error)
2398bf215546Sopenharmony_ci{
2399bf215546Sopenharmony_ci   bool valid_usage;
2400bf215546Sopenharmony_ci
2401bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API) {
2402bf215546Sopenharmony_ci      _mesa_debug(ctx, "%s(%s, %ld, %p, %s)\n",
2403bf215546Sopenharmony_ci                  func,
2404bf215546Sopenharmony_ci                  _mesa_enum_to_string(target),
2405bf215546Sopenharmony_ci                  (long int) size, data,
2406bf215546Sopenharmony_ci                  _mesa_enum_to_string(usage));
2407bf215546Sopenharmony_ci   }
2408bf215546Sopenharmony_ci
2409bf215546Sopenharmony_ci   if (!no_error) {
2410bf215546Sopenharmony_ci      if (size < 0) {
2411bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", func);
2412bf215546Sopenharmony_ci         return;
2413bf215546Sopenharmony_ci      }
2414bf215546Sopenharmony_ci
2415bf215546Sopenharmony_ci      switch (usage) {
2416bf215546Sopenharmony_ci      case GL_STREAM_DRAW_ARB:
2417bf215546Sopenharmony_ci         valid_usage = (ctx->API != API_OPENGLES);
2418bf215546Sopenharmony_ci         break;
2419bf215546Sopenharmony_ci      case GL_STATIC_DRAW_ARB:
2420bf215546Sopenharmony_ci      case GL_DYNAMIC_DRAW_ARB:
2421bf215546Sopenharmony_ci         valid_usage = true;
2422bf215546Sopenharmony_ci         break;
2423bf215546Sopenharmony_ci      case GL_STREAM_READ_ARB:
2424bf215546Sopenharmony_ci      case GL_STREAM_COPY_ARB:
2425bf215546Sopenharmony_ci      case GL_STATIC_READ_ARB:
2426bf215546Sopenharmony_ci      case GL_STATIC_COPY_ARB:
2427bf215546Sopenharmony_ci      case GL_DYNAMIC_READ_ARB:
2428bf215546Sopenharmony_ci      case GL_DYNAMIC_COPY_ARB:
2429bf215546Sopenharmony_ci         valid_usage = _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx);
2430bf215546Sopenharmony_ci         break;
2431bf215546Sopenharmony_ci      default:
2432bf215546Sopenharmony_ci         valid_usage = false;
2433bf215546Sopenharmony_ci         break;
2434bf215546Sopenharmony_ci      }
2435bf215546Sopenharmony_ci
2436bf215546Sopenharmony_ci      if (!valid_usage) {
2437bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid usage: %s)", func,
2438bf215546Sopenharmony_ci                     _mesa_enum_to_string(usage));
2439bf215546Sopenharmony_ci         return;
2440bf215546Sopenharmony_ci      }
2441bf215546Sopenharmony_ci
2442bf215546Sopenharmony_ci      if (bufObj->Immutable || bufObj->HandleAllocated) {
2443bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(immutable)", func);
2444bf215546Sopenharmony_ci         return;
2445bf215546Sopenharmony_ci      }
2446bf215546Sopenharmony_ci   }
2447bf215546Sopenharmony_ci
2448bf215546Sopenharmony_ci   /* Unmap the existing buffer.  We'll replace it now.  Not an error. */
2449bf215546Sopenharmony_ci   _mesa_buffer_unmap_all_mappings(ctx, bufObj);
2450bf215546Sopenharmony_ci
2451bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, 0, 0);
2452bf215546Sopenharmony_ci
2453bf215546Sopenharmony_ci   bufObj->Written = GL_TRUE;
2454bf215546Sopenharmony_ci   bufObj->MinMaxCacheDirty = true;
2455bf215546Sopenharmony_ci
2456bf215546Sopenharmony_ci#ifdef VBO_DEBUG
2457bf215546Sopenharmony_ci   printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n",
2458bf215546Sopenharmony_ci                bufObj->Name, size, data, usage);
2459bf215546Sopenharmony_ci#endif
2460bf215546Sopenharmony_ci
2461bf215546Sopenharmony_ci#ifdef BOUNDS_CHECK
2462bf215546Sopenharmony_ci   size += 100;
2463bf215546Sopenharmony_ci#endif
2464bf215546Sopenharmony_ci
2465bf215546Sopenharmony_ci   if (!_mesa_bufferobj_data(ctx, target, size, data, usage,
2466bf215546Sopenharmony_ci                             GL_MAP_READ_BIT |
2467bf215546Sopenharmony_ci                             GL_MAP_WRITE_BIT |
2468bf215546Sopenharmony_ci                             GL_DYNAMIC_STORAGE_BIT,
2469bf215546Sopenharmony_ci                             bufObj)) {
2470bf215546Sopenharmony_ci      if (target == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD) {
2471bf215546Sopenharmony_ci         if (!no_error) {
2472bf215546Sopenharmony_ci            /* From GL_AMD_pinned_memory:
2473bf215546Sopenharmony_ci             *
2474bf215546Sopenharmony_ci             *   INVALID_OPERATION is generated by BufferData if <target> is
2475bf215546Sopenharmony_ci             *   EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, and the store cannot be
2476bf215546Sopenharmony_ci             *   mapped to the GPU address space.
2477bf215546Sopenharmony_ci             */
2478bf215546Sopenharmony_ci            _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func);
2479bf215546Sopenharmony_ci         }
2480bf215546Sopenharmony_ci      } else {
2481bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
2482bf215546Sopenharmony_ci      }
2483bf215546Sopenharmony_ci   }
2484bf215546Sopenharmony_ci}
2485bf215546Sopenharmony_ci
2486bf215546Sopenharmony_cistatic void
2487bf215546Sopenharmony_cibuffer_data_error(struct gl_context *ctx, struct gl_buffer_object *bufObj,
2488bf215546Sopenharmony_ci                  GLenum target, GLsizeiptr size, const GLvoid *data,
2489bf215546Sopenharmony_ci                  GLenum usage, const char *func)
2490bf215546Sopenharmony_ci{
2491bf215546Sopenharmony_ci   buffer_data(ctx, bufObj, target, size, data, usage, func, false);
2492bf215546Sopenharmony_ci}
2493bf215546Sopenharmony_ci
2494bf215546Sopenharmony_cistatic void
2495bf215546Sopenharmony_cibuffer_data_no_error(struct gl_context *ctx, struct gl_buffer_object *bufObj,
2496bf215546Sopenharmony_ci                     GLenum target, GLsizeiptr size, const GLvoid *data,
2497bf215546Sopenharmony_ci                     GLenum usage, const char *func)
2498bf215546Sopenharmony_ci{
2499bf215546Sopenharmony_ci   buffer_data(ctx, bufObj, target, size, data, usage, func, true);
2500bf215546Sopenharmony_ci}
2501bf215546Sopenharmony_ci
2502bf215546Sopenharmony_civoid
2503bf215546Sopenharmony_ci_mesa_buffer_data(struct gl_context *ctx, struct gl_buffer_object *bufObj,
2504bf215546Sopenharmony_ci                  GLenum target, GLsizeiptr size, const GLvoid *data,
2505bf215546Sopenharmony_ci                  GLenum usage, const char *func)
2506bf215546Sopenharmony_ci{
2507bf215546Sopenharmony_ci   buffer_data_error(ctx, bufObj, target, size, data, usage, func);
2508bf215546Sopenharmony_ci}
2509bf215546Sopenharmony_ci
2510bf215546Sopenharmony_civoid GLAPIENTRY
2511bf215546Sopenharmony_ci_mesa_BufferData_no_error(GLenum target, GLsizeiptr size, const GLvoid *data,
2512bf215546Sopenharmony_ci                          GLenum usage)
2513bf215546Sopenharmony_ci{
2514bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2515bf215546Sopenharmony_ci
2516bf215546Sopenharmony_ci   struct gl_buffer_object **bufObj = get_buffer_target(ctx, target);
2517bf215546Sopenharmony_ci   buffer_data_no_error(ctx, *bufObj, target, size, data, usage,
2518bf215546Sopenharmony_ci                        "glBufferData");
2519bf215546Sopenharmony_ci}
2520bf215546Sopenharmony_ci
2521bf215546Sopenharmony_civoid GLAPIENTRY
2522bf215546Sopenharmony_ci_mesa_BufferData(GLenum target, GLsizeiptr size,
2523bf215546Sopenharmony_ci                 const GLvoid *data, GLenum usage)
2524bf215546Sopenharmony_ci{
2525bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2526bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
2527bf215546Sopenharmony_ci
2528bf215546Sopenharmony_ci   bufObj = get_buffer(ctx, "glBufferData", target, GL_INVALID_OPERATION);
2529bf215546Sopenharmony_ci   if (!bufObj)
2530bf215546Sopenharmony_ci      return;
2531bf215546Sopenharmony_ci
2532bf215546Sopenharmony_ci   _mesa_buffer_data(ctx, bufObj, target, size, data, usage,
2533bf215546Sopenharmony_ci                     "glBufferData");
2534bf215546Sopenharmony_ci}
2535bf215546Sopenharmony_ci
2536bf215546Sopenharmony_civoid GLAPIENTRY
2537bf215546Sopenharmony_ci_mesa_NamedBufferData_no_error(GLuint buffer, GLsizeiptr size,
2538bf215546Sopenharmony_ci                               const GLvoid *data, GLenum usage)
2539bf215546Sopenharmony_ci{
2540bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2541bf215546Sopenharmony_ci
2542bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
2543bf215546Sopenharmony_ci   buffer_data_no_error(ctx, bufObj, GL_NONE, size, data, usage,
2544bf215546Sopenharmony_ci                        "glNamedBufferData");
2545bf215546Sopenharmony_ci}
2546bf215546Sopenharmony_ci
2547bf215546Sopenharmony_civoid GLAPIENTRY
2548bf215546Sopenharmony_ci_mesa_NamedBufferData(GLuint buffer, GLsizeiptr size, const GLvoid *data,
2549bf215546Sopenharmony_ci                      GLenum usage)
2550bf215546Sopenharmony_ci{
2551bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2552bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
2553bf215546Sopenharmony_ci
2554bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glNamedBufferData");
2555bf215546Sopenharmony_ci   if (!bufObj)
2556bf215546Sopenharmony_ci      return;
2557bf215546Sopenharmony_ci
2558bf215546Sopenharmony_ci   /* In direct state access, buffer objects have an unspecified target since
2559bf215546Sopenharmony_ci    * they are not required to be bound.
2560bf215546Sopenharmony_ci    */
2561bf215546Sopenharmony_ci   _mesa_buffer_data(ctx, bufObj, GL_NONE, size, data, usage,
2562bf215546Sopenharmony_ci                     "glNamedBufferData");
2563bf215546Sopenharmony_ci}
2564bf215546Sopenharmony_ci
2565bf215546Sopenharmony_civoid GLAPIENTRY
2566bf215546Sopenharmony_ci_mesa_NamedBufferDataEXT(GLuint buffer, GLsizeiptr size, const GLvoid *data,
2567bf215546Sopenharmony_ci                         GLenum usage)
2568bf215546Sopenharmony_ci{
2569bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2570bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
2571bf215546Sopenharmony_ci
2572bf215546Sopenharmony_ci   if (!buffer) {
2573bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
2574bf215546Sopenharmony_ci                  "glNamedBufferDataEXT(buffer=0)");
2575bf215546Sopenharmony_ci      return;
2576bf215546Sopenharmony_ci   }
2577bf215546Sopenharmony_ci
2578bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
2579bf215546Sopenharmony_ci   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
2580bf215546Sopenharmony_ci                                     &bufObj, "glNamedBufferDataEXT", false))
2581bf215546Sopenharmony_ci      return;
2582bf215546Sopenharmony_ci
2583bf215546Sopenharmony_ci   _mesa_buffer_data(ctx, bufObj, GL_NONE, size, data, usage,
2584bf215546Sopenharmony_ci                     "glNamedBufferDataEXT");
2585bf215546Sopenharmony_ci}
2586bf215546Sopenharmony_ci
2587bf215546Sopenharmony_cistatic bool
2588bf215546Sopenharmony_civalidate_buffer_sub_data(struct gl_context *ctx,
2589bf215546Sopenharmony_ci                         struct gl_buffer_object *bufObj,
2590bf215546Sopenharmony_ci                         GLintptr offset, GLsizeiptr size,
2591bf215546Sopenharmony_ci                         const char *func)
2592bf215546Sopenharmony_ci{
2593bf215546Sopenharmony_ci   if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size,
2594bf215546Sopenharmony_ci                                         true, func)) {
2595bf215546Sopenharmony_ci      /* error already recorded */
2596bf215546Sopenharmony_ci      return false;
2597bf215546Sopenharmony_ci   }
2598bf215546Sopenharmony_ci
2599bf215546Sopenharmony_ci   if (bufObj->Immutable &&
2600bf215546Sopenharmony_ci       !(bufObj->StorageFlags & GL_DYNAMIC_STORAGE_BIT)) {
2601bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func);
2602bf215546Sopenharmony_ci      return false;
2603bf215546Sopenharmony_ci   }
2604bf215546Sopenharmony_ci
2605bf215546Sopenharmony_ci   if ((bufObj->Usage == GL_STATIC_DRAW ||
2606bf215546Sopenharmony_ci        bufObj->Usage == GL_STATIC_COPY) &&
2607bf215546Sopenharmony_ci       bufObj->NumSubDataCalls >= BUFFER_WARNING_CALL_COUNT - 1) {
2608bf215546Sopenharmony_ci      /* If the application declared the buffer as static draw/copy or stream
2609bf215546Sopenharmony_ci       * draw, it should not be frequently modified with glBufferSubData.
2610bf215546Sopenharmony_ci       */
2611bf215546Sopenharmony_ci      BUFFER_USAGE_WARNING(ctx,
2612bf215546Sopenharmony_ci                           "using %s(buffer %u, offset %u, size %u) to "
2613bf215546Sopenharmony_ci                           "update a %s buffer",
2614bf215546Sopenharmony_ci                           func, bufObj->Name, offset, size,
2615bf215546Sopenharmony_ci                           _mesa_enum_to_string(bufObj->Usage));
2616bf215546Sopenharmony_ci   }
2617bf215546Sopenharmony_ci
2618bf215546Sopenharmony_ci   return true;
2619bf215546Sopenharmony_ci}
2620bf215546Sopenharmony_ci
2621bf215546Sopenharmony_ci
2622bf215546Sopenharmony_ci/**
2623bf215546Sopenharmony_ci * Implementation for glBufferSubData and glNamedBufferSubData.
2624bf215546Sopenharmony_ci *
2625bf215546Sopenharmony_ci * \param ctx     GL context.
2626bf215546Sopenharmony_ci * \param bufObj  The buffer object.
2627bf215546Sopenharmony_ci * \param offset  Offset of the first byte of the subdata range.
2628bf215546Sopenharmony_ci * \param size    Size, in bytes, of the subdata range.
2629bf215546Sopenharmony_ci * \param data    The data store.
2630bf215546Sopenharmony_ci * \param func  Name of calling function for recording errors.
2631bf215546Sopenharmony_ci *
2632bf215546Sopenharmony_ci */
2633bf215546Sopenharmony_civoid
2634bf215546Sopenharmony_ci_mesa_buffer_sub_data(struct gl_context *ctx, struct gl_buffer_object *bufObj,
2635bf215546Sopenharmony_ci                      GLintptr offset, GLsizeiptr size, const GLvoid *data)
2636bf215546Sopenharmony_ci{
2637bf215546Sopenharmony_ci   if (size == 0)
2638bf215546Sopenharmony_ci      return;
2639bf215546Sopenharmony_ci
2640bf215546Sopenharmony_ci   bufObj->NumSubDataCalls++;
2641bf215546Sopenharmony_ci   bufObj->Written = GL_TRUE;
2642bf215546Sopenharmony_ci   bufObj->MinMaxCacheDirty = true;
2643bf215546Sopenharmony_ci
2644bf215546Sopenharmony_ci   _mesa_bufferobj_subdata(ctx, offset, size, data, bufObj);
2645bf215546Sopenharmony_ci}
2646bf215546Sopenharmony_ci
2647bf215546Sopenharmony_ci
2648bf215546Sopenharmony_cistatic ALWAYS_INLINE void
2649bf215546Sopenharmony_cibuffer_sub_data(GLenum target, GLuint buffer, GLintptr offset,
2650bf215546Sopenharmony_ci                GLsizeiptr size, const GLvoid *data,
2651bf215546Sopenharmony_ci                bool dsa, bool no_error, const char *func)
2652bf215546Sopenharmony_ci{
2653bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2654bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
2655bf215546Sopenharmony_ci
2656bf215546Sopenharmony_ci   if (dsa) {
2657bf215546Sopenharmony_ci      if (no_error) {
2658bf215546Sopenharmony_ci         bufObj = _mesa_lookup_bufferobj(ctx, buffer);
2659bf215546Sopenharmony_ci      } else {
2660bf215546Sopenharmony_ci         bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, func);
2661bf215546Sopenharmony_ci         if (!bufObj)
2662bf215546Sopenharmony_ci            return;
2663bf215546Sopenharmony_ci      }
2664bf215546Sopenharmony_ci   } else {
2665bf215546Sopenharmony_ci      if (no_error) {
2666bf215546Sopenharmony_ci         struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target);
2667bf215546Sopenharmony_ci         bufObj = *bufObjPtr;
2668bf215546Sopenharmony_ci      } else {
2669bf215546Sopenharmony_ci         bufObj = get_buffer(ctx, func, target, GL_INVALID_OPERATION);
2670bf215546Sopenharmony_ci         if (!bufObj)
2671bf215546Sopenharmony_ci            return;
2672bf215546Sopenharmony_ci      }
2673bf215546Sopenharmony_ci   }
2674bf215546Sopenharmony_ci
2675bf215546Sopenharmony_ci   if (no_error || validate_buffer_sub_data(ctx, bufObj, offset, size, func))
2676bf215546Sopenharmony_ci      _mesa_buffer_sub_data(ctx, bufObj, offset, size, data);
2677bf215546Sopenharmony_ci}
2678bf215546Sopenharmony_ci
2679bf215546Sopenharmony_ci
2680bf215546Sopenharmony_civoid GLAPIENTRY
2681bf215546Sopenharmony_ci_mesa_BufferSubData_no_error(GLenum target, GLintptr offset,
2682bf215546Sopenharmony_ci                             GLsizeiptr size, const GLvoid *data)
2683bf215546Sopenharmony_ci{
2684bf215546Sopenharmony_ci   buffer_sub_data(target, 0, offset, size, data, false, true,
2685bf215546Sopenharmony_ci                   "glBufferSubData");
2686bf215546Sopenharmony_ci}
2687bf215546Sopenharmony_ci
2688bf215546Sopenharmony_ci
2689bf215546Sopenharmony_civoid GLAPIENTRY
2690bf215546Sopenharmony_ci_mesa_BufferSubData(GLenum target, GLintptr offset,
2691bf215546Sopenharmony_ci                    GLsizeiptr size, const GLvoid *data)
2692bf215546Sopenharmony_ci{
2693bf215546Sopenharmony_ci   buffer_sub_data(target, 0, offset, size, data, false, false,
2694bf215546Sopenharmony_ci                   "glBufferSubData");
2695bf215546Sopenharmony_ci}
2696bf215546Sopenharmony_ci
2697bf215546Sopenharmony_civoid GLAPIENTRY
2698bf215546Sopenharmony_ci_mesa_NamedBufferSubData_no_error(GLuint buffer, GLintptr offset,
2699bf215546Sopenharmony_ci                                  GLsizeiptr size, const GLvoid *data)
2700bf215546Sopenharmony_ci{
2701bf215546Sopenharmony_ci   buffer_sub_data(0, buffer, offset, size, data, true, true,
2702bf215546Sopenharmony_ci                   "glNamedBufferSubData");
2703bf215546Sopenharmony_ci}
2704bf215546Sopenharmony_ci
2705bf215546Sopenharmony_civoid GLAPIENTRY
2706bf215546Sopenharmony_ci_mesa_NamedBufferSubData(GLuint buffer, GLintptr offset,
2707bf215546Sopenharmony_ci                         GLsizeiptr size, const GLvoid *data)
2708bf215546Sopenharmony_ci{
2709bf215546Sopenharmony_ci   buffer_sub_data(0, buffer, offset, size, data, true, false,
2710bf215546Sopenharmony_ci                   "glNamedBufferSubData");
2711bf215546Sopenharmony_ci}
2712bf215546Sopenharmony_ci
2713bf215546Sopenharmony_civoid GLAPIENTRY
2714bf215546Sopenharmony_ci_mesa_NamedBufferSubDataEXT(GLuint buffer, GLintptr offset,
2715bf215546Sopenharmony_ci                            GLsizeiptr size, const GLvoid *data)
2716bf215546Sopenharmony_ci{
2717bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2718bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
2719bf215546Sopenharmony_ci
2720bf215546Sopenharmony_ci   if (!buffer) {
2721bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
2722bf215546Sopenharmony_ci                  "glNamedBufferSubDataEXT(buffer=0)");
2723bf215546Sopenharmony_ci      return;
2724bf215546Sopenharmony_ci   }
2725bf215546Sopenharmony_ci
2726bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
2727bf215546Sopenharmony_ci   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
2728bf215546Sopenharmony_ci                                     &bufObj, "glNamedBufferSubDataEXT", false))
2729bf215546Sopenharmony_ci      return;
2730bf215546Sopenharmony_ci
2731bf215546Sopenharmony_ci   if (validate_buffer_sub_data(ctx, bufObj, offset, size,
2732bf215546Sopenharmony_ci                                "glNamedBufferSubDataEXT")) {
2733bf215546Sopenharmony_ci      _mesa_buffer_sub_data(ctx, bufObj, offset, size, data);
2734bf215546Sopenharmony_ci   }
2735bf215546Sopenharmony_ci}
2736bf215546Sopenharmony_ci
2737bf215546Sopenharmony_ci
2738bf215546Sopenharmony_civoid GLAPIENTRY
2739bf215546Sopenharmony_ci_mesa_GetBufferSubData(GLenum target, GLintptr offset,
2740bf215546Sopenharmony_ci                       GLsizeiptr size, GLvoid *data)
2741bf215546Sopenharmony_ci{
2742bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2743bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
2744bf215546Sopenharmony_ci
2745bf215546Sopenharmony_ci   bufObj = get_buffer(ctx, "glGetBufferSubData", target,
2746bf215546Sopenharmony_ci                       GL_INVALID_OPERATION);
2747bf215546Sopenharmony_ci   if (!bufObj)
2748bf215546Sopenharmony_ci      return;
2749bf215546Sopenharmony_ci
2750bf215546Sopenharmony_ci   if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size, false,
2751bf215546Sopenharmony_ci                                         "glGetBufferSubData")) {
2752bf215546Sopenharmony_ci      return;
2753bf215546Sopenharmony_ci   }
2754bf215546Sopenharmony_ci
2755bf215546Sopenharmony_ci   bufferobj_get_subdata(ctx, offset, size, data, bufObj);
2756bf215546Sopenharmony_ci}
2757bf215546Sopenharmony_ci
2758bf215546Sopenharmony_civoid GLAPIENTRY
2759bf215546Sopenharmony_ci_mesa_GetNamedBufferSubData(GLuint buffer, GLintptr offset,
2760bf215546Sopenharmony_ci                            GLsizeiptr size, GLvoid *data)
2761bf215546Sopenharmony_ci{
2762bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2763bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
2764bf215546Sopenharmony_ci
2765bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer,
2766bf215546Sopenharmony_ci                                       "glGetNamedBufferSubData");
2767bf215546Sopenharmony_ci   if (!bufObj)
2768bf215546Sopenharmony_ci      return;
2769bf215546Sopenharmony_ci
2770bf215546Sopenharmony_ci   if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size, false,
2771bf215546Sopenharmony_ci                                         "glGetNamedBufferSubData")) {
2772bf215546Sopenharmony_ci      return;
2773bf215546Sopenharmony_ci   }
2774bf215546Sopenharmony_ci
2775bf215546Sopenharmony_ci   bufferobj_get_subdata(ctx, offset, size, data, bufObj);
2776bf215546Sopenharmony_ci}
2777bf215546Sopenharmony_ci
2778bf215546Sopenharmony_ci
2779bf215546Sopenharmony_civoid GLAPIENTRY
2780bf215546Sopenharmony_ci_mesa_GetNamedBufferSubDataEXT(GLuint buffer, GLintptr offset,
2781bf215546Sopenharmony_ci                               GLsizeiptr size, GLvoid *data)
2782bf215546Sopenharmony_ci{
2783bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2784bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
2785bf215546Sopenharmony_ci
2786bf215546Sopenharmony_ci   if (!buffer) {
2787bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
2788bf215546Sopenharmony_ci                  "glGetNamedBufferSubDataEXT(buffer=0)");
2789bf215546Sopenharmony_ci      return;
2790bf215546Sopenharmony_ci   }
2791bf215546Sopenharmony_ci
2792bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
2793bf215546Sopenharmony_ci   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
2794bf215546Sopenharmony_ci                                     &bufObj, "glGetNamedBufferSubDataEXT", false))
2795bf215546Sopenharmony_ci      return;
2796bf215546Sopenharmony_ci
2797bf215546Sopenharmony_ci   if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size, false,
2798bf215546Sopenharmony_ci                                         "glGetNamedBufferSubDataEXT")) {
2799bf215546Sopenharmony_ci      return;
2800bf215546Sopenharmony_ci   }
2801bf215546Sopenharmony_ci
2802bf215546Sopenharmony_ci   bufferobj_get_subdata(ctx, offset, size, data, bufObj);
2803bf215546Sopenharmony_ci}
2804bf215546Sopenharmony_ci
2805bf215546Sopenharmony_ci/**
2806bf215546Sopenharmony_ci * \param subdata   true if caller is *SubData, false if *Data
2807bf215546Sopenharmony_ci */
2808bf215546Sopenharmony_cistatic ALWAYS_INLINE void
2809bf215546Sopenharmony_ciclear_buffer_sub_data(struct gl_context *ctx, struct gl_buffer_object *bufObj,
2810bf215546Sopenharmony_ci                      GLenum internalformat, GLintptr offset, GLsizeiptr size,
2811bf215546Sopenharmony_ci                      GLenum format, GLenum type, const GLvoid *data,
2812bf215546Sopenharmony_ci                      const char *func, bool subdata, bool no_error)
2813bf215546Sopenharmony_ci{
2814bf215546Sopenharmony_ci   mesa_format mesaFormat;
2815bf215546Sopenharmony_ci   GLubyte clearValue[MAX_PIXEL_BYTES];
2816bf215546Sopenharmony_ci   GLsizeiptr clearValueSize;
2817bf215546Sopenharmony_ci
2818bf215546Sopenharmony_ci   /* This checks for disallowed mappings. */
2819bf215546Sopenharmony_ci   if (!no_error && !buffer_object_subdata_range_good(ctx, bufObj, offset, size,
2820bf215546Sopenharmony_ci                                                      subdata, func)) {
2821bf215546Sopenharmony_ci      return;
2822bf215546Sopenharmony_ci   }
2823bf215546Sopenharmony_ci
2824bf215546Sopenharmony_ci   if (no_error) {
2825bf215546Sopenharmony_ci      mesaFormat = _mesa_get_texbuffer_format(ctx, internalformat);
2826bf215546Sopenharmony_ci   } else {
2827bf215546Sopenharmony_ci      mesaFormat = validate_clear_buffer_format(ctx, internalformat,
2828bf215546Sopenharmony_ci                                                format, type, func);
2829bf215546Sopenharmony_ci   }
2830bf215546Sopenharmony_ci
2831bf215546Sopenharmony_ci   if (mesaFormat == MESA_FORMAT_NONE)
2832bf215546Sopenharmony_ci      return;
2833bf215546Sopenharmony_ci
2834bf215546Sopenharmony_ci   clearValueSize = _mesa_get_format_bytes(mesaFormat);
2835bf215546Sopenharmony_ci   if (!no_error &&
2836bf215546Sopenharmony_ci       (offset % clearValueSize != 0 || size % clearValueSize != 0)) {
2837bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
2838bf215546Sopenharmony_ci                  "%s(offset or size is not a multiple of "
2839bf215546Sopenharmony_ci                  "internalformat size)", func);
2840bf215546Sopenharmony_ci      return;
2841bf215546Sopenharmony_ci   }
2842bf215546Sopenharmony_ci
2843bf215546Sopenharmony_ci   /* Bail early. Negative size has already been checked. */
2844bf215546Sopenharmony_ci   if (size == 0)
2845bf215546Sopenharmony_ci      return;
2846bf215546Sopenharmony_ci
2847bf215546Sopenharmony_ci   bufObj->MinMaxCacheDirty = true;
2848bf215546Sopenharmony_ci
2849bf215546Sopenharmony_ci   if (!ctx->pipe->clear_buffer) {
2850bf215546Sopenharmony_ci      clear_buffer_subdata_sw(ctx, offset, size,
2851bf215546Sopenharmony_ci                              data, clearValueSize, bufObj);
2852bf215546Sopenharmony_ci      return;
2853bf215546Sopenharmony_ci   }
2854bf215546Sopenharmony_ci
2855bf215546Sopenharmony_ci   if (!data)
2856bf215546Sopenharmony_ci      memset(clearValue, 0, MAX_PIXEL_BYTES);
2857bf215546Sopenharmony_ci   else if (!convert_clear_buffer_data(ctx, mesaFormat, clearValue,
2858bf215546Sopenharmony_ci                                       format, type, data, func)) {
2859bf215546Sopenharmony_ci      return;
2860bf215546Sopenharmony_ci   }
2861bf215546Sopenharmony_ci
2862bf215546Sopenharmony_ci   ctx->pipe->clear_buffer(ctx->pipe, bufObj->buffer, offset, size,
2863bf215546Sopenharmony_ci                           clearValue, clearValueSize);
2864bf215546Sopenharmony_ci}
2865bf215546Sopenharmony_ci
2866bf215546Sopenharmony_cistatic void
2867bf215546Sopenharmony_ciclear_buffer_sub_data_error(struct gl_context *ctx,
2868bf215546Sopenharmony_ci                            struct gl_buffer_object *bufObj,
2869bf215546Sopenharmony_ci                            GLenum internalformat, GLintptr offset,
2870bf215546Sopenharmony_ci                            GLsizeiptr size, GLenum format, GLenum type,
2871bf215546Sopenharmony_ci                            const GLvoid *data, const char *func, bool subdata)
2872bf215546Sopenharmony_ci{
2873bf215546Sopenharmony_ci   clear_buffer_sub_data(ctx, bufObj, internalformat, offset, size, format,
2874bf215546Sopenharmony_ci                         type, data, func, subdata, false);
2875bf215546Sopenharmony_ci}
2876bf215546Sopenharmony_ci
2877bf215546Sopenharmony_ci
2878bf215546Sopenharmony_cistatic void
2879bf215546Sopenharmony_ciclear_buffer_sub_data_no_error(struct gl_context *ctx,
2880bf215546Sopenharmony_ci                               struct gl_buffer_object *bufObj,
2881bf215546Sopenharmony_ci                               GLenum internalformat, GLintptr offset,
2882bf215546Sopenharmony_ci                               GLsizeiptr size, GLenum format, GLenum type,
2883bf215546Sopenharmony_ci                               const GLvoid *data, const char *func,
2884bf215546Sopenharmony_ci                               bool subdata)
2885bf215546Sopenharmony_ci{
2886bf215546Sopenharmony_ci   clear_buffer_sub_data(ctx, bufObj, internalformat, offset, size, format,
2887bf215546Sopenharmony_ci                         type, data, func, subdata, true);
2888bf215546Sopenharmony_ci}
2889bf215546Sopenharmony_ci
2890bf215546Sopenharmony_ci
2891bf215546Sopenharmony_civoid GLAPIENTRY
2892bf215546Sopenharmony_ci_mesa_ClearBufferData_no_error(GLenum target, GLenum internalformat,
2893bf215546Sopenharmony_ci                               GLenum format, GLenum type, const GLvoid *data)
2894bf215546Sopenharmony_ci{
2895bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2896bf215546Sopenharmony_ci
2897bf215546Sopenharmony_ci   struct gl_buffer_object **bufObj = get_buffer_target(ctx, target);
2898bf215546Sopenharmony_ci   clear_buffer_sub_data_no_error(ctx, *bufObj, internalformat, 0,
2899bf215546Sopenharmony_ci                                  (*bufObj)->Size, format, type, data,
2900bf215546Sopenharmony_ci                                  "glClearBufferData", false);
2901bf215546Sopenharmony_ci}
2902bf215546Sopenharmony_ci
2903bf215546Sopenharmony_ci
2904bf215546Sopenharmony_civoid GLAPIENTRY
2905bf215546Sopenharmony_ci_mesa_ClearBufferData(GLenum target, GLenum internalformat, GLenum format,
2906bf215546Sopenharmony_ci                      GLenum type, const GLvoid *data)
2907bf215546Sopenharmony_ci{
2908bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2909bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
2910bf215546Sopenharmony_ci
2911bf215546Sopenharmony_ci   bufObj = get_buffer(ctx, "glClearBufferData", target, GL_INVALID_VALUE);
2912bf215546Sopenharmony_ci   if (!bufObj)
2913bf215546Sopenharmony_ci      return;
2914bf215546Sopenharmony_ci
2915bf215546Sopenharmony_ci   clear_buffer_sub_data_error(ctx, bufObj, internalformat, 0, bufObj->Size,
2916bf215546Sopenharmony_ci                               format, type, data, "glClearBufferData", false);
2917bf215546Sopenharmony_ci}
2918bf215546Sopenharmony_ci
2919bf215546Sopenharmony_ci
2920bf215546Sopenharmony_civoid GLAPIENTRY
2921bf215546Sopenharmony_ci_mesa_ClearNamedBufferData_no_error(GLuint buffer, GLenum internalformat,
2922bf215546Sopenharmony_ci                                    GLenum format, GLenum type,
2923bf215546Sopenharmony_ci                                    const GLvoid *data)
2924bf215546Sopenharmony_ci{
2925bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2926bf215546Sopenharmony_ci
2927bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
2928bf215546Sopenharmony_ci   clear_buffer_sub_data_no_error(ctx, bufObj, internalformat, 0, bufObj->Size,
2929bf215546Sopenharmony_ci                                  format, type, data, "glClearNamedBufferData",
2930bf215546Sopenharmony_ci                                  false);
2931bf215546Sopenharmony_ci}
2932bf215546Sopenharmony_ci
2933bf215546Sopenharmony_ci
2934bf215546Sopenharmony_civoid GLAPIENTRY
2935bf215546Sopenharmony_ci_mesa_ClearNamedBufferData(GLuint buffer, GLenum internalformat,
2936bf215546Sopenharmony_ci                           GLenum format, GLenum type, const GLvoid *data)
2937bf215546Sopenharmony_ci{
2938bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2939bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
2940bf215546Sopenharmony_ci
2941bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glClearNamedBufferData");
2942bf215546Sopenharmony_ci   if (!bufObj)
2943bf215546Sopenharmony_ci      return;
2944bf215546Sopenharmony_ci
2945bf215546Sopenharmony_ci   clear_buffer_sub_data_error(ctx, bufObj, internalformat, 0, bufObj->Size,
2946bf215546Sopenharmony_ci                               format, type, data, "glClearNamedBufferData",
2947bf215546Sopenharmony_ci                               false);
2948bf215546Sopenharmony_ci}
2949bf215546Sopenharmony_ci
2950bf215546Sopenharmony_ci
2951bf215546Sopenharmony_civoid GLAPIENTRY
2952bf215546Sopenharmony_ci_mesa_ClearNamedBufferDataEXT(GLuint buffer, GLenum internalformat,
2953bf215546Sopenharmony_ci                              GLenum format, GLenum type, const GLvoid *data)
2954bf215546Sopenharmony_ci{
2955bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2956bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
2957bf215546Sopenharmony_ci   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
2958bf215546Sopenharmony_ci                                     &bufObj, "glClearNamedBufferDataEXT", false))
2959bf215546Sopenharmony_ci      return;
2960bf215546Sopenharmony_ci
2961bf215546Sopenharmony_ci   clear_buffer_sub_data_error(ctx, bufObj, internalformat, 0, bufObj->Size,
2962bf215546Sopenharmony_ci                               format, type, data, "glClearNamedBufferDataEXT",
2963bf215546Sopenharmony_ci                               false);
2964bf215546Sopenharmony_ci}
2965bf215546Sopenharmony_ci
2966bf215546Sopenharmony_ci
2967bf215546Sopenharmony_civoid GLAPIENTRY
2968bf215546Sopenharmony_ci_mesa_ClearBufferSubData_no_error(GLenum target, GLenum internalformat,
2969bf215546Sopenharmony_ci                                  GLintptr offset, GLsizeiptr size,
2970bf215546Sopenharmony_ci                                  GLenum format, GLenum type,
2971bf215546Sopenharmony_ci                                  const GLvoid *data)
2972bf215546Sopenharmony_ci{
2973bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2974bf215546Sopenharmony_ci
2975bf215546Sopenharmony_ci   struct gl_buffer_object **bufObj = get_buffer_target(ctx, target);
2976bf215546Sopenharmony_ci   clear_buffer_sub_data_no_error(ctx, *bufObj, internalformat, offset, size,
2977bf215546Sopenharmony_ci                                  format, type, data, "glClearBufferSubData",
2978bf215546Sopenharmony_ci                                  true);
2979bf215546Sopenharmony_ci}
2980bf215546Sopenharmony_ci
2981bf215546Sopenharmony_ci
2982bf215546Sopenharmony_civoid GLAPIENTRY
2983bf215546Sopenharmony_ci_mesa_ClearBufferSubData(GLenum target, GLenum internalformat,
2984bf215546Sopenharmony_ci                         GLintptr offset, GLsizeiptr size,
2985bf215546Sopenharmony_ci                         GLenum format, GLenum type,
2986bf215546Sopenharmony_ci                         const GLvoid *data)
2987bf215546Sopenharmony_ci{
2988bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
2989bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
2990bf215546Sopenharmony_ci
2991bf215546Sopenharmony_ci   bufObj = get_buffer(ctx, "glClearBufferSubData", target, GL_INVALID_VALUE);
2992bf215546Sopenharmony_ci   if (!bufObj)
2993bf215546Sopenharmony_ci      return;
2994bf215546Sopenharmony_ci
2995bf215546Sopenharmony_ci   clear_buffer_sub_data_error(ctx, bufObj, internalformat, offset, size,
2996bf215546Sopenharmony_ci                               format, type, data, "glClearBufferSubData",
2997bf215546Sopenharmony_ci                               true);
2998bf215546Sopenharmony_ci}
2999bf215546Sopenharmony_ci
3000bf215546Sopenharmony_ci
3001bf215546Sopenharmony_civoid GLAPIENTRY
3002bf215546Sopenharmony_ci_mesa_ClearNamedBufferSubData_no_error(GLuint buffer, GLenum internalformat,
3003bf215546Sopenharmony_ci                                       GLintptr offset, GLsizeiptr size,
3004bf215546Sopenharmony_ci                                       GLenum format, GLenum type,
3005bf215546Sopenharmony_ci                                       const GLvoid *data)
3006bf215546Sopenharmony_ci{
3007bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3008bf215546Sopenharmony_ci
3009bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
3010bf215546Sopenharmony_ci   clear_buffer_sub_data_no_error(ctx, bufObj, internalformat, offset, size,
3011bf215546Sopenharmony_ci                                  format, type, data,
3012bf215546Sopenharmony_ci                                  "glClearNamedBufferSubData", true);
3013bf215546Sopenharmony_ci}
3014bf215546Sopenharmony_ci
3015bf215546Sopenharmony_ci
3016bf215546Sopenharmony_civoid GLAPIENTRY
3017bf215546Sopenharmony_ci_mesa_ClearNamedBufferSubData(GLuint buffer, GLenum internalformat,
3018bf215546Sopenharmony_ci                              GLintptr offset, GLsizeiptr size,
3019bf215546Sopenharmony_ci                              GLenum format, GLenum type,
3020bf215546Sopenharmony_ci                              const GLvoid *data)
3021bf215546Sopenharmony_ci{
3022bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3023bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
3024bf215546Sopenharmony_ci
3025bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer,
3026bf215546Sopenharmony_ci                                       "glClearNamedBufferSubData");
3027bf215546Sopenharmony_ci   if (!bufObj)
3028bf215546Sopenharmony_ci      return;
3029bf215546Sopenharmony_ci
3030bf215546Sopenharmony_ci   clear_buffer_sub_data_error(ctx, bufObj, internalformat, offset, size,
3031bf215546Sopenharmony_ci                               format, type, data, "glClearNamedBufferSubData",
3032bf215546Sopenharmony_ci                               true);
3033bf215546Sopenharmony_ci}
3034bf215546Sopenharmony_ci
3035bf215546Sopenharmony_civoid GLAPIENTRY
3036bf215546Sopenharmony_ci_mesa_ClearNamedBufferSubDataEXT(GLuint buffer, GLenum internalformat,
3037bf215546Sopenharmony_ci                                 GLintptr offset, GLsizeiptr size,
3038bf215546Sopenharmony_ci                                 GLenum format, GLenum type,
3039bf215546Sopenharmony_ci                                 const GLvoid *data)
3040bf215546Sopenharmony_ci{
3041bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3042bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
3043bf215546Sopenharmony_ci   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
3044bf215546Sopenharmony_ci                                     &bufObj, "glClearNamedBufferSubDataEXT", false))
3045bf215546Sopenharmony_ci      return;
3046bf215546Sopenharmony_ci
3047bf215546Sopenharmony_ci   clear_buffer_sub_data_error(ctx, bufObj, internalformat, offset, size,
3048bf215546Sopenharmony_ci                               format, type, data, "glClearNamedBufferSubDataEXT",
3049bf215546Sopenharmony_ci                               true);
3050bf215546Sopenharmony_ci}
3051bf215546Sopenharmony_ci
3052bf215546Sopenharmony_cistatic GLboolean
3053bf215546Sopenharmony_ciunmap_buffer(struct gl_context *ctx, struct gl_buffer_object *bufObj)
3054bf215546Sopenharmony_ci{
3055bf215546Sopenharmony_ci   GLboolean status = _mesa_bufferobj_unmap(ctx, bufObj, MAP_USER);
3056bf215546Sopenharmony_ci   bufObj->Mappings[MAP_USER].AccessFlags = 0;
3057bf215546Sopenharmony_ci   assert(bufObj->Mappings[MAP_USER].Pointer == NULL);
3058bf215546Sopenharmony_ci   assert(bufObj->Mappings[MAP_USER].Offset == 0);
3059bf215546Sopenharmony_ci   assert(bufObj->Mappings[MAP_USER].Length == 0);
3060bf215546Sopenharmony_ci
3061bf215546Sopenharmony_ci   return status;
3062bf215546Sopenharmony_ci}
3063bf215546Sopenharmony_ci
3064bf215546Sopenharmony_cistatic GLboolean
3065bf215546Sopenharmony_civalidate_and_unmap_buffer(struct gl_context *ctx,
3066bf215546Sopenharmony_ci                          struct gl_buffer_object *bufObj,
3067bf215546Sopenharmony_ci                          const char *func)
3068bf215546Sopenharmony_ci{
3069bf215546Sopenharmony_ci   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
3070bf215546Sopenharmony_ci
3071bf215546Sopenharmony_ci   if (!_mesa_bufferobj_mapped(bufObj, MAP_USER)) {
3072bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
3073bf215546Sopenharmony_ci                  "%s(buffer is not mapped)", func);
3074bf215546Sopenharmony_ci      return GL_FALSE;
3075bf215546Sopenharmony_ci   }
3076bf215546Sopenharmony_ci
3077bf215546Sopenharmony_ci#ifdef BOUNDS_CHECK
3078bf215546Sopenharmony_ci   if (bufObj->Mappings[MAP_USER].AccessFlags != GL_READ_ONLY_ARB) {
3079bf215546Sopenharmony_ci      GLubyte *buf = (GLubyte *) bufObj->Mappings[MAP_USER].Pointer;
3080bf215546Sopenharmony_ci      GLuint i;
3081bf215546Sopenharmony_ci      /* check that last 100 bytes are still = magic value */
3082bf215546Sopenharmony_ci      for (i = 0; i < 100; i++) {
3083bf215546Sopenharmony_ci         GLuint pos = bufObj->Size - i - 1;
3084bf215546Sopenharmony_ci         if (buf[pos] != 123) {
3085bf215546Sopenharmony_ci            _mesa_warning(ctx, "Out of bounds buffer object write detected"
3086bf215546Sopenharmony_ci                          " at position %d (value = %u)\n",
3087bf215546Sopenharmony_ci                          pos, buf[pos]);
3088bf215546Sopenharmony_ci         }
3089bf215546Sopenharmony_ci      }
3090bf215546Sopenharmony_ci   }
3091bf215546Sopenharmony_ci#endif
3092bf215546Sopenharmony_ci
3093bf215546Sopenharmony_ci#ifdef VBO_DEBUG
3094bf215546Sopenharmony_ci   if (bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_WRITE_BIT) {
3095bf215546Sopenharmony_ci      GLuint i, unchanged = 0;
3096bf215546Sopenharmony_ci      GLubyte *b = (GLubyte *) bufObj->Mappings[MAP_USER].Pointer;
3097bf215546Sopenharmony_ci      GLint pos = -1;
3098bf215546Sopenharmony_ci      /* check which bytes changed */
3099bf215546Sopenharmony_ci      for (i = 0; i < bufObj->Size - 1; i++) {
3100bf215546Sopenharmony_ci         if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) {
3101bf215546Sopenharmony_ci            unchanged++;
3102bf215546Sopenharmony_ci            if (pos == -1)
3103bf215546Sopenharmony_ci               pos = i;
3104bf215546Sopenharmony_ci         }
3105bf215546Sopenharmony_ci      }
3106bf215546Sopenharmony_ci      if (unchanged) {
3107bf215546Sopenharmony_ci         printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n",
3108bf215546Sopenharmony_ci                      bufObj->Name, unchanged, bufObj->Size, pos);
3109bf215546Sopenharmony_ci      }
3110bf215546Sopenharmony_ci   }
3111bf215546Sopenharmony_ci#endif
3112bf215546Sopenharmony_ci
3113bf215546Sopenharmony_ci   return unmap_buffer(ctx, bufObj);
3114bf215546Sopenharmony_ci}
3115bf215546Sopenharmony_ci
3116bf215546Sopenharmony_ciGLboolean GLAPIENTRY
3117bf215546Sopenharmony_ci_mesa_UnmapBuffer_no_error(GLenum target)
3118bf215546Sopenharmony_ci{
3119bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3120bf215546Sopenharmony_ci   struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target);
3121bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj = *bufObjPtr;
3122bf215546Sopenharmony_ci
3123bf215546Sopenharmony_ci   return unmap_buffer(ctx, bufObj);
3124bf215546Sopenharmony_ci}
3125bf215546Sopenharmony_ci
3126bf215546Sopenharmony_ciGLboolean GLAPIENTRY
3127bf215546Sopenharmony_ci_mesa_UnmapBuffer(GLenum target)
3128bf215546Sopenharmony_ci{
3129bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3130bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
3131bf215546Sopenharmony_ci
3132bf215546Sopenharmony_ci   bufObj = get_buffer(ctx, "glUnmapBuffer", target, GL_INVALID_OPERATION);
3133bf215546Sopenharmony_ci   if (!bufObj)
3134bf215546Sopenharmony_ci      return GL_FALSE;
3135bf215546Sopenharmony_ci
3136bf215546Sopenharmony_ci   return validate_and_unmap_buffer(ctx, bufObj, "glUnmapBuffer");
3137bf215546Sopenharmony_ci}
3138bf215546Sopenharmony_ci
3139bf215546Sopenharmony_ciGLboolean GLAPIENTRY
3140bf215546Sopenharmony_ci_mesa_UnmapNamedBufferEXT_no_error(GLuint buffer)
3141bf215546Sopenharmony_ci{
3142bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3143bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
3144bf215546Sopenharmony_ci
3145bf215546Sopenharmony_ci   return unmap_buffer(ctx, bufObj);
3146bf215546Sopenharmony_ci}
3147bf215546Sopenharmony_ci
3148bf215546Sopenharmony_ciGLboolean GLAPIENTRY
3149bf215546Sopenharmony_ci_mesa_UnmapNamedBufferEXT(GLuint buffer)
3150bf215546Sopenharmony_ci{
3151bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3152bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
3153bf215546Sopenharmony_ci
3154bf215546Sopenharmony_ci   if (!buffer) {
3155bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
3156bf215546Sopenharmony_ci                  "glUnmapNamedBufferEXT(buffer=0)");
3157bf215546Sopenharmony_ci      return GL_FALSE;
3158bf215546Sopenharmony_ci   }
3159bf215546Sopenharmony_ci
3160bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glUnmapNamedBuffer");
3161bf215546Sopenharmony_ci   if (!bufObj)
3162bf215546Sopenharmony_ci      return GL_FALSE;
3163bf215546Sopenharmony_ci
3164bf215546Sopenharmony_ci   return validate_and_unmap_buffer(ctx, bufObj, "glUnmapNamedBuffer");
3165bf215546Sopenharmony_ci}
3166bf215546Sopenharmony_ci
3167bf215546Sopenharmony_ci
3168bf215546Sopenharmony_cistatic bool
3169bf215546Sopenharmony_ciget_buffer_parameter(struct gl_context *ctx,
3170bf215546Sopenharmony_ci                     struct gl_buffer_object *bufObj, GLenum pname,
3171bf215546Sopenharmony_ci                     GLint64 *params, const char *func)
3172bf215546Sopenharmony_ci{
3173bf215546Sopenharmony_ci   switch (pname) {
3174bf215546Sopenharmony_ci   case GL_BUFFER_SIZE_ARB:
3175bf215546Sopenharmony_ci      *params = bufObj->Size;
3176bf215546Sopenharmony_ci      break;
3177bf215546Sopenharmony_ci   case GL_BUFFER_USAGE_ARB:
3178bf215546Sopenharmony_ci      *params = bufObj->Usage;
3179bf215546Sopenharmony_ci      break;
3180bf215546Sopenharmony_ci   case GL_BUFFER_ACCESS_ARB:
3181bf215546Sopenharmony_ci      *params = simplified_access_mode(ctx,
3182bf215546Sopenharmony_ci                            bufObj->Mappings[MAP_USER].AccessFlags);
3183bf215546Sopenharmony_ci      break;
3184bf215546Sopenharmony_ci   case GL_BUFFER_MAPPED_ARB:
3185bf215546Sopenharmony_ci      *params = _mesa_bufferobj_mapped(bufObj, MAP_USER);
3186bf215546Sopenharmony_ci      break;
3187bf215546Sopenharmony_ci   case GL_BUFFER_ACCESS_FLAGS:
3188bf215546Sopenharmony_ci      if (!ctx->Extensions.ARB_map_buffer_range)
3189bf215546Sopenharmony_ci         goto invalid_pname;
3190bf215546Sopenharmony_ci      *params = bufObj->Mappings[MAP_USER].AccessFlags;
3191bf215546Sopenharmony_ci      break;
3192bf215546Sopenharmony_ci   case GL_BUFFER_MAP_OFFSET:
3193bf215546Sopenharmony_ci      if (!ctx->Extensions.ARB_map_buffer_range)
3194bf215546Sopenharmony_ci         goto invalid_pname;
3195bf215546Sopenharmony_ci      *params = bufObj->Mappings[MAP_USER].Offset;
3196bf215546Sopenharmony_ci      break;
3197bf215546Sopenharmony_ci   case GL_BUFFER_MAP_LENGTH:
3198bf215546Sopenharmony_ci      if (!ctx->Extensions.ARB_map_buffer_range)
3199bf215546Sopenharmony_ci         goto invalid_pname;
3200bf215546Sopenharmony_ci      *params = bufObj->Mappings[MAP_USER].Length;
3201bf215546Sopenharmony_ci      break;
3202bf215546Sopenharmony_ci   case GL_BUFFER_IMMUTABLE_STORAGE:
3203bf215546Sopenharmony_ci      if (!ctx->Extensions.ARB_buffer_storage)
3204bf215546Sopenharmony_ci         goto invalid_pname;
3205bf215546Sopenharmony_ci      *params = bufObj->Immutable;
3206bf215546Sopenharmony_ci      break;
3207bf215546Sopenharmony_ci   case GL_BUFFER_STORAGE_FLAGS:
3208bf215546Sopenharmony_ci      if (!ctx->Extensions.ARB_buffer_storage)
3209bf215546Sopenharmony_ci         goto invalid_pname;
3210bf215546Sopenharmony_ci      *params = bufObj->StorageFlags;
3211bf215546Sopenharmony_ci      break;
3212bf215546Sopenharmony_ci   default:
3213bf215546Sopenharmony_ci      goto invalid_pname;
3214bf215546Sopenharmony_ci   }
3215bf215546Sopenharmony_ci
3216bf215546Sopenharmony_ci   return true;
3217bf215546Sopenharmony_ci
3218bf215546Sopenharmony_ciinvalid_pname:
3219bf215546Sopenharmony_ci   _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname: %s)", func,
3220bf215546Sopenharmony_ci               _mesa_enum_to_string(pname));
3221bf215546Sopenharmony_ci   return false;
3222bf215546Sopenharmony_ci}
3223bf215546Sopenharmony_ci
3224bf215546Sopenharmony_civoid GLAPIENTRY
3225bf215546Sopenharmony_ci_mesa_GetBufferParameteriv(GLenum target, GLenum pname, GLint *params)
3226bf215546Sopenharmony_ci{
3227bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3228bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
3229bf215546Sopenharmony_ci   GLint64 parameter;
3230bf215546Sopenharmony_ci
3231bf215546Sopenharmony_ci   bufObj = get_buffer(ctx, "glGetBufferParameteriv", target,
3232bf215546Sopenharmony_ci                       GL_INVALID_OPERATION);
3233bf215546Sopenharmony_ci   if (!bufObj)
3234bf215546Sopenharmony_ci      return;
3235bf215546Sopenharmony_ci
3236bf215546Sopenharmony_ci   if (!get_buffer_parameter(ctx, bufObj, pname, &parameter,
3237bf215546Sopenharmony_ci                             "glGetBufferParameteriv"))
3238bf215546Sopenharmony_ci      return; /* Error already recorded. */
3239bf215546Sopenharmony_ci
3240bf215546Sopenharmony_ci   *params = (GLint) parameter;
3241bf215546Sopenharmony_ci}
3242bf215546Sopenharmony_ci
3243bf215546Sopenharmony_civoid GLAPIENTRY
3244bf215546Sopenharmony_ci_mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params)
3245bf215546Sopenharmony_ci{
3246bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3247bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
3248bf215546Sopenharmony_ci   GLint64 parameter;
3249bf215546Sopenharmony_ci
3250bf215546Sopenharmony_ci   bufObj = get_buffer(ctx, "glGetBufferParameteri64v", target,
3251bf215546Sopenharmony_ci                       GL_INVALID_OPERATION);
3252bf215546Sopenharmony_ci   if (!bufObj)
3253bf215546Sopenharmony_ci      return;
3254bf215546Sopenharmony_ci
3255bf215546Sopenharmony_ci   if (!get_buffer_parameter(ctx, bufObj, pname, &parameter,
3256bf215546Sopenharmony_ci                             "glGetBufferParameteri64v"))
3257bf215546Sopenharmony_ci      return; /* Error already recorded. */
3258bf215546Sopenharmony_ci
3259bf215546Sopenharmony_ci   *params = parameter;
3260bf215546Sopenharmony_ci}
3261bf215546Sopenharmony_ci
3262bf215546Sopenharmony_civoid GLAPIENTRY
3263bf215546Sopenharmony_ci_mesa_GetNamedBufferParameteriv(GLuint buffer, GLenum pname, GLint *params)
3264bf215546Sopenharmony_ci{
3265bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3266bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
3267bf215546Sopenharmony_ci   GLint64 parameter;
3268bf215546Sopenharmony_ci
3269bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer,
3270bf215546Sopenharmony_ci                                       "glGetNamedBufferParameteriv");
3271bf215546Sopenharmony_ci   if (!bufObj)
3272bf215546Sopenharmony_ci      return;
3273bf215546Sopenharmony_ci
3274bf215546Sopenharmony_ci   if (!get_buffer_parameter(ctx, bufObj, pname, &parameter,
3275bf215546Sopenharmony_ci                             "glGetNamedBufferParameteriv"))
3276bf215546Sopenharmony_ci      return; /* Error already recorded. */
3277bf215546Sopenharmony_ci
3278bf215546Sopenharmony_ci   *params = (GLint) parameter;
3279bf215546Sopenharmony_ci}
3280bf215546Sopenharmony_ci
3281bf215546Sopenharmony_civoid GLAPIENTRY
3282bf215546Sopenharmony_ci_mesa_GetNamedBufferParameterivEXT(GLuint buffer, GLenum pname, GLint *params)
3283bf215546Sopenharmony_ci{
3284bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3285bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
3286bf215546Sopenharmony_ci   GLint64 parameter;
3287bf215546Sopenharmony_ci
3288bf215546Sopenharmony_ci   if (!buffer) {
3289bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
3290bf215546Sopenharmony_ci                  "glGetNamedBufferParameterivEXT: buffer=0");
3291bf215546Sopenharmony_ci      return;
3292bf215546Sopenharmony_ci   }
3293bf215546Sopenharmony_ci
3294bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
3295bf215546Sopenharmony_ci   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
3296bf215546Sopenharmony_ci                                     &bufObj, "glGetNamedBufferParameterivEXT", false))
3297bf215546Sopenharmony_ci      return;
3298bf215546Sopenharmony_ci
3299bf215546Sopenharmony_ci   if (!get_buffer_parameter(ctx, bufObj, pname, &parameter,
3300bf215546Sopenharmony_ci                             "glGetNamedBufferParameterivEXT"))
3301bf215546Sopenharmony_ci      return; /* Error already recorded. */
3302bf215546Sopenharmony_ci
3303bf215546Sopenharmony_ci   *params = (GLint) parameter;
3304bf215546Sopenharmony_ci}
3305bf215546Sopenharmony_ci
3306bf215546Sopenharmony_civoid GLAPIENTRY
3307bf215546Sopenharmony_ci_mesa_GetNamedBufferParameteri64v(GLuint buffer, GLenum pname,
3308bf215546Sopenharmony_ci                                  GLint64 *params)
3309bf215546Sopenharmony_ci{
3310bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3311bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
3312bf215546Sopenharmony_ci   GLint64 parameter;
3313bf215546Sopenharmony_ci
3314bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer,
3315bf215546Sopenharmony_ci                                       "glGetNamedBufferParameteri64v");
3316bf215546Sopenharmony_ci   if (!bufObj)
3317bf215546Sopenharmony_ci      return;
3318bf215546Sopenharmony_ci
3319bf215546Sopenharmony_ci   if (!get_buffer_parameter(ctx, bufObj, pname, &parameter,
3320bf215546Sopenharmony_ci                             "glGetNamedBufferParameteri64v"))
3321bf215546Sopenharmony_ci      return; /* Error already recorded. */
3322bf215546Sopenharmony_ci
3323bf215546Sopenharmony_ci   *params = parameter;
3324bf215546Sopenharmony_ci}
3325bf215546Sopenharmony_ci
3326bf215546Sopenharmony_ci
3327bf215546Sopenharmony_civoid GLAPIENTRY
3328bf215546Sopenharmony_ci_mesa_GetBufferPointerv(GLenum target, GLenum pname, GLvoid **params)
3329bf215546Sopenharmony_ci{
3330bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3331bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
3332bf215546Sopenharmony_ci
3333bf215546Sopenharmony_ci   if (pname != GL_BUFFER_MAP_POINTER) {
3334bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointerv(pname != "
3335bf215546Sopenharmony_ci                  "GL_BUFFER_MAP_POINTER)");
3336bf215546Sopenharmony_ci      return;
3337bf215546Sopenharmony_ci   }
3338bf215546Sopenharmony_ci
3339bf215546Sopenharmony_ci   bufObj = get_buffer(ctx, "glGetBufferPointerv", target,
3340bf215546Sopenharmony_ci                       GL_INVALID_OPERATION);
3341bf215546Sopenharmony_ci   if (!bufObj)
3342bf215546Sopenharmony_ci      return;
3343bf215546Sopenharmony_ci
3344bf215546Sopenharmony_ci   *params = bufObj->Mappings[MAP_USER].Pointer;
3345bf215546Sopenharmony_ci}
3346bf215546Sopenharmony_ci
3347bf215546Sopenharmony_civoid GLAPIENTRY
3348bf215546Sopenharmony_ci_mesa_GetNamedBufferPointerv(GLuint buffer, GLenum pname, GLvoid **params)
3349bf215546Sopenharmony_ci{
3350bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3351bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
3352bf215546Sopenharmony_ci
3353bf215546Sopenharmony_ci   if (pname != GL_BUFFER_MAP_POINTER) {
3354bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glGetNamedBufferPointerv(pname != "
3355bf215546Sopenharmony_ci                  "GL_BUFFER_MAP_POINTER)");
3356bf215546Sopenharmony_ci      return;
3357bf215546Sopenharmony_ci   }
3358bf215546Sopenharmony_ci
3359bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer,
3360bf215546Sopenharmony_ci                                       "glGetNamedBufferPointerv");
3361bf215546Sopenharmony_ci   if (!bufObj)
3362bf215546Sopenharmony_ci      return;
3363bf215546Sopenharmony_ci
3364bf215546Sopenharmony_ci   *params = bufObj->Mappings[MAP_USER].Pointer;
3365bf215546Sopenharmony_ci}
3366bf215546Sopenharmony_ci
3367bf215546Sopenharmony_civoid GLAPIENTRY
3368bf215546Sopenharmony_ci_mesa_GetNamedBufferPointervEXT(GLuint buffer, GLenum pname, GLvoid **params)
3369bf215546Sopenharmony_ci{
3370bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3371bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
3372bf215546Sopenharmony_ci
3373bf215546Sopenharmony_ci   if (!buffer) {
3374bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
3375bf215546Sopenharmony_ci                  "glGetNamedBufferPointervEXT(buffer=0)");
3376bf215546Sopenharmony_ci      return;
3377bf215546Sopenharmony_ci   }
3378bf215546Sopenharmony_ci   if (pname != GL_BUFFER_MAP_POINTER) {
3379bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glGetNamedBufferPointervEXT(pname != "
3380bf215546Sopenharmony_ci                  "GL_BUFFER_MAP_POINTER)");
3381bf215546Sopenharmony_ci      return;
3382bf215546Sopenharmony_ci   }
3383bf215546Sopenharmony_ci
3384bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
3385bf215546Sopenharmony_ci   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
3386bf215546Sopenharmony_ci                                     &bufObj, "glGetNamedBufferPointervEXT", false))
3387bf215546Sopenharmony_ci      return;
3388bf215546Sopenharmony_ci
3389bf215546Sopenharmony_ci   *params = bufObj->Mappings[MAP_USER].Pointer;
3390bf215546Sopenharmony_ci}
3391bf215546Sopenharmony_ci
3392bf215546Sopenharmony_cistatic void
3393bf215546Sopenharmony_cicopy_buffer_sub_data(struct gl_context *ctx, struct gl_buffer_object *src,
3394bf215546Sopenharmony_ci                     struct gl_buffer_object *dst, GLintptr readOffset,
3395bf215546Sopenharmony_ci                     GLintptr writeOffset, GLsizeiptr size, const char *func)
3396bf215546Sopenharmony_ci{
3397bf215546Sopenharmony_ci   if (_mesa_check_disallowed_mapping(src)) {
3398bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
3399bf215546Sopenharmony_ci                  "%s(readBuffer is mapped)", func);
3400bf215546Sopenharmony_ci      return;
3401bf215546Sopenharmony_ci   }
3402bf215546Sopenharmony_ci
3403bf215546Sopenharmony_ci   if (_mesa_check_disallowed_mapping(dst)) {
3404bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
3405bf215546Sopenharmony_ci                  "%s(writeBuffer is mapped)", func);
3406bf215546Sopenharmony_ci      return;
3407bf215546Sopenharmony_ci   }
3408bf215546Sopenharmony_ci
3409bf215546Sopenharmony_ci   if (readOffset < 0) {
3410bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
3411bf215546Sopenharmony_ci                  "%s(readOffset %d < 0)", func, (int) readOffset);
3412bf215546Sopenharmony_ci      return;
3413bf215546Sopenharmony_ci   }
3414bf215546Sopenharmony_ci
3415bf215546Sopenharmony_ci   if (writeOffset < 0) {
3416bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
3417bf215546Sopenharmony_ci                  "%s(writeOffset %d < 0)", func, (int) writeOffset);
3418bf215546Sopenharmony_ci      return;
3419bf215546Sopenharmony_ci   }
3420bf215546Sopenharmony_ci
3421bf215546Sopenharmony_ci   if (size < 0) {
3422bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
3423bf215546Sopenharmony_ci                  "%s(size %d < 0)", func, (int) size);
3424bf215546Sopenharmony_ci      return;
3425bf215546Sopenharmony_ci   }
3426bf215546Sopenharmony_ci
3427bf215546Sopenharmony_ci   if (readOffset + size > src->Size) {
3428bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
3429bf215546Sopenharmony_ci                  "%s(readOffset %d + size %d > src_buffer_size %d)", func,
3430bf215546Sopenharmony_ci                  (int) readOffset, (int) size, (int) src->Size);
3431bf215546Sopenharmony_ci      return;
3432bf215546Sopenharmony_ci   }
3433bf215546Sopenharmony_ci
3434bf215546Sopenharmony_ci   if (writeOffset + size > dst->Size) {
3435bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
3436bf215546Sopenharmony_ci                  "%s(writeOffset %d + size %d > dst_buffer_size %d)", func,
3437bf215546Sopenharmony_ci                  (int) writeOffset, (int) size, (int) dst->Size);
3438bf215546Sopenharmony_ci      return;
3439bf215546Sopenharmony_ci   }
3440bf215546Sopenharmony_ci
3441bf215546Sopenharmony_ci   if (src == dst) {
3442bf215546Sopenharmony_ci      if (readOffset + size <= writeOffset) {
3443bf215546Sopenharmony_ci         /* OK */
3444bf215546Sopenharmony_ci      }
3445bf215546Sopenharmony_ci      else if (writeOffset + size <= readOffset) {
3446bf215546Sopenharmony_ci         /* OK */
3447bf215546Sopenharmony_ci      }
3448bf215546Sopenharmony_ci      else {
3449bf215546Sopenharmony_ci         /* overlapping src/dst is illegal */
3450bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_VALUE,
3451bf215546Sopenharmony_ci                     "%s(overlapping src/dst)", func);
3452bf215546Sopenharmony_ci         return;
3453bf215546Sopenharmony_ci      }
3454bf215546Sopenharmony_ci   }
3455bf215546Sopenharmony_ci
3456bf215546Sopenharmony_ci   bufferobj_copy_subdata(ctx, src, dst, readOffset, writeOffset, size);
3457bf215546Sopenharmony_ci}
3458bf215546Sopenharmony_ci
3459bf215546Sopenharmony_civoid GLAPIENTRY
3460bf215546Sopenharmony_ci_mesa_CopyBufferSubData_no_error(GLenum readTarget, GLenum writeTarget,
3461bf215546Sopenharmony_ci                                 GLintptr readOffset, GLintptr writeOffset,
3462bf215546Sopenharmony_ci                                 GLsizeiptr size)
3463bf215546Sopenharmony_ci{
3464bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3465bf215546Sopenharmony_ci
3466bf215546Sopenharmony_ci   struct gl_buffer_object **src_ptr = get_buffer_target(ctx, readTarget);
3467bf215546Sopenharmony_ci   struct gl_buffer_object *src = *src_ptr;
3468bf215546Sopenharmony_ci
3469bf215546Sopenharmony_ci   struct gl_buffer_object **dst_ptr = get_buffer_target(ctx, writeTarget);
3470bf215546Sopenharmony_ci   struct gl_buffer_object *dst = *dst_ptr;
3471bf215546Sopenharmony_ci
3472bf215546Sopenharmony_ci   bufferobj_copy_subdata(ctx, src, dst, readOffset, writeOffset,
3473bf215546Sopenharmony_ci                       size);
3474bf215546Sopenharmony_ci}
3475bf215546Sopenharmony_ci
3476bf215546Sopenharmony_civoid GLAPIENTRY
3477bf215546Sopenharmony_ci_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
3478bf215546Sopenharmony_ci                        GLintptr readOffset, GLintptr writeOffset,
3479bf215546Sopenharmony_ci                        GLsizeiptr size)
3480bf215546Sopenharmony_ci{
3481bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3482bf215546Sopenharmony_ci   struct gl_buffer_object *src, *dst;
3483bf215546Sopenharmony_ci
3484bf215546Sopenharmony_ci   src = get_buffer(ctx, "glCopyBufferSubData", readTarget,
3485bf215546Sopenharmony_ci                    GL_INVALID_OPERATION);
3486bf215546Sopenharmony_ci   if (!src)
3487bf215546Sopenharmony_ci      return;
3488bf215546Sopenharmony_ci
3489bf215546Sopenharmony_ci   dst = get_buffer(ctx, "glCopyBufferSubData", writeTarget,
3490bf215546Sopenharmony_ci                    GL_INVALID_OPERATION);
3491bf215546Sopenharmony_ci   if (!dst)
3492bf215546Sopenharmony_ci      return;
3493bf215546Sopenharmony_ci
3494bf215546Sopenharmony_ci   copy_buffer_sub_data(ctx, src, dst, readOffset, writeOffset, size,
3495bf215546Sopenharmony_ci                        "glCopyBufferSubData");
3496bf215546Sopenharmony_ci}
3497bf215546Sopenharmony_ci
3498bf215546Sopenharmony_civoid GLAPIENTRY
3499bf215546Sopenharmony_ci_mesa_NamedCopyBufferSubDataEXT(GLuint readBuffer, GLuint writeBuffer,
3500bf215546Sopenharmony_ci                                GLintptr readOffset, GLintptr writeOffset,
3501bf215546Sopenharmony_ci                                GLsizeiptr size)
3502bf215546Sopenharmony_ci{
3503bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3504bf215546Sopenharmony_ci   struct gl_buffer_object *src, *dst;
3505bf215546Sopenharmony_ci
3506bf215546Sopenharmony_ci   src = _mesa_lookup_bufferobj(ctx, readBuffer);
3507bf215546Sopenharmony_ci   if (!_mesa_handle_bind_buffer_gen(ctx, readBuffer,
3508bf215546Sopenharmony_ci                                     &src,
3509bf215546Sopenharmony_ci                                     "glNamedCopyBufferSubDataEXT", false))
3510bf215546Sopenharmony_ci      return;
3511bf215546Sopenharmony_ci
3512bf215546Sopenharmony_ci   dst = _mesa_lookup_bufferobj(ctx, writeBuffer);
3513bf215546Sopenharmony_ci   if (!_mesa_handle_bind_buffer_gen(ctx, writeBuffer,
3514bf215546Sopenharmony_ci                                     &dst,
3515bf215546Sopenharmony_ci                                     "glNamedCopyBufferSubDataEXT", false))
3516bf215546Sopenharmony_ci      return;
3517bf215546Sopenharmony_ci
3518bf215546Sopenharmony_ci   copy_buffer_sub_data(ctx, src, dst, readOffset, writeOffset, size,
3519bf215546Sopenharmony_ci                        "glNamedCopyBufferSubDataEXT");
3520bf215546Sopenharmony_ci}
3521bf215546Sopenharmony_ci
3522bf215546Sopenharmony_civoid GLAPIENTRY
3523bf215546Sopenharmony_ci_mesa_CopyNamedBufferSubData_no_error(GLuint readBuffer, GLuint writeBuffer,
3524bf215546Sopenharmony_ci                                      GLintptr readOffset,
3525bf215546Sopenharmony_ci                                      GLintptr writeOffset, GLsizeiptr size)
3526bf215546Sopenharmony_ci{
3527bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3528bf215546Sopenharmony_ci
3529bf215546Sopenharmony_ci   struct gl_buffer_object *src = _mesa_lookup_bufferobj(ctx, readBuffer);
3530bf215546Sopenharmony_ci   struct gl_buffer_object *dst = _mesa_lookup_bufferobj(ctx, writeBuffer);
3531bf215546Sopenharmony_ci
3532bf215546Sopenharmony_ci   bufferobj_copy_subdata(ctx, src, dst, readOffset, writeOffset,
3533bf215546Sopenharmony_ci                       size);
3534bf215546Sopenharmony_ci}
3535bf215546Sopenharmony_ci
3536bf215546Sopenharmony_civoid GLAPIENTRY
3537bf215546Sopenharmony_ci_mesa_CopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer,
3538bf215546Sopenharmony_ci                             GLintptr readOffset, GLintptr writeOffset,
3539bf215546Sopenharmony_ci                             GLsizeiptr size)
3540bf215546Sopenharmony_ci{
3541bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3542bf215546Sopenharmony_ci   struct gl_buffer_object *src, *dst;
3543bf215546Sopenharmony_ci
3544bf215546Sopenharmony_ci   src = _mesa_lookup_bufferobj_err(ctx, readBuffer,
3545bf215546Sopenharmony_ci                                    "glCopyNamedBufferSubData");
3546bf215546Sopenharmony_ci   if (!src)
3547bf215546Sopenharmony_ci      return;
3548bf215546Sopenharmony_ci
3549bf215546Sopenharmony_ci   dst = _mesa_lookup_bufferobj_err(ctx, writeBuffer,
3550bf215546Sopenharmony_ci                                    "glCopyNamedBufferSubData");
3551bf215546Sopenharmony_ci   if (!dst)
3552bf215546Sopenharmony_ci      return;
3553bf215546Sopenharmony_ci
3554bf215546Sopenharmony_ci   copy_buffer_sub_data(ctx, src, dst, readOffset, writeOffset, size,
3555bf215546Sopenharmony_ci                        "glCopyNamedBufferSubData");
3556bf215546Sopenharmony_ci}
3557bf215546Sopenharmony_ci
3558bf215546Sopenharmony_civoid GLAPIENTRY
3559bf215546Sopenharmony_ci_mesa_InternalBufferSubDataCopyMESA(GLintptr srcBuffer, GLuint srcOffset,
3560bf215546Sopenharmony_ci                                    GLuint dstTargetOrName, GLintptr dstOffset,
3561bf215546Sopenharmony_ci                                    GLsizeiptr size, GLboolean named,
3562bf215546Sopenharmony_ci                                    GLboolean ext_dsa)
3563bf215546Sopenharmony_ci{
3564bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3565bf215546Sopenharmony_ci   struct gl_buffer_object *src = (struct gl_buffer_object *)srcBuffer;
3566bf215546Sopenharmony_ci   struct gl_buffer_object *dst;
3567bf215546Sopenharmony_ci   const char *func;
3568bf215546Sopenharmony_ci
3569bf215546Sopenharmony_ci   /* Handle behavior for all 3 variants. */
3570bf215546Sopenharmony_ci   if (named && ext_dsa) {
3571bf215546Sopenharmony_ci      func = "glNamedBufferSubDataEXT";
3572bf215546Sopenharmony_ci      dst = _mesa_lookup_bufferobj(ctx, dstTargetOrName);
3573bf215546Sopenharmony_ci      if (!_mesa_handle_bind_buffer_gen(ctx, dstTargetOrName, &dst, func, false))
3574bf215546Sopenharmony_ci         goto done;
3575bf215546Sopenharmony_ci   } else if (named) {
3576bf215546Sopenharmony_ci      func = "glNamedBufferSubData";
3577bf215546Sopenharmony_ci      dst = _mesa_lookup_bufferobj_err(ctx, dstTargetOrName, func);
3578bf215546Sopenharmony_ci      if (!dst)
3579bf215546Sopenharmony_ci         goto done;
3580bf215546Sopenharmony_ci   } else {
3581bf215546Sopenharmony_ci      assert(!ext_dsa);
3582bf215546Sopenharmony_ci      func = "glBufferSubData";
3583bf215546Sopenharmony_ci      dst = get_buffer(ctx, func, dstTargetOrName, GL_INVALID_OPERATION);
3584bf215546Sopenharmony_ci      if (!dst)
3585bf215546Sopenharmony_ci         goto done;
3586bf215546Sopenharmony_ci   }
3587bf215546Sopenharmony_ci
3588bf215546Sopenharmony_ci   if (!validate_buffer_sub_data(ctx, dst, dstOffset, size, func))
3589bf215546Sopenharmony_ci      goto done; /* the error is already set */
3590bf215546Sopenharmony_ci
3591bf215546Sopenharmony_ci   bufferobj_copy_subdata(ctx, src, dst, srcOffset, dstOffset, size);
3592bf215546Sopenharmony_ci
3593bf215546Sopenharmony_cidone:
3594bf215546Sopenharmony_ci   /* The caller passes the reference to this function, so unreference it. */
3595bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &src, NULL);
3596bf215546Sopenharmony_ci}
3597bf215546Sopenharmony_ci
3598bf215546Sopenharmony_cistatic bool
3599bf215546Sopenharmony_civalidate_map_buffer_range(struct gl_context *ctx,
3600bf215546Sopenharmony_ci                          struct gl_buffer_object *bufObj, GLintptr offset,
3601bf215546Sopenharmony_ci                          GLsizeiptr length, GLbitfield access,
3602bf215546Sopenharmony_ci                          const char *func)
3603bf215546Sopenharmony_ci{
3604bf215546Sopenharmony_ci   GLbitfield allowed_access;
3605bf215546Sopenharmony_ci
3606bf215546Sopenharmony_ci   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, false);
3607bf215546Sopenharmony_ci
3608bf215546Sopenharmony_ci   if (offset < 0) {
3609bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
3610bf215546Sopenharmony_ci                  "%s(offset %ld < 0)", func, (long) offset);
3611bf215546Sopenharmony_ci      return false;
3612bf215546Sopenharmony_ci   }
3613bf215546Sopenharmony_ci
3614bf215546Sopenharmony_ci   if (length < 0) {
3615bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
3616bf215546Sopenharmony_ci                  "%s(length %ld < 0)", func, (long) length);
3617bf215546Sopenharmony_ci      return false;
3618bf215546Sopenharmony_ci   }
3619bf215546Sopenharmony_ci
3620bf215546Sopenharmony_ci   /* Page 38 of the PDF of the OpenGL ES 3.0 spec says:
3621bf215546Sopenharmony_ci    *
3622bf215546Sopenharmony_ci    *     "An INVALID_OPERATION error is generated for any of the following
3623bf215546Sopenharmony_ci    *     conditions:
3624bf215546Sopenharmony_ci    *
3625bf215546Sopenharmony_ci    *     * <length> is zero."
3626bf215546Sopenharmony_ci    *
3627bf215546Sopenharmony_ci    * Additionally, page 94 of the PDF of the OpenGL 4.5 core spec
3628bf215546Sopenharmony_ci    * (30.10.2014) also says this, so it's no longer allowed for desktop GL,
3629bf215546Sopenharmony_ci    * either.
3630bf215546Sopenharmony_ci    */
3631bf215546Sopenharmony_ci   if (length == 0) {
3632bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(length = 0)", func);
3633bf215546Sopenharmony_ci      return false;
3634bf215546Sopenharmony_ci   }
3635bf215546Sopenharmony_ci
3636bf215546Sopenharmony_ci   allowed_access = GL_MAP_READ_BIT |
3637bf215546Sopenharmony_ci                    GL_MAP_WRITE_BIT |
3638bf215546Sopenharmony_ci                    GL_MAP_INVALIDATE_RANGE_BIT |
3639bf215546Sopenharmony_ci                    GL_MAP_INVALIDATE_BUFFER_BIT |
3640bf215546Sopenharmony_ci                    GL_MAP_FLUSH_EXPLICIT_BIT |
3641bf215546Sopenharmony_ci                    GL_MAP_UNSYNCHRONIZED_BIT;
3642bf215546Sopenharmony_ci
3643bf215546Sopenharmony_ci   if (ctx->Extensions.ARB_buffer_storage) {
3644bf215546Sopenharmony_ci         allowed_access |= GL_MAP_PERSISTENT_BIT |
3645bf215546Sopenharmony_ci                           GL_MAP_COHERENT_BIT;
3646bf215546Sopenharmony_ci   }
3647bf215546Sopenharmony_ci
3648bf215546Sopenharmony_ci   if (access & ~allowed_access) {
3649bf215546Sopenharmony_ci      /* generate an error if any bits other than those allowed are set */
3650bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
3651bf215546Sopenharmony_ci                  "%s(access has undefined bits set)", func);
3652bf215546Sopenharmony_ci      return false;
3653bf215546Sopenharmony_ci   }
3654bf215546Sopenharmony_ci
3655bf215546Sopenharmony_ci   if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) {
3656bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
3657bf215546Sopenharmony_ci                  "%s(access indicates neither read or write)", func);
3658bf215546Sopenharmony_ci      return false;
3659bf215546Sopenharmony_ci   }
3660bf215546Sopenharmony_ci
3661bf215546Sopenharmony_ci   if ((access & GL_MAP_READ_BIT) &&
3662bf215546Sopenharmony_ci       (access & (GL_MAP_INVALIDATE_RANGE_BIT |
3663bf215546Sopenharmony_ci                  GL_MAP_INVALIDATE_BUFFER_BIT |
3664bf215546Sopenharmony_ci                  GL_MAP_UNSYNCHRONIZED_BIT))) {
3665bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
3666bf215546Sopenharmony_ci                  "%s(read access with disallowed bits)", func);
3667bf215546Sopenharmony_ci      return false;
3668bf215546Sopenharmony_ci   }
3669bf215546Sopenharmony_ci
3670bf215546Sopenharmony_ci   if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) &&
3671bf215546Sopenharmony_ci       ((access & GL_MAP_WRITE_BIT) == 0)) {
3672bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
3673bf215546Sopenharmony_ci                  "%s(access has flush explicit without write)", func);
3674bf215546Sopenharmony_ci      return false;
3675bf215546Sopenharmony_ci   }
3676bf215546Sopenharmony_ci
3677bf215546Sopenharmony_ci   if (access & GL_MAP_READ_BIT &&
3678bf215546Sopenharmony_ci       !(bufObj->StorageFlags & GL_MAP_READ_BIT)) {
3679bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
3680bf215546Sopenharmony_ci                  "%s(buffer does not allow read access)", func);
3681bf215546Sopenharmony_ci      return false;
3682bf215546Sopenharmony_ci   }
3683bf215546Sopenharmony_ci
3684bf215546Sopenharmony_ci   if (access & GL_MAP_WRITE_BIT &&
3685bf215546Sopenharmony_ci       !(bufObj->StorageFlags & GL_MAP_WRITE_BIT)) {
3686bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
3687bf215546Sopenharmony_ci                  "%s(buffer does not allow write access)", func);
3688bf215546Sopenharmony_ci      return false;
3689bf215546Sopenharmony_ci   }
3690bf215546Sopenharmony_ci
3691bf215546Sopenharmony_ci   if (access & GL_MAP_COHERENT_BIT &&
3692bf215546Sopenharmony_ci       !(bufObj->StorageFlags & GL_MAP_COHERENT_BIT)) {
3693bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
3694bf215546Sopenharmony_ci                  "%s(buffer does not allow coherent access)", func);
3695bf215546Sopenharmony_ci      return false;
3696bf215546Sopenharmony_ci   }
3697bf215546Sopenharmony_ci
3698bf215546Sopenharmony_ci   if (access & GL_MAP_PERSISTENT_BIT &&
3699bf215546Sopenharmony_ci       !(bufObj->StorageFlags & GL_MAP_PERSISTENT_BIT)) {
3700bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
3701bf215546Sopenharmony_ci                  "%s(buffer does not allow persistent access)", func);
3702bf215546Sopenharmony_ci      return false;
3703bf215546Sopenharmony_ci   }
3704bf215546Sopenharmony_ci
3705bf215546Sopenharmony_ci   if (offset + length > bufObj->Size) {
3706bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
3707bf215546Sopenharmony_ci                  "%s(offset %lu + length %lu > buffer_size %lu)", func,
3708bf215546Sopenharmony_ci                  (unsigned long) offset, (unsigned long) length,
3709bf215546Sopenharmony_ci                  (unsigned long) bufObj->Size);
3710bf215546Sopenharmony_ci      return false;
3711bf215546Sopenharmony_ci   }
3712bf215546Sopenharmony_ci
3713bf215546Sopenharmony_ci   if (_mesa_bufferobj_mapped(bufObj, MAP_USER)) {
3714bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
3715bf215546Sopenharmony_ci                  "%s(buffer already mapped)", func);
3716bf215546Sopenharmony_ci      return false;
3717bf215546Sopenharmony_ci   }
3718bf215546Sopenharmony_ci
3719bf215546Sopenharmony_ci   if (access & GL_MAP_WRITE_BIT) {
3720bf215546Sopenharmony_ci      bufObj->NumMapBufferWriteCalls++;
3721bf215546Sopenharmony_ci      if ((bufObj->Usage == GL_STATIC_DRAW ||
3722bf215546Sopenharmony_ci           bufObj->Usage == GL_STATIC_COPY) &&
3723bf215546Sopenharmony_ci          bufObj->NumMapBufferWriteCalls >= BUFFER_WARNING_CALL_COUNT) {
3724bf215546Sopenharmony_ci         BUFFER_USAGE_WARNING(ctx,
3725bf215546Sopenharmony_ci                              "using %s(buffer %u, offset %u, length %u) to "
3726bf215546Sopenharmony_ci                              "update a %s buffer",
3727bf215546Sopenharmony_ci                              func, bufObj->Name, offset, length,
3728bf215546Sopenharmony_ci                              _mesa_enum_to_string(bufObj->Usage));
3729bf215546Sopenharmony_ci      }
3730bf215546Sopenharmony_ci   }
3731bf215546Sopenharmony_ci
3732bf215546Sopenharmony_ci   return true;
3733bf215546Sopenharmony_ci}
3734bf215546Sopenharmony_ci
3735bf215546Sopenharmony_cistatic void *
3736bf215546Sopenharmony_cimap_buffer_range(struct gl_context *ctx, struct gl_buffer_object *bufObj,
3737bf215546Sopenharmony_ci                 GLintptr offset, GLsizeiptr length, GLbitfield access,
3738bf215546Sopenharmony_ci                 const char *func)
3739bf215546Sopenharmony_ci{
3740bf215546Sopenharmony_ci   if (!bufObj->Size) {
3741bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s(buffer size = 0)", func);
3742bf215546Sopenharmony_ci      return NULL;
3743bf215546Sopenharmony_ci   }
3744bf215546Sopenharmony_ci
3745bf215546Sopenharmony_ci   void *map = _mesa_bufferobj_map_range(ctx, offset, length, access, bufObj,
3746bf215546Sopenharmony_ci                                         MAP_USER);
3747bf215546Sopenharmony_ci   if (!map) {
3748bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s(map failed)", func);
3749bf215546Sopenharmony_ci   }
3750bf215546Sopenharmony_ci   else {
3751bf215546Sopenharmony_ci      /* The driver callback should have set all these fields.
3752bf215546Sopenharmony_ci       * This is important because other modules (like VBO) might call
3753bf215546Sopenharmony_ci       * the driver function directly.
3754bf215546Sopenharmony_ci       */
3755bf215546Sopenharmony_ci      assert(bufObj->Mappings[MAP_USER].Pointer == map);
3756bf215546Sopenharmony_ci      assert(bufObj->Mappings[MAP_USER].Length == length);
3757bf215546Sopenharmony_ci      assert(bufObj->Mappings[MAP_USER].Offset == offset);
3758bf215546Sopenharmony_ci      assert(bufObj->Mappings[MAP_USER].AccessFlags == access);
3759bf215546Sopenharmony_ci   }
3760bf215546Sopenharmony_ci
3761bf215546Sopenharmony_ci   if (access & GL_MAP_WRITE_BIT) {
3762bf215546Sopenharmony_ci      bufObj->Written = GL_TRUE;
3763bf215546Sopenharmony_ci      bufObj->MinMaxCacheDirty = true;
3764bf215546Sopenharmony_ci   }
3765bf215546Sopenharmony_ci
3766bf215546Sopenharmony_ci#ifdef VBO_DEBUG
3767bf215546Sopenharmony_ci   if (strstr(func, "Range") == NULL) { /* If not MapRange */
3768bf215546Sopenharmony_ci      printf("glMapBuffer(%u, sz %ld, access 0x%x)\n",
3769bf215546Sopenharmony_ci            bufObj->Name, bufObj->Size, access);
3770bf215546Sopenharmony_ci      /* Access must be write only */
3771bf215546Sopenharmony_ci      if ((access & GL_MAP_WRITE_BIT) && (!(access & ~GL_MAP_WRITE_BIT))) {
3772bf215546Sopenharmony_ci         GLuint i;
3773bf215546Sopenharmony_ci         GLubyte *b = (GLubyte *) bufObj->Mappings[MAP_USER].Pointer;
3774bf215546Sopenharmony_ci         for (i = 0; i < bufObj->Size; i++)
3775bf215546Sopenharmony_ci            b[i] = i & 0xff;
3776bf215546Sopenharmony_ci      }
3777bf215546Sopenharmony_ci   }
3778bf215546Sopenharmony_ci#endif
3779bf215546Sopenharmony_ci
3780bf215546Sopenharmony_ci#ifdef BOUNDS_CHECK
3781bf215546Sopenharmony_ci   if (strstr(func, "Range") == NULL) { /* If not MapRange */
3782bf215546Sopenharmony_ci      GLubyte *buf = (GLubyte *) bufObj->Mappings[MAP_USER].Pointer;
3783bf215546Sopenharmony_ci      GLuint i;
3784bf215546Sopenharmony_ci      /* buffer is 100 bytes larger than requested, fill with magic value */
3785bf215546Sopenharmony_ci      for (i = 0; i < 100; i++) {
3786bf215546Sopenharmony_ci         buf[bufObj->Size - i - 1] = 123;
3787bf215546Sopenharmony_ci      }
3788bf215546Sopenharmony_ci   }
3789bf215546Sopenharmony_ci#endif
3790bf215546Sopenharmony_ci
3791bf215546Sopenharmony_ci   return map;
3792bf215546Sopenharmony_ci}
3793bf215546Sopenharmony_ci
3794bf215546Sopenharmony_civoid * GLAPIENTRY
3795bf215546Sopenharmony_ci_mesa_MapBufferRange_no_error(GLenum target, GLintptr offset,
3796bf215546Sopenharmony_ci                              GLsizeiptr length, GLbitfield access)
3797bf215546Sopenharmony_ci{
3798bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3799bf215546Sopenharmony_ci
3800bf215546Sopenharmony_ci   struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target);
3801bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj = *bufObjPtr;
3802bf215546Sopenharmony_ci
3803bf215546Sopenharmony_ci   return map_buffer_range(ctx, bufObj, offset, length, access,
3804bf215546Sopenharmony_ci                           "glMapBufferRange");
3805bf215546Sopenharmony_ci}
3806bf215546Sopenharmony_ci
3807bf215546Sopenharmony_civoid * GLAPIENTRY
3808bf215546Sopenharmony_ci_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
3809bf215546Sopenharmony_ci                     GLbitfield access)
3810bf215546Sopenharmony_ci{
3811bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3812bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
3813bf215546Sopenharmony_ci
3814bf215546Sopenharmony_ci   if (!ctx->Extensions.ARB_map_buffer_range) {
3815bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
3816bf215546Sopenharmony_ci                  "glMapBufferRange(ARB_map_buffer_range not supported)");
3817bf215546Sopenharmony_ci      return NULL;
3818bf215546Sopenharmony_ci   }
3819bf215546Sopenharmony_ci
3820bf215546Sopenharmony_ci   bufObj = get_buffer(ctx, "glMapBufferRange", target, GL_INVALID_OPERATION);
3821bf215546Sopenharmony_ci   if (!bufObj)
3822bf215546Sopenharmony_ci      return NULL;
3823bf215546Sopenharmony_ci
3824bf215546Sopenharmony_ci   if (!validate_map_buffer_range(ctx, bufObj, offset, length, access,
3825bf215546Sopenharmony_ci                                  "glMapBufferRange"))
3826bf215546Sopenharmony_ci      return NULL;
3827bf215546Sopenharmony_ci
3828bf215546Sopenharmony_ci   return map_buffer_range(ctx, bufObj, offset, length, access,
3829bf215546Sopenharmony_ci                           "glMapBufferRange");
3830bf215546Sopenharmony_ci}
3831bf215546Sopenharmony_ci
3832bf215546Sopenharmony_civoid * GLAPIENTRY
3833bf215546Sopenharmony_ci_mesa_MapNamedBufferRange_no_error(GLuint buffer, GLintptr offset,
3834bf215546Sopenharmony_ci                                   GLsizeiptr length, GLbitfield access)
3835bf215546Sopenharmony_ci{
3836bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3837bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
3838bf215546Sopenharmony_ci
3839bf215546Sopenharmony_ci   return map_buffer_range(ctx, bufObj, offset, length, access,
3840bf215546Sopenharmony_ci                           "glMapNamedBufferRange");
3841bf215546Sopenharmony_ci}
3842bf215546Sopenharmony_ci
3843bf215546Sopenharmony_cistatic void *
3844bf215546Sopenharmony_cimap_named_buffer_range(GLuint buffer, GLintptr offset, GLsizeiptr length,
3845bf215546Sopenharmony_ci                       GLbitfield access, bool dsa_ext, const char *func)
3846bf215546Sopenharmony_ci{
3847bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3848bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj = NULL;
3849bf215546Sopenharmony_ci
3850bf215546Sopenharmony_ci   if (!ctx->Extensions.ARB_map_buffer_range) {
3851bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
3852bf215546Sopenharmony_ci                  "%s(ARB_map_buffer_range not supported)", func);
3853bf215546Sopenharmony_ci      return NULL;
3854bf215546Sopenharmony_ci   }
3855bf215546Sopenharmony_ci
3856bf215546Sopenharmony_ci   if (dsa_ext) {
3857bf215546Sopenharmony_ci      bufObj = _mesa_lookup_bufferobj(ctx, buffer);
3858bf215546Sopenharmony_ci      if (!_mesa_handle_bind_buffer_gen(ctx, buffer, &bufObj, func, false))
3859bf215546Sopenharmony_ci         return NULL;
3860bf215546Sopenharmony_ci   } else {
3861bf215546Sopenharmony_ci      bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, func);
3862bf215546Sopenharmony_ci      if (!bufObj)
3863bf215546Sopenharmony_ci         return NULL;
3864bf215546Sopenharmony_ci   }
3865bf215546Sopenharmony_ci
3866bf215546Sopenharmony_ci   if (!validate_map_buffer_range(ctx, bufObj, offset, length, access, func))
3867bf215546Sopenharmony_ci      return NULL;
3868bf215546Sopenharmony_ci
3869bf215546Sopenharmony_ci   return map_buffer_range(ctx, bufObj, offset, length, access, func);
3870bf215546Sopenharmony_ci}
3871bf215546Sopenharmony_ci
3872bf215546Sopenharmony_civoid * GLAPIENTRY
3873bf215546Sopenharmony_ci_mesa_MapNamedBufferRangeEXT(GLuint buffer, GLintptr offset, GLsizeiptr length,
3874bf215546Sopenharmony_ci                             GLbitfield access)
3875bf215546Sopenharmony_ci{
3876bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3877bf215546Sopenharmony_ci   if (!buffer) {
3878bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
3879bf215546Sopenharmony_ci                  "glMapNamedBufferRangeEXT(buffer=0)");
3880bf215546Sopenharmony_ci      return NULL;
3881bf215546Sopenharmony_ci   }
3882bf215546Sopenharmony_ci   return map_named_buffer_range(buffer, offset, length, access, true,
3883bf215546Sopenharmony_ci                                 "glMapNamedBufferRangeEXT");
3884bf215546Sopenharmony_ci}
3885bf215546Sopenharmony_ci
3886bf215546Sopenharmony_civoid * GLAPIENTRY
3887bf215546Sopenharmony_ci_mesa_MapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length,
3888bf215546Sopenharmony_ci                          GLbitfield access)
3889bf215546Sopenharmony_ci{
3890bf215546Sopenharmony_ci   return map_named_buffer_range(buffer, offset, length, access, false,
3891bf215546Sopenharmony_ci                                 "glMapNamedBufferRange");
3892bf215546Sopenharmony_ci}
3893bf215546Sopenharmony_ci
3894bf215546Sopenharmony_ci/**
3895bf215546Sopenharmony_ci * Converts GLenum access from MapBuffer and MapNamedBuffer into
3896bf215546Sopenharmony_ci * flags for input to map_buffer_range.
3897bf215546Sopenharmony_ci *
3898bf215546Sopenharmony_ci * \return true if the type of requested access is permissible.
3899bf215546Sopenharmony_ci */
3900bf215546Sopenharmony_cistatic bool
3901bf215546Sopenharmony_ciget_map_buffer_access_flags(struct gl_context *ctx, GLenum access,
3902bf215546Sopenharmony_ci                            GLbitfield *flags)
3903bf215546Sopenharmony_ci{
3904bf215546Sopenharmony_ci   switch (access) {
3905bf215546Sopenharmony_ci   case GL_READ_ONLY_ARB:
3906bf215546Sopenharmony_ci      *flags = GL_MAP_READ_BIT;
3907bf215546Sopenharmony_ci      return _mesa_is_desktop_gl(ctx);
3908bf215546Sopenharmony_ci   case GL_WRITE_ONLY_ARB:
3909bf215546Sopenharmony_ci      *flags = GL_MAP_WRITE_BIT;
3910bf215546Sopenharmony_ci      return true;
3911bf215546Sopenharmony_ci   case GL_READ_WRITE_ARB:
3912bf215546Sopenharmony_ci      *flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
3913bf215546Sopenharmony_ci      return _mesa_is_desktop_gl(ctx);
3914bf215546Sopenharmony_ci   default:
3915bf215546Sopenharmony_ci      *flags = 0;
3916bf215546Sopenharmony_ci      return false;
3917bf215546Sopenharmony_ci   }
3918bf215546Sopenharmony_ci}
3919bf215546Sopenharmony_ci
3920bf215546Sopenharmony_civoid * GLAPIENTRY
3921bf215546Sopenharmony_ci_mesa_MapBuffer_no_error(GLenum target, GLenum access)
3922bf215546Sopenharmony_ci{
3923bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3924bf215546Sopenharmony_ci
3925bf215546Sopenharmony_ci   GLbitfield accessFlags;
3926bf215546Sopenharmony_ci   get_map_buffer_access_flags(ctx, access, &accessFlags);
3927bf215546Sopenharmony_ci
3928bf215546Sopenharmony_ci   struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target);
3929bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj = *bufObjPtr;
3930bf215546Sopenharmony_ci
3931bf215546Sopenharmony_ci   return map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags,
3932bf215546Sopenharmony_ci                           "glMapBuffer");
3933bf215546Sopenharmony_ci}
3934bf215546Sopenharmony_ci
3935bf215546Sopenharmony_civoid * GLAPIENTRY
3936bf215546Sopenharmony_ci_mesa_MapBuffer(GLenum target, GLenum access)
3937bf215546Sopenharmony_ci{
3938bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3939bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
3940bf215546Sopenharmony_ci   GLbitfield accessFlags;
3941bf215546Sopenharmony_ci
3942bf215546Sopenharmony_ci   if (!get_map_buffer_access_flags(ctx, access, &accessFlags)) {
3943bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glMapBuffer(invalid access)");
3944bf215546Sopenharmony_ci      return NULL;
3945bf215546Sopenharmony_ci   }
3946bf215546Sopenharmony_ci
3947bf215546Sopenharmony_ci   bufObj = get_buffer(ctx, "glMapBuffer", target, GL_INVALID_OPERATION);
3948bf215546Sopenharmony_ci   if (!bufObj)
3949bf215546Sopenharmony_ci      return NULL;
3950bf215546Sopenharmony_ci
3951bf215546Sopenharmony_ci   if (!validate_map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags,
3952bf215546Sopenharmony_ci                                  "glMapBuffer"))
3953bf215546Sopenharmony_ci      return NULL;
3954bf215546Sopenharmony_ci
3955bf215546Sopenharmony_ci   return map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags,
3956bf215546Sopenharmony_ci                           "glMapBuffer");
3957bf215546Sopenharmony_ci}
3958bf215546Sopenharmony_ci
3959bf215546Sopenharmony_civoid * GLAPIENTRY
3960bf215546Sopenharmony_ci_mesa_MapNamedBuffer_no_error(GLuint buffer, GLenum access)
3961bf215546Sopenharmony_ci{
3962bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3963bf215546Sopenharmony_ci
3964bf215546Sopenharmony_ci   GLbitfield accessFlags;
3965bf215546Sopenharmony_ci   get_map_buffer_access_flags(ctx, access, &accessFlags);
3966bf215546Sopenharmony_ci
3967bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
3968bf215546Sopenharmony_ci
3969bf215546Sopenharmony_ci   return map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags,
3970bf215546Sopenharmony_ci                           "glMapNamedBuffer");
3971bf215546Sopenharmony_ci}
3972bf215546Sopenharmony_ci
3973bf215546Sopenharmony_civoid * GLAPIENTRY
3974bf215546Sopenharmony_ci_mesa_MapNamedBuffer(GLuint buffer, GLenum access)
3975bf215546Sopenharmony_ci{
3976bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
3977bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
3978bf215546Sopenharmony_ci   GLbitfield accessFlags;
3979bf215546Sopenharmony_ci
3980bf215546Sopenharmony_ci   if (!get_map_buffer_access_flags(ctx, access, &accessFlags)) {
3981bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glMapNamedBuffer(invalid access)");
3982bf215546Sopenharmony_ci      return NULL;
3983bf215546Sopenharmony_ci   }
3984bf215546Sopenharmony_ci
3985bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glMapNamedBuffer");
3986bf215546Sopenharmony_ci   if (!bufObj)
3987bf215546Sopenharmony_ci      return NULL;
3988bf215546Sopenharmony_ci
3989bf215546Sopenharmony_ci   if (!validate_map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags,
3990bf215546Sopenharmony_ci                                  "glMapNamedBuffer"))
3991bf215546Sopenharmony_ci      return NULL;
3992bf215546Sopenharmony_ci
3993bf215546Sopenharmony_ci   return map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags,
3994bf215546Sopenharmony_ci                           "glMapNamedBuffer");
3995bf215546Sopenharmony_ci}
3996bf215546Sopenharmony_ci
3997bf215546Sopenharmony_civoid * GLAPIENTRY
3998bf215546Sopenharmony_ci_mesa_MapNamedBufferEXT(GLuint buffer, GLenum access)
3999bf215546Sopenharmony_ci{
4000bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
4001bf215546Sopenharmony_ci
4002bf215546Sopenharmony_ci   GLbitfield accessFlags;
4003bf215546Sopenharmony_ci   if (!buffer) {
4004bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
4005bf215546Sopenharmony_ci                  "glMapNamedBufferEXT(buffer=0)");
4006bf215546Sopenharmony_ci      return NULL;
4007bf215546Sopenharmony_ci   }
4008bf215546Sopenharmony_ci   if (!get_map_buffer_access_flags(ctx, access, &accessFlags)) {
4009bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glMapNamedBufferEXT(invalid access)");
4010bf215546Sopenharmony_ci      return NULL;
4011bf215546Sopenharmony_ci   }
4012bf215546Sopenharmony_ci
4013bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
4014bf215546Sopenharmony_ci   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
4015bf215546Sopenharmony_ci                                     &bufObj, "glMapNamedBufferEXT", false))
4016bf215546Sopenharmony_ci      return NULL;
4017bf215546Sopenharmony_ci
4018bf215546Sopenharmony_ci   if (!validate_map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags,
4019bf215546Sopenharmony_ci                                  "glMapNamedBufferEXT"))
4020bf215546Sopenharmony_ci      return NULL;
4021bf215546Sopenharmony_ci
4022bf215546Sopenharmony_ci   return map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags,
4023bf215546Sopenharmony_ci                           "glMapNamedBufferEXT");
4024bf215546Sopenharmony_ci}
4025bf215546Sopenharmony_ci
4026bf215546Sopenharmony_cistatic void
4027bf215546Sopenharmony_ciflush_mapped_buffer_range(struct gl_context *ctx,
4028bf215546Sopenharmony_ci                          struct gl_buffer_object *bufObj,
4029bf215546Sopenharmony_ci                          GLintptr offset, GLsizeiptr length,
4030bf215546Sopenharmony_ci                          const char *func)
4031bf215546Sopenharmony_ci{
4032bf215546Sopenharmony_ci   if (!ctx->Extensions.ARB_map_buffer_range) {
4033bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
4034bf215546Sopenharmony_ci                  "%s(ARB_map_buffer_range not supported)", func);
4035bf215546Sopenharmony_ci      return;
4036bf215546Sopenharmony_ci   }
4037bf215546Sopenharmony_ci
4038bf215546Sopenharmony_ci   if (offset < 0) {
4039bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
4040bf215546Sopenharmony_ci                  "%s(offset %ld < 0)", func, (long) offset);
4041bf215546Sopenharmony_ci      return;
4042bf215546Sopenharmony_ci   }
4043bf215546Sopenharmony_ci
4044bf215546Sopenharmony_ci   if (length < 0) {
4045bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
4046bf215546Sopenharmony_ci                  "%s(length %ld < 0)", func, (long) length);
4047bf215546Sopenharmony_ci      return;
4048bf215546Sopenharmony_ci   }
4049bf215546Sopenharmony_ci
4050bf215546Sopenharmony_ci   if (!_mesa_bufferobj_mapped(bufObj, MAP_USER)) {
4051bf215546Sopenharmony_ci      /* buffer is not mapped */
4052bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
4053bf215546Sopenharmony_ci                  "%s(buffer is not mapped)", func);
4054bf215546Sopenharmony_ci      return;
4055bf215546Sopenharmony_ci   }
4056bf215546Sopenharmony_ci
4057bf215546Sopenharmony_ci   if ((bufObj->Mappings[MAP_USER].AccessFlags &
4058bf215546Sopenharmony_ci        GL_MAP_FLUSH_EXPLICIT_BIT) == 0) {
4059bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
4060bf215546Sopenharmony_ci                  "%s(GL_MAP_FLUSH_EXPLICIT_BIT not set)", func);
4061bf215546Sopenharmony_ci      return;
4062bf215546Sopenharmony_ci   }
4063bf215546Sopenharmony_ci
4064bf215546Sopenharmony_ci   if (offset + length > bufObj->Mappings[MAP_USER].Length) {
4065bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
4066bf215546Sopenharmony_ci                  "%s(offset %ld + length %ld > mapped length %ld)", func,
4067bf215546Sopenharmony_ci                  (long) offset, (long) length,
4068bf215546Sopenharmony_ci                  (long) bufObj->Mappings[MAP_USER].Length);
4069bf215546Sopenharmony_ci      return;
4070bf215546Sopenharmony_ci   }
4071bf215546Sopenharmony_ci
4072bf215546Sopenharmony_ci   assert(bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_WRITE_BIT);
4073bf215546Sopenharmony_ci
4074bf215546Sopenharmony_ci   _mesa_bufferobj_flush_mapped_range(ctx, offset, length, bufObj,
4075bf215546Sopenharmony_ci                                      MAP_USER);
4076bf215546Sopenharmony_ci}
4077bf215546Sopenharmony_ci
4078bf215546Sopenharmony_civoid GLAPIENTRY
4079bf215546Sopenharmony_ci_mesa_FlushMappedBufferRange_no_error(GLenum target, GLintptr offset,
4080bf215546Sopenharmony_ci                                      GLsizeiptr length)
4081bf215546Sopenharmony_ci{
4082bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
4083bf215546Sopenharmony_ci   struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target);
4084bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj = *bufObjPtr;
4085bf215546Sopenharmony_ci
4086bf215546Sopenharmony_ci   _mesa_bufferobj_flush_mapped_range(ctx, offset, length, bufObj,
4087bf215546Sopenharmony_ci                                      MAP_USER);
4088bf215546Sopenharmony_ci}
4089bf215546Sopenharmony_ci
4090bf215546Sopenharmony_civoid GLAPIENTRY
4091bf215546Sopenharmony_ci_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset,
4092bf215546Sopenharmony_ci                             GLsizeiptr length)
4093bf215546Sopenharmony_ci{
4094bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
4095bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
4096bf215546Sopenharmony_ci
4097bf215546Sopenharmony_ci   bufObj = get_buffer(ctx, "glFlushMappedBufferRange", target,
4098bf215546Sopenharmony_ci                       GL_INVALID_OPERATION);
4099bf215546Sopenharmony_ci   if (!bufObj)
4100bf215546Sopenharmony_ci      return;
4101bf215546Sopenharmony_ci
4102bf215546Sopenharmony_ci   flush_mapped_buffer_range(ctx, bufObj, offset, length,
4103bf215546Sopenharmony_ci                             "glFlushMappedBufferRange");
4104bf215546Sopenharmony_ci}
4105bf215546Sopenharmony_ci
4106bf215546Sopenharmony_civoid GLAPIENTRY
4107bf215546Sopenharmony_ci_mesa_FlushMappedNamedBufferRange_no_error(GLuint buffer, GLintptr offset,
4108bf215546Sopenharmony_ci                                           GLsizeiptr length)
4109bf215546Sopenharmony_ci{
4110bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
4111bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
4112bf215546Sopenharmony_ci
4113bf215546Sopenharmony_ci   _mesa_bufferobj_flush_mapped_range(ctx, offset, length, bufObj,
4114bf215546Sopenharmony_ci                                      MAP_USER);
4115bf215546Sopenharmony_ci}
4116bf215546Sopenharmony_ci
4117bf215546Sopenharmony_civoid GLAPIENTRY
4118bf215546Sopenharmony_ci_mesa_FlushMappedNamedBufferRange(GLuint buffer, GLintptr offset,
4119bf215546Sopenharmony_ci                                  GLsizeiptr length)
4120bf215546Sopenharmony_ci{
4121bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
4122bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
4123bf215546Sopenharmony_ci
4124bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj_err(ctx, buffer,
4125bf215546Sopenharmony_ci                                       "glFlushMappedNamedBufferRange");
4126bf215546Sopenharmony_ci   if (!bufObj)
4127bf215546Sopenharmony_ci      return;
4128bf215546Sopenharmony_ci
4129bf215546Sopenharmony_ci   flush_mapped_buffer_range(ctx, bufObj, offset, length,
4130bf215546Sopenharmony_ci                             "glFlushMappedNamedBufferRange");
4131bf215546Sopenharmony_ci}
4132bf215546Sopenharmony_ci
4133bf215546Sopenharmony_civoid GLAPIENTRY
4134bf215546Sopenharmony_ci_mesa_FlushMappedNamedBufferRangeEXT(GLuint buffer, GLintptr offset,
4135bf215546Sopenharmony_ci                                     GLsizeiptr length)
4136bf215546Sopenharmony_ci{
4137bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
4138bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
4139bf215546Sopenharmony_ci
4140bf215546Sopenharmony_ci   if (!buffer) {
4141bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
4142bf215546Sopenharmony_ci                  "glFlushMappedNamedBufferRangeEXT(buffer=0)");
4143bf215546Sopenharmony_ci      return;
4144bf215546Sopenharmony_ci   }
4145bf215546Sopenharmony_ci
4146bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
4147bf215546Sopenharmony_ci   if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
4148bf215546Sopenharmony_ci                                     &bufObj, "glFlushMappedNamedBufferRangeEXT", false))
4149bf215546Sopenharmony_ci      return;
4150bf215546Sopenharmony_ci
4151bf215546Sopenharmony_ci   flush_mapped_buffer_range(ctx, bufObj, offset, length,
4152bf215546Sopenharmony_ci                             "glFlushMappedNamedBufferRangeEXT");
4153bf215546Sopenharmony_ci}
4154bf215546Sopenharmony_ci
4155bf215546Sopenharmony_cistatic void
4156bf215546Sopenharmony_cibind_buffer_range_uniform_buffer(struct gl_context *ctx, GLuint index,
4157bf215546Sopenharmony_ci                                 struct gl_buffer_object *bufObj,
4158bf215546Sopenharmony_ci                                 GLintptr offset, GLsizeiptr size)
4159bf215546Sopenharmony_ci{
4160bf215546Sopenharmony_ci   if (!bufObj) {
4161bf215546Sopenharmony_ci      offset = -1;
4162bf215546Sopenharmony_ci      size = -1;
4163bf215546Sopenharmony_ci   }
4164bf215546Sopenharmony_ci
4165bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj);
4166bf215546Sopenharmony_ci   bind_uniform_buffer(ctx, index, bufObj, offset, size, GL_FALSE);
4167bf215546Sopenharmony_ci}
4168bf215546Sopenharmony_ci
4169bf215546Sopenharmony_ci/**
4170bf215546Sopenharmony_ci * Bind a region of a buffer object to a uniform block binding point.
4171bf215546Sopenharmony_ci * \param index  the uniform buffer binding point index
4172bf215546Sopenharmony_ci * \param bufObj  the buffer object
4173bf215546Sopenharmony_ci * \param offset  offset to the start of buffer object region
4174bf215546Sopenharmony_ci * \param size  size of the buffer object region
4175bf215546Sopenharmony_ci */
4176bf215546Sopenharmony_cistatic void
4177bf215546Sopenharmony_cibind_buffer_range_uniform_buffer_err(struct gl_context *ctx, GLuint index,
4178bf215546Sopenharmony_ci                                     struct gl_buffer_object *bufObj,
4179bf215546Sopenharmony_ci                                     GLintptr offset, GLsizeiptr size)
4180bf215546Sopenharmony_ci{
4181bf215546Sopenharmony_ci   if (index >= ctx->Const.MaxUniformBufferBindings) {
4182bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index);
4183bf215546Sopenharmony_ci      return;
4184bf215546Sopenharmony_ci   }
4185bf215546Sopenharmony_ci
4186bf215546Sopenharmony_ci   if (offset & (ctx->Const.UniformBufferOffsetAlignment - 1)) {
4187bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
4188bf215546Sopenharmony_ci                  "glBindBufferRange(offset misaligned %d/%d)", (int) offset,
4189bf215546Sopenharmony_ci		  ctx->Const.UniformBufferOffsetAlignment);
4190bf215546Sopenharmony_ci      return;
4191bf215546Sopenharmony_ci   }
4192bf215546Sopenharmony_ci
4193bf215546Sopenharmony_ci   bind_buffer_range_uniform_buffer(ctx, index, bufObj, offset, size);
4194bf215546Sopenharmony_ci}
4195bf215546Sopenharmony_ci
4196bf215546Sopenharmony_cistatic void
4197bf215546Sopenharmony_cibind_buffer_range_shader_storage_buffer(struct gl_context *ctx,
4198bf215546Sopenharmony_ci                                        GLuint index,
4199bf215546Sopenharmony_ci                                        struct gl_buffer_object *bufObj,
4200bf215546Sopenharmony_ci                                        GLintptr offset,
4201bf215546Sopenharmony_ci                                        GLsizeiptr size)
4202bf215546Sopenharmony_ci{
4203bf215546Sopenharmony_ci   if (!bufObj) {
4204bf215546Sopenharmony_ci      offset = -1;
4205bf215546Sopenharmony_ci      size = -1;
4206bf215546Sopenharmony_ci   }
4207bf215546Sopenharmony_ci
4208bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer, bufObj);
4209bf215546Sopenharmony_ci   bind_shader_storage_buffer(ctx, index, bufObj, offset, size, GL_FALSE);
4210bf215546Sopenharmony_ci}
4211bf215546Sopenharmony_ci
4212bf215546Sopenharmony_ci/**
4213bf215546Sopenharmony_ci * Bind a region of a buffer object to a shader storage block binding point.
4214bf215546Sopenharmony_ci * \param index  the shader storage buffer binding point index
4215bf215546Sopenharmony_ci * \param bufObj  the buffer object
4216bf215546Sopenharmony_ci * \param offset  offset to the start of buffer object region
4217bf215546Sopenharmony_ci * \param size  size of the buffer object region
4218bf215546Sopenharmony_ci */
4219bf215546Sopenharmony_cistatic void
4220bf215546Sopenharmony_cibind_buffer_range_shader_storage_buffer_err(struct gl_context *ctx,
4221bf215546Sopenharmony_ci                                            GLuint index,
4222bf215546Sopenharmony_ci                                            struct gl_buffer_object *bufObj,
4223bf215546Sopenharmony_ci                                            GLintptr offset, GLsizeiptr size)
4224bf215546Sopenharmony_ci{
4225bf215546Sopenharmony_ci   if (index >= ctx->Const.MaxShaderStorageBufferBindings) {
4226bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index);
4227bf215546Sopenharmony_ci      return;
4228bf215546Sopenharmony_ci   }
4229bf215546Sopenharmony_ci
4230bf215546Sopenharmony_ci   if (offset & (ctx->Const.ShaderStorageBufferOffsetAlignment - 1)) {
4231bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
4232bf215546Sopenharmony_ci                  "glBindBufferRange(offset misaligned %d/%d)", (int) offset,
4233bf215546Sopenharmony_ci                  ctx->Const.ShaderStorageBufferOffsetAlignment);
4234bf215546Sopenharmony_ci      return;
4235bf215546Sopenharmony_ci   }
4236bf215546Sopenharmony_ci
4237bf215546Sopenharmony_ci   bind_buffer_range_shader_storage_buffer(ctx, index, bufObj, offset, size);
4238bf215546Sopenharmony_ci}
4239bf215546Sopenharmony_ci
4240bf215546Sopenharmony_cistatic void
4241bf215546Sopenharmony_cibind_buffer_range_atomic_buffer(struct gl_context *ctx, GLuint index,
4242bf215546Sopenharmony_ci                                 struct gl_buffer_object *bufObj,
4243bf215546Sopenharmony_ci                                 GLintptr offset, GLsizeiptr size)
4244bf215546Sopenharmony_ci{
4245bf215546Sopenharmony_ci   if (!bufObj) {
4246bf215546Sopenharmony_ci      offset = -1;
4247bf215546Sopenharmony_ci      size = -1;
4248bf215546Sopenharmony_ci   }
4249bf215546Sopenharmony_ci
4250bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, bufObj);
4251bf215546Sopenharmony_ci   bind_atomic_buffer(ctx, index, bufObj, offset, size, GL_FALSE);
4252bf215546Sopenharmony_ci}
4253bf215546Sopenharmony_ci
4254bf215546Sopenharmony_ci/**
4255bf215546Sopenharmony_ci * Bind a region of a buffer object to an atomic storage block binding point.
4256bf215546Sopenharmony_ci * \param index  the shader storage buffer binding point index
4257bf215546Sopenharmony_ci * \param bufObj  the buffer object
4258bf215546Sopenharmony_ci * \param offset  offset to the start of buffer object region
4259bf215546Sopenharmony_ci * \param size  size of the buffer object region
4260bf215546Sopenharmony_ci */
4261bf215546Sopenharmony_cistatic void
4262bf215546Sopenharmony_cibind_buffer_range_atomic_buffer_err(struct gl_context *ctx,
4263bf215546Sopenharmony_ci                                    GLuint index,
4264bf215546Sopenharmony_ci                                    struct gl_buffer_object *bufObj,
4265bf215546Sopenharmony_ci                                    GLintptr offset, GLsizeiptr size)
4266bf215546Sopenharmony_ci{
4267bf215546Sopenharmony_ci   if (index >= ctx->Const.MaxAtomicBufferBindings) {
4268bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index);
4269bf215546Sopenharmony_ci      return;
4270bf215546Sopenharmony_ci   }
4271bf215546Sopenharmony_ci
4272bf215546Sopenharmony_ci   if (offset & (ATOMIC_COUNTER_SIZE - 1)) {
4273bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
4274bf215546Sopenharmony_ci		  "glBindBufferRange(offset misaligned %d/%d)", (int) offset,
4275bf215546Sopenharmony_ci		  ATOMIC_COUNTER_SIZE);
4276bf215546Sopenharmony_ci      return;
4277bf215546Sopenharmony_ci   }
4278bf215546Sopenharmony_ci
4279bf215546Sopenharmony_ci   bind_buffer_range_atomic_buffer(ctx, index, bufObj, offset, size);
4280bf215546Sopenharmony_ci}
4281bf215546Sopenharmony_ci
4282bf215546Sopenharmony_cistatic inline bool
4283bf215546Sopenharmony_cibind_buffers_check_offset_and_size(struct gl_context *ctx,
4284bf215546Sopenharmony_ci                                   GLuint index,
4285bf215546Sopenharmony_ci                                   const GLintptr *offsets,
4286bf215546Sopenharmony_ci                                   const GLsizeiptr *sizes)
4287bf215546Sopenharmony_ci{
4288bf215546Sopenharmony_ci   if (offsets[index] < 0) {
4289bf215546Sopenharmony_ci      /* The ARB_multi_bind spec says:
4290bf215546Sopenharmony_ci       *
4291bf215546Sopenharmony_ci       *    "An INVALID_VALUE error is generated by BindBuffersRange if any
4292bf215546Sopenharmony_ci       *     value in <offsets> is less than zero (per binding)."
4293bf215546Sopenharmony_ci       */
4294bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
4295bf215546Sopenharmony_ci                  "glBindBuffersRange(offsets[%u]=%" PRId64 " < 0)",
4296bf215546Sopenharmony_ci                  index, (int64_t) offsets[index]);
4297bf215546Sopenharmony_ci      return false;
4298bf215546Sopenharmony_ci   }
4299bf215546Sopenharmony_ci
4300bf215546Sopenharmony_ci   if (sizes[index] <= 0) {
4301bf215546Sopenharmony_ci      /* The ARB_multi_bind spec says:
4302bf215546Sopenharmony_ci       *
4303bf215546Sopenharmony_ci       *     "An INVALID_VALUE error is generated by BindBuffersRange if any
4304bf215546Sopenharmony_ci       *      value in <sizes> is less than or equal to zero (per binding)."
4305bf215546Sopenharmony_ci       */
4306bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
4307bf215546Sopenharmony_ci                  "glBindBuffersRange(sizes[%u]=%" PRId64 " <= 0)",
4308bf215546Sopenharmony_ci                  index, (int64_t) sizes[index]);
4309bf215546Sopenharmony_ci      return false;
4310bf215546Sopenharmony_ci   }
4311bf215546Sopenharmony_ci
4312bf215546Sopenharmony_ci   return true;
4313bf215546Sopenharmony_ci}
4314bf215546Sopenharmony_ci
4315bf215546Sopenharmony_cistatic bool
4316bf215546Sopenharmony_cierror_check_bind_uniform_buffers(struct gl_context *ctx,
4317bf215546Sopenharmony_ci                                 GLuint first, GLsizei count,
4318bf215546Sopenharmony_ci                                 const char *caller)
4319bf215546Sopenharmony_ci{
4320bf215546Sopenharmony_ci   if (!ctx->Extensions.ARB_uniform_buffer_object) {
4321bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM,
4322bf215546Sopenharmony_ci                  "%s(target=GL_UNIFORM_BUFFER)", caller);
4323bf215546Sopenharmony_ci      return false;
4324bf215546Sopenharmony_ci   }
4325bf215546Sopenharmony_ci
4326bf215546Sopenharmony_ci   /* The ARB_multi_bind_spec says:
4327bf215546Sopenharmony_ci    *
4328bf215546Sopenharmony_ci    *     "An INVALID_OPERATION error is generated if <first> + <count> is
4329bf215546Sopenharmony_ci    *      greater than the number of target-specific indexed binding points,
4330bf215546Sopenharmony_ci    *      as described in section 6.7.1."
4331bf215546Sopenharmony_ci    */
4332bf215546Sopenharmony_ci   if (first + count > ctx->Const.MaxUniformBufferBindings) {
4333bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
4334bf215546Sopenharmony_ci                  "%s(first=%u + count=%d > the value of "
4335bf215546Sopenharmony_ci                  "GL_MAX_UNIFORM_BUFFER_BINDINGS=%u)",
4336bf215546Sopenharmony_ci                  caller, first, count,
4337bf215546Sopenharmony_ci                  ctx->Const.MaxUniformBufferBindings);
4338bf215546Sopenharmony_ci      return false;
4339bf215546Sopenharmony_ci   }
4340bf215546Sopenharmony_ci
4341bf215546Sopenharmony_ci   return true;
4342bf215546Sopenharmony_ci}
4343bf215546Sopenharmony_ci
4344bf215546Sopenharmony_cistatic bool
4345bf215546Sopenharmony_cierror_check_bind_shader_storage_buffers(struct gl_context *ctx,
4346bf215546Sopenharmony_ci                                        GLuint first, GLsizei count,
4347bf215546Sopenharmony_ci                                        const char *caller)
4348bf215546Sopenharmony_ci{
4349bf215546Sopenharmony_ci   if (!ctx->Extensions.ARB_shader_storage_buffer_object) {
4350bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM,
4351bf215546Sopenharmony_ci                  "%s(target=GL_SHADER_STORAGE_BUFFER)", caller);
4352bf215546Sopenharmony_ci      return false;
4353bf215546Sopenharmony_ci   }
4354bf215546Sopenharmony_ci
4355bf215546Sopenharmony_ci   /* The ARB_multi_bind_spec says:
4356bf215546Sopenharmony_ci    *
4357bf215546Sopenharmony_ci    *     "An INVALID_OPERATION error is generated if <first> + <count> is
4358bf215546Sopenharmony_ci    *      greater than the number of target-specific indexed binding points,
4359bf215546Sopenharmony_ci    *      as described in section 6.7.1."
4360bf215546Sopenharmony_ci    */
4361bf215546Sopenharmony_ci   if (first + count > ctx->Const.MaxShaderStorageBufferBindings) {
4362bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
4363bf215546Sopenharmony_ci                  "%s(first=%u + count=%d > the value of "
4364bf215546Sopenharmony_ci                  "GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS=%u)",
4365bf215546Sopenharmony_ci                  caller, first, count,
4366bf215546Sopenharmony_ci                  ctx->Const.MaxShaderStorageBufferBindings);
4367bf215546Sopenharmony_ci      return false;
4368bf215546Sopenharmony_ci   }
4369bf215546Sopenharmony_ci
4370bf215546Sopenharmony_ci   return true;
4371bf215546Sopenharmony_ci}
4372bf215546Sopenharmony_ci
4373bf215546Sopenharmony_ci/**
4374bf215546Sopenharmony_ci * Unbind all uniform buffers in the range
4375bf215546Sopenharmony_ci * <first> through <first>+<count>-1
4376bf215546Sopenharmony_ci */
4377bf215546Sopenharmony_cistatic void
4378bf215546Sopenharmony_ciunbind_uniform_buffers(struct gl_context *ctx, GLuint first, GLsizei count)
4379bf215546Sopenharmony_ci{
4380bf215546Sopenharmony_ci   for (int i = 0; i < count; i++)
4381bf215546Sopenharmony_ci      set_buffer_binding(ctx, &ctx->UniformBufferBindings[first + i],
4382bf215546Sopenharmony_ci                         NULL, -1, -1, GL_TRUE, 0);
4383bf215546Sopenharmony_ci}
4384bf215546Sopenharmony_ci
4385bf215546Sopenharmony_ci/**
4386bf215546Sopenharmony_ci * Unbind all shader storage buffers in the range
4387bf215546Sopenharmony_ci * <first> through <first>+<count>-1
4388bf215546Sopenharmony_ci */
4389bf215546Sopenharmony_cistatic void
4390bf215546Sopenharmony_ciunbind_shader_storage_buffers(struct gl_context *ctx, GLuint first,
4391bf215546Sopenharmony_ci                              GLsizei count)
4392bf215546Sopenharmony_ci{
4393bf215546Sopenharmony_ci   for (int i = 0; i < count; i++)
4394bf215546Sopenharmony_ci      set_buffer_binding(ctx, &ctx->ShaderStorageBufferBindings[first + i],
4395bf215546Sopenharmony_ci                         NULL, -1, -1, GL_TRUE, 0);
4396bf215546Sopenharmony_ci}
4397bf215546Sopenharmony_ci
4398bf215546Sopenharmony_cistatic void
4399bf215546Sopenharmony_cibind_uniform_buffers(struct gl_context *ctx, GLuint first, GLsizei count,
4400bf215546Sopenharmony_ci                     const GLuint *buffers,
4401bf215546Sopenharmony_ci                     bool range,
4402bf215546Sopenharmony_ci                     const GLintptr *offsets, const GLsizeiptr *sizes,
4403bf215546Sopenharmony_ci                     const char *caller)
4404bf215546Sopenharmony_ci{
4405bf215546Sopenharmony_ci   if (!error_check_bind_uniform_buffers(ctx, first, count, caller))
4406bf215546Sopenharmony_ci      return;
4407bf215546Sopenharmony_ci
4408bf215546Sopenharmony_ci   /* Assume that at least one binding will be changed */
4409bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, 0, 0);
4410bf215546Sopenharmony_ci   ctx->NewDriverState |= ST_NEW_UNIFORM_BUFFER;
4411bf215546Sopenharmony_ci
4412bf215546Sopenharmony_ci   if (!buffers) {
4413bf215546Sopenharmony_ci      /* The ARB_multi_bind spec says:
4414bf215546Sopenharmony_ci       *
4415bf215546Sopenharmony_ci       *    "If <buffers> is NULL, all bindings from <first> through
4416bf215546Sopenharmony_ci       *     <first>+<count>-1 are reset to their unbound (zero) state.
4417bf215546Sopenharmony_ci       *     In this case, the offsets and sizes associated with the
4418bf215546Sopenharmony_ci       *     binding points are set to default values, ignoring
4419bf215546Sopenharmony_ci       *     <offsets> and <sizes>."
4420bf215546Sopenharmony_ci       */
4421bf215546Sopenharmony_ci      unbind_uniform_buffers(ctx, first, count);
4422bf215546Sopenharmony_ci      return;
4423bf215546Sopenharmony_ci   }
4424bf215546Sopenharmony_ci
4425bf215546Sopenharmony_ci   /* Note that the error semantics for multi-bind commands differ from
4426bf215546Sopenharmony_ci    * those of other GL commands.
4427bf215546Sopenharmony_ci    *
4428bf215546Sopenharmony_ci    * The Issues section in the ARB_multi_bind spec says:
4429bf215546Sopenharmony_ci    *
4430bf215546Sopenharmony_ci    *    "(11) Typically, OpenGL specifies that if an error is generated by a
4431bf215546Sopenharmony_ci    *          command, that command has no effect.  This is somewhat
4432bf215546Sopenharmony_ci    *          unfortunate for multi-bind commands, because it would require a
4433bf215546Sopenharmony_ci    *          first pass to scan the entire list of bound objects for errors
4434bf215546Sopenharmony_ci    *          and then a second pass to actually perform the bindings.
4435bf215546Sopenharmony_ci    *          Should we have different error semantics?
4436bf215546Sopenharmony_ci    *
4437bf215546Sopenharmony_ci    *       RESOLVED:  Yes.  In this specification, when the parameters for
4438bf215546Sopenharmony_ci    *       one of the <count> binding points are invalid, that binding point
4439bf215546Sopenharmony_ci    *       is not updated and an error will be generated.  However, other
4440bf215546Sopenharmony_ci    *       binding points in the same command will be updated if their
4441bf215546Sopenharmony_ci    *       parameters are valid and no other error occurs."
4442bf215546Sopenharmony_ci    */
4443bf215546Sopenharmony_ci
4444bf215546Sopenharmony_ci   _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects,
4445bf215546Sopenharmony_ci                             ctx->BufferObjectsLocked);
4446bf215546Sopenharmony_ci
4447bf215546Sopenharmony_ci   for (int i = 0; i < count; i++) {
4448bf215546Sopenharmony_ci      struct gl_buffer_binding *binding =
4449bf215546Sopenharmony_ci         &ctx->UniformBufferBindings[first + i];
4450bf215546Sopenharmony_ci      GLintptr offset = 0;
4451bf215546Sopenharmony_ci      GLsizeiptr size = 0;
4452bf215546Sopenharmony_ci
4453bf215546Sopenharmony_ci      if (range) {
4454bf215546Sopenharmony_ci         if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
4455bf215546Sopenharmony_ci            continue;
4456bf215546Sopenharmony_ci
4457bf215546Sopenharmony_ci         /* The ARB_multi_bind spec says:
4458bf215546Sopenharmony_ci          *
4459bf215546Sopenharmony_ci          *     "An INVALID_VALUE error is generated by BindBuffersRange if any
4460bf215546Sopenharmony_ci          *      pair of values in <offsets> and <sizes> does not respectively
4461bf215546Sopenharmony_ci          *      satisfy the constraints described for those parameters for the
4462bf215546Sopenharmony_ci          *      specified target, as described in section 6.7.1 (per binding)."
4463bf215546Sopenharmony_ci          *
4464bf215546Sopenharmony_ci          * Section 6.7.1 refers to table 6.5, which says:
4465bf215546Sopenharmony_ci          *
4466bf215546Sopenharmony_ci          *     "┌───────────────────────────────────────────────────────────────┐
4467bf215546Sopenharmony_ci          *      │ Uniform buffer array bindings (see sec. 7.6)                  │
4468bf215546Sopenharmony_ci          *      ├─────────────────────┬─────────────────────────────────────────┤
4469bf215546Sopenharmony_ci          *      │  ...                │  ...                                    │
4470bf215546Sopenharmony_ci          *      │  offset restriction │  multiple of value of UNIFORM_BUFFER_-  │
4471bf215546Sopenharmony_ci          *      │                     │  OFFSET_ALIGNMENT                       │
4472bf215546Sopenharmony_ci          *      │  ...                │  ...                                    │
4473bf215546Sopenharmony_ci          *      │  size restriction   │  none                                   │
4474bf215546Sopenharmony_ci          *      └─────────────────────┴─────────────────────────────────────────┘"
4475bf215546Sopenharmony_ci          */
4476bf215546Sopenharmony_ci         if (offsets[i] & (ctx->Const.UniformBufferOffsetAlignment - 1)) {
4477bf215546Sopenharmony_ci            _mesa_error(ctx, GL_INVALID_VALUE,
4478bf215546Sopenharmony_ci                        "glBindBuffersRange(offsets[%u]=%" PRId64
4479bf215546Sopenharmony_ci                        " is misaligned; it must be a multiple of the value of "
4480bf215546Sopenharmony_ci                        "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT=%u when "
4481bf215546Sopenharmony_ci                        "target=GL_UNIFORM_BUFFER)",
4482bf215546Sopenharmony_ci                        i, (int64_t) offsets[i],
4483bf215546Sopenharmony_ci                        ctx->Const.UniformBufferOffsetAlignment);
4484bf215546Sopenharmony_ci            continue;
4485bf215546Sopenharmony_ci         }
4486bf215546Sopenharmony_ci
4487bf215546Sopenharmony_ci         offset = offsets[i];
4488bf215546Sopenharmony_ci         size = sizes[i];
4489bf215546Sopenharmony_ci      }
4490bf215546Sopenharmony_ci
4491bf215546Sopenharmony_ci      set_buffer_multi_binding(ctx, buffers, i, caller,
4492bf215546Sopenharmony_ci                               binding, offset, size, range,
4493bf215546Sopenharmony_ci                               USAGE_UNIFORM_BUFFER);
4494bf215546Sopenharmony_ci   }
4495bf215546Sopenharmony_ci
4496bf215546Sopenharmony_ci   _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects,
4497bf215546Sopenharmony_ci                               ctx->BufferObjectsLocked);
4498bf215546Sopenharmony_ci}
4499bf215546Sopenharmony_ci
4500bf215546Sopenharmony_cistatic void
4501bf215546Sopenharmony_cibind_shader_storage_buffers(struct gl_context *ctx, GLuint first,
4502bf215546Sopenharmony_ci                            GLsizei count, const GLuint *buffers,
4503bf215546Sopenharmony_ci                            bool range,
4504bf215546Sopenharmony_ci                            const GLintptr *offsets,
4505bf215546Sopenharmony_ci                            const GLsizeiptr *sizes,
4506bf215546Sopenharmony_ci                            const char *caller)
4507bf215546Sopenharmony_ci{
4508bf215546Sopenharmony_ci   if (!error_check_bind_shader_storage_buffers(ctx, first, count, caller))
4509bf215546Sopenharmony_ci      return;
4510bf215546Sopenharmony_ci
4511bf215546Sopenharmony_ci   /* Assume that at least one binding will be changed */
4512bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, 0, 0);
4513bf215546Sopenharmony_ci   ctx->NewDriverState |= ST_NEW_STORAGE_BUFFER;
4514bf215546Sopenharmony_ci
4515bf215546Sopenharmony_ci   if (!buffers) {
4516bf215546Sopenharmony_ci      /* The ARB_multi_bind spec says:
4517bf215546Sopenharmony_ci       *
4518bf215546Sopenharmony_ci       *    "If <buffers> is NULL, all bindings from <first> through
4519bf215546Sopenharmony_ci       *     <first>+<count>-1 are reset to their unbound (zero) state.
4520bf215546Sopenharmony_ci       *     In this case, the offsets and sizes associated with the
4521bf215546Sopenharmony_ci       *     binding points are set to default values, ignoring
4522bf215546Sopenharmony_ci       *     <offsets> and <sizes>."
4523bf215546Sopenharmony_ci       */
4524bf215546Sopenharmony_ci      unbind_shader_storage_buffers(ctx, first, count);
4525bf215546Sopenharmony_ci      return;
4526bf215546Sopenharmony_ci   }
4527bf215546Sopenharmony_ci
4528bf215546Sopenharmony_ci   /* Note that the error semantics for multi-bind commands differ from
4529bf215546Sopenharmony_ci    * those of other GL commands.
4530bf215546Sopenharmony_ci    *
4531bf215546Sopenharmony_ci    * The Issues section in the ARB_multi_bind spec says:
4532bf215546Sopenharmony_ci    *
4533bf215546Sopenharmony_ci    *    "(11) Typically, OpenGL specifies that if an error is generated by a
4534bf215546Sopenharmony_ci    *          command, that command has no effect.  This is somewhat
4535bf215546Sopenharmony_ci    *          unfortunate for multi-bind commands, because it would require a
4536bf215546Sopenharmony_ci    *          first pass to scan the entire list of bound objects for errors
4537bf215546Sopenharmony_ci    *          and then a second pass to actually perform the bindings.
4538bf215546Sopenharmony_ci    *          Should we have different error semantics?
4539bf215546Sopenharmony_ci    *
4540bf215546Sopenharmony_ci    *       RESOLVED:  Yes.  In this specification, when the parameters for
4541bf215546Sopenharmony_ci    *       one of the <count> binding points are invalid, that binding point
4542bf215546Sopenharmony_ci    *       is not updated and an error will be generated.  However, other
4543bf215546Sopenharmony_ci    *       binding points in the same command will be updated if their
4544bf215546Sopenharmony_ci    *       parameters are valid and no other error occurs."
4545bf215546Sopenharmony_ci    */
4546bf215546Sopenharmony_ci
4547bf215546Sopenharmony_ci   _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects,
4548bf215546Sopenharmony_ci                             ctx->BufferObjectsLocked);
4549bf215546Sopenharmony_ci
4550bf215546Sopenharmony_ci   for (int i = 0; i < count; i++) {
4551bf215546Sopenharmony_ci      struct gl_buffer_binding *binding =
4552bf215546Sopenharmony_ci         &ctx->ShaderStorageBufferBindings[first + i];
4553bf215546Sopenharmony_ci      GLintptr offset = 0;
4554bf215546Sopenharmony_ci      GLsizeiptr size = 0;
4555bf215546Sopenharmony_ci
4556bf215546Sopenharmony_ci      if (range) {
4557bf215546Sopenharmony_ci         if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
4558bf215546Sopenharmony_ci            continue;
4559bf215546Sopenharmony_ci
4560bf215546Sopenharmony_ci         /* The ARB_multi_bind spec says:
4561bf215546Sopenharmony_ci         *
4562bf215546Sopenharmony_ci         *     "An INVALID_VALUE error is generated by BindBuffersRange if any
4563bf215546Sopenharmony_ci         *      pair of values in <offsets> and <sizes> does not respectively
4564bf215546Sopenharmony_ci         *      satisfy the constraints described for those parameters for the
4565bf215546Sopenharmony_ci         *      specified target, as described in section 6.7.1 (per binding)."
4566bf215546Sopenharmony_ci         *
4567bf215546Sopenharmony_ci         * Section 6.7.1 refers to table 6.5, which says:
4568bf215546Sopenharmony_ci         *
4569bf215546Sopenharmony_ci         *     "┌───────────────────────────────────────────────────────────────┐
4570bf215546Sopenharmony_ci         *      │ Shader storage buffer array bindings (see sec. 7.8)           │
4571bf215546Sopenharmony_ci         *      ├─────────────────────┬─────────────────────────────────────────┤
4572bf215546Sopenharmony_ci         *      │  ...                │  ...                                    │
4573bf215546Sopenharmony_ci         *      │  offset restriction │  multiple of value of SHADER_STORAGE_-  │
4574bf215546Sopenharmony_ci         *      │                     │  BUFFER_OFFSET_ALIGNMENT                │
4575bf215546Sopenharmony_ci         *      │  ...                │  ...                                    │
4576bf215546Sopenharmony_ci         *      │  size restriction   │  none                                   │
4577bf215546Sopenharmony_ci         *      └─────────────────────┴─────────────────────────────────────────┘"
4578bf215546Sopenharmony_ci         */
4579bf215546Sopenharmony_ci         if (offsets[i] & (ctx->Const.ShaderStorageBufferOffsetAlignment - 1)) {
4580bf215546Sopenharmony_ci            _mesa_error(ctx, GL_INVALID_VALUE,
4581bf215546Sopenharmony_ci                        "glBindBuffersRange(offsets[%u]=%" PRId64
4582bf215546Sopenharmony_ci                        " is misaligned; it must be a multiple of the value of "
4583bf215546Sopenharmony_ci                        "GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT=%u when "
4584bf215546Sopenharmony_ci                        "target=GL_SHADER_STORAGE_BUFFER)",
4585bf215546Sopenharmony_ci                        i, (int64_t) offsets[i],
4586bf215546Sopenharmony_ci                        ctx->Const.ShaderStorageBufferOffsetAlignment);
4587bf215546Sopenharmony_ci            continue;
4588bf215546Sopenharmony_ci         }
4589bf215546Sopenharmony_ci
4590bf215546Sopenharmony_ci         offset = offsets[i];
4591bf215546Sopenharmony_ci         size = sizes[i];
4592bf215546Sopenharmony_ci      }
4593bf215546Sopenharmony_ci
4594bf215546Sopenharmony_ci      set_buffer_multi_binding(ctx, buffers, i, caller,
4595bf215546Sopenharmony_ci                               binding, offset, size, range,
4596bf215546Sopenharmony_ci                               USAGE_SHADER_STORAGE_BUFFER);
4597bf215546Sopenharmony_ci   }
4598bf215546Sopenharmony_ci
4599bf215546Sopenharmony_ci   _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects,
4600bf215546Sopenharmony_ci                               ctx->BufferObjectsLocked);
4601bf215546Sopenharmony_ci}
4602bf215546Sopenharmony_ci
4603bf215546Sopenharmony_cistatic bool
4604bf215546Sopenharmony_cierror_check_bind_xfb_buffers(struct gl_context *ctx,
4605bf215546Sopenharmony_ci                             struct gl_transform_feedback_object *tfObj,
4606bf215546Sopenharmony_ci                             GLuint first, GLsizei count, const char *caller)
4607bf215546Sopenharmony_ci{
4608bf215546Sopenharmony_ci   if (!ctx->Extensions.EXT_transform_feedback) {
4609bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM,
4610bf215546Sopenharmony_ci                  "%s(target=GL_TRANSFORM_FEEDBACK_BUFFER)", caller);
4611bf215546Sopenharmony_ci      return false;
4612bf215546Sopenharmony_ci   }
4613bf215546Sopenharmony_ci
4614bf215546Sopenharmony_ci   /* Page 398 of the PDF of the OpenGL 4.4 (Core Profile) spec says:
4615bf215546Sopenharmony_ci    *
4616bf215546Sopenharmony_ci    *     "An INVALID_OPERATION error is generated :
4617bf215546Sopenharmony_ci    *
4618bf215546Sopenharmony_ci    *     ...
4619bf215546Sopenharmony_ci    *     • by BindBufferRange or BindBufferBase if target is TRANSFORM_-
4620bf215546Sopenharmony_ci    *       FEEDBACK_BUFFER and transform feedback is currently active."
4621bf215546Sopenharmony_ci    *
4622bf215546Sopenharmony_ci    * We assume that this is also meant to apply to BindBuffersRange
4623bf215546Sopenharmony_ci    * and BindBuffersBase.
4624bf215546Sopenharmony_ci    */
4625bf215546Sopenharmony_ci   if (tfObj->Active) {
4626bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
4627bf215546Sopenharmony_ci                  "%s(Changing transform feedback buffers while "
4628bf215546Sopenharmony_ci                  "transform feedback is active)", caller);
4629bf215546Sopenharmony_ci      return false;
4630bf215546Sopenharmony_ci   }
4631bf215546Sopenharmony_ci
4632bf215546Sopenharmony_ci   /* The ARB_multi_bind_spec says:
4633bf215546Sopenharmony_ci    *
4634bf215546Sopenharmony_ci    *     "An INVALID_OPERATION error is generated if <first> + <count> is
4635bf215546Sopenharmony_ci    *      greater than the number of target-specific indexed binding points,
4636bf215546Sopenharmony_ci    *      as described in section 6.7.1."
4637bf215546Sopenharmony_ci    */
4638bf215546Sopenharmony_ci   if (first + count > ctx->Const.MaxTransformFeedbackBuffers) {
4639bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
4640bf215546Sopenharmony_ci                  "%s(first=%u + count=%d > the value of "
4641bf215546Sopenharmony_ci                  "GL_MAX_TRANSFORM_FEEDBACK_BUFFERS=%u)",
4642bf215546Sopenharmony_ci                  caller, first, count,
4643bf215546Sopenharmony_ci                  ctx->Const.MaxTransformFeedbackBuffers);
4644bf215546Sopenharmony_ci      return false;
4645bf215546Sopenharmony_ci   }
4646bf215546Sopenharmony_ci
4647bf215546Sopenharmony_ci   return true;
4648bf215546Sopenharmony_ci}
4649bf215546Sopenharmony_ci
4650bf215546Sopenharmony_ci/**
4651bf215546Sopenharmony_ci * Unbind all transform feedback buffers in the range
4652bf215546Sopenharmony_ci * <first> through <first>+<count>-1
4653bf215546Sopenharmony_ci */
4654bf215546Sopenharmony_cistatic void
4655bf215546Sopenharmony_ciunbind_xfb_buffers(struct gl_context *ctx,
4656bf215546Sopenharmony_ci                   struct gl_transform_feedback_object *tfObj,
4657bf215546Sopenharmony_ci                   GLuint first, GLsizei count)
4658bf215546Sopenharmony_ci{
4659bf215546Sopenharmony_ci   for (int i = 0; i < count; i++)
4660bf215546Sopenharmony_ci      _mesa_set_transform_feedback_binding(ctx, tfObj, first + i,
4661bf215546Sopenharmony_ci                                           NULL, 0, 0);
4662bf215546Sopenharmony_ci}
4663bf215546Sopenharmony_ci
4664bf215546Sopenharmony_cistatic void
4665bf215546Sopenharmony_cibind_xfb_buffers(struct gl_context *ctx,
4666bf215546Sopenharmony_ci                 GLuint first, GLsizei count,
4667bf215546Sopenharmony_ci                 const GLuint *buffers,
4668bf215546Sopenharmony_ci                 bool range,
4669bf215546Sopenharmony_ci                 const GLintptr *offsets,
4670bf215546Sopenharmony_ci                 const GLsizeiptr *sizes,
4671bf215546Sopenharmony_ci                 const char *caller)
4672bf215546Sopenharmony_ci{
4673bf215546Sopenharmony_ci   struct gl_transform_feedback_object *tfObj =
4674bf215546Sopenharmony_ci       ctx->TransformFeedback.CurrentObject;
4675bf215546Sopenharmony_ci
4676bf215546Sopenharmony_ci   if (!error_check_bind_xfb_buffers(ctx, tfObj, first, count, caller))
4677bf215546Sopenharmony_ci      return;
4678bf215546Sopenharmony_ci
4679bf215546Sopenharmony_ci   /* Assume that at least one binding will be changed */
4680bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, 0, 0);
4681bf215546Sopenharmony_ci
4682bf215546Sopenharmony_ci   if (!buffers) {
4683bf215546Sopenharmony_ci      /* The ARB_multi_bind spec says:
4684bf215546Sopenharmony_ci       *
4685bf215546Sopenharmony_ci       *    "If <buffers> is NULL, all bindings from <first> through
4686bf215546Sopenharmony_ci       *     <first>+<count>-1 are reset to their unbound (zero) state.
4687bf215546Sopenharmony_ci       *     In this case, the offsets and sizes associated with the
4688bf215546Sopenharmony_ci       *     binding points are set to default values, ignoring
4689bf215546Sopenharmony_ci       *     <offsets> and <sizes>."
4690bf215546Sopenharmony_ci       */
4691bf215546Sopenharmony_ci      unbind_xfb_buffers(ctx, tfObj, first, count);
4692bf215546Sopenharmony_ci      return;
4693bf215546Sopenharmony_ci   }
4694bf215546Sopenharmony_ci
4695bf215546Sopenharmony_ci   /* Note that the error semantics for multi-bind commands differ from
4696bf215546Sopenharmony_ci    * those of other GL commands.
4697bf215546Sopenharmony_ci    *
4698bf215546Sopenharmony_ci    * The Issues section in the ARB_multi_bind spec says:
4699bf215546Sopenharmony_ci    *
4700bf215546Sopenharmony_ci    *    "(11) Typically, OpenGL specifies that if an error is generated by a
4701bf215546Sopenharmony_ci    *          command, that command has no effect.  This is somewhat
4702bf215546Sopenharmony_ci    *          unfortunate for multi-bind commands, because it would require a
4703bf215546Sopenharmony_ci    *          first pass to scan the entire list of bound objects for errors
4704bf215546Sopenharmony_ci    *          and then a second pass to actually perform the bindings.
4705bf215546Sopenharmony_ci    *          Should we have different error semantics?
4706bf215546Sopenharmony_ci    *
4707bf215546Sopenharmony_ci    *       RESOLVED:  Yes.  In this specification, when the parameters for
4708bf215546Sopenharmony_ci    *       one of the <count> binding points are invalid, that binding point
4709bf215546Sopenharmony_ci    *       is not updated and an error will be generated.  However, other
4710bf215546Sopenharmony_ci    *       binding points in the same command will be updated if their
4711bf215546Sopenharmony_ci    *       parameters are valid and no other error occurs."
4712bf215546Sopenharmony_ci    */
4713bf215546Sopenharmony_ci
4714bf215546Sopenharmony_ci   _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects,
4715bf215546Sopenharmony_ci                             ctx->BufferObjectsLocked);
4716bf215546Sopenharmony_ci
4717bf215546Sopenharmony_ci   for (int i = 0; i < count; i++) {
4718bf215546Sopenharmony_ci      const GLuint index = first + i;
4719bf215546Sopenharmony_ci      struct gl_buffer_object * const boundBufObj = tfObj->Buffers[index];
4720bf215546Sopenharmony_ci      struct gl_buffer_object *bufObj;
4721bf215546Sopenharmony_ci      GLintptr offset = 0;
4722bf215546Sopenharmony_ci      GLsizeiptr size = 0;
4723bf215546Sopenharmony_ci
4724bf215546Sopenharmony_ci      if (range) {
4725bf215546Sopenharmony_ci         if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
4726bf215546Sopenharmony_ci            continue;
4727bf215546Sopenharmony_ci
4728bf215546Sopenharmony_ci         /* The ARB_multi_bind spec says:
4729bf215546Sopenharmony_ci          *
4730bf215546Sopenharmony_ci          *     "An INVALID_VALUE error is generated by BindBuffersRange if any
4731bf215546Sopenharmony_ci          *      pair of values in <offsets> and <sizes> does not respectively
4732bf215546Sopenharmony_ci          *      satisfy the constraints described for those parameters for the
4733bf215546Sopenharmony_ci          *      specified target, as described in section 6.7.1 (per binding)."
4734bf215546Sopenharmony_ci          *
4735bf215546Sopenharmony_ci          * Section 6.7.1 refers to table 6.5, which says:
4736bf215546Sopenharmony_ci          *
4737bf215546Sopenharmony_ci          *     "┌───────────────────────────────────────────────────────────────┐
4738bf215546Sopenharmony_ci          *      │ Transform feedback array bindings (see sec. 13.2.2)           │
4739bf215546Sopenharmony_ci          *      ├───────────────────────┬───────────────────────────────────────┤
4740bf215546Sopenharmony_ci          *      │    ...                │    ...                                │
4741bf215546Sopenharmony_ci          *      │    offset restriction │    multiple of 4                      │
4742bf215546Sopenharmony_ci          *      │    ...                │    ...                                │
4743bf215546Sopenharmony_ci          *      │    size restriction   │    multiple of 4                      │
4744bf215546Sopenharmony_ci          *      └───────────────────────┴───────────────────────────────────────┘"
4745bf215546Sopenharmony_ci          */
4746bf215546Sopenharmony_ci         if (offsets[i] & 0x3) {
4747bf215546Sopenharmony_ci            _mesa_error(ctx, GL_INVALID_VALUE,
4748bf215546Sopenharmony_ci                        "glBindBuffersRange(offsets[%u]=%" PRId64
4749bf215546Sopenharmony_ci                        " is misaligned; it must be a multiple of 4 when "
4750bf215546Sopenharmony_ci                        "target=GL_TRANSFORM_FEEDBACK_BUFFER)",
4751bf215546Sopenharmony_ci                        i, (int64_t) offsets[i]);
4752bf215546Sopenharmony_ci            continue;
4753bf215546Sopenharmony_ci         }
4754bf215546Sopenharmony_ci
4755bf215546Sopenharmony_ci         if (sizes[i] & 0x3) {
4756bf215546Sopenharmony_ci            _mesa_error(ctx, GL_INVALID_VALUE,
4757bf215546Sopenharmony_ci                        "glBindBuffersRange(sizes[%u]=%" PRId64
4758bf215546Sopenharmony_ci                        " is misaligned; it must be a multiple of 4 when "
4759bf215546Sopenharmony_ci                        "target=GL_TRANSFORM_FEEDBACK_BUFFER)",
4760bf215546Sopenharmony_ci                        i, (int64_t) sizes[i]);
4761bf215546Sopenharmony_ci            continue;
4762bf215546Sopenharmony_ci         }
4763bf215546Sopenharmony_ci
4764bf215546Sopenharmony_ci         offset = offsets[i];
4765bf215546Sopenharmony_ci         size = sizes[i];
4766bf215546Sopenharmony_ci      }
4767bf215546Sopenharmony_ci
4768bf215546Sopenharmony_ci      if (boundBufObj && boundBufObj->Name == buffers[i])
4769bf215546Sopenharmony_ci         bufObj = boundBufObj;
4770bf215546Sopenharmony_ci      else {
4771bf215546Sopenharmony_ci         bool error;
4772bf215546Sopenharmony_ci         bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, caller,
4773bf215546Sopenharmony_ci                                                    &error);
4774bf215546Sopenharmony_ci         if (error)
4775bf215546Sopenharmony_ci            continue;
4776bf215546Sopenharmony_ci      }
4777bf215546Sopenharmony_ci
4778bf215546Sopenharmony_ci      _mesa_set_transform_feedback_binding(ctx, tfObj, index, bufObj,
4779bf215546Sopenharmony_ci                                           offset, size);
4780bf215546Sopenharmony_ci   }
4781bf215546Sopenharmony_ci
4782bf215546Sopenharmony_ci   _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects,
4783bf215546Sopenharmony_ci                               ctx->BufferObjectsLocked);
4784bf215546Sopenharmony_ci}
4785bf215546Sopenharmony_ci
4786bf215546Sopenharmony_cistatic bool
4787bf215546Sopenharmony_cierror_check_bind_atomic_buffers(struct gl_context *ctx,
4788bf215546Sopenharmony_ci                                GLuint first, GLsizei count,
4789bf215546Sopenharmony_ci                                const char *caller)
4790bf215546Sopenharmony_ci{
4791bf215546Sopenharmony_ci   if (!ctx->Extensions.ARB_shader_atomic_counters) {
4792bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM,
4793bf215546Sopenharmony_ci                  "%s(target=GL_ATOMIC_COUNTER_BUFFER)", caller);
4794bf215546Sopenharmony_ci      return false;
4795bf215546Sopenharmony_ci   }
4796bf215546Sopenharmony_ci
4797bf215546Sopenharmony_ci   /* The ARB_multi_bind_spec says:
4798bf215546Sopenharmony_ci    *
4799bf215546Sopenharmony_ci    *     "An INVALID_OPERATION error is generated if <first> + <count> is
4800bf215546Sopenharmony_ci    *      greater than the number of target-specific indexed binding points,
4801bf215546Sopenharmony_ci    *      as described in section 6.7.1."
4802bf215546Sopenharmony_ci    */
4803bf215546Sopenharmony_ci   if (first + count > ctx->Const.MaxAtomicBufferBindings) {
4804bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
4805bf215546Sopenharmony_ci                  "%s(first=%u + count=%d > the value of "
4806bf215546Sopenharmony_ci                  "GL_MAX_ATOMIC_BUFFER_BINDINGS=%u)",
4807bf215546Sopenharmony_ci                  caller, first, count, ctx->Const.MaxAtomicBufferBindings);
4808bf215546Sopenharmony_ci      return false;
4809bf215546Sopenharmony_ci   }
4810bf215546Sopenharmony_ci
4811bf215546Sopenharmony_ci   return true;
4812bf215546Sopenharmony_ci}
4813bf215546Sopenharmony_ci
4814bf215546Sopenharmony_ci/**
4815bf215546Sopenharmony_ci * Unbind all atomic counter buffers in the range
4816bf215546Sopenharmony_ci * <first> through <first>+<count>-1
4817bf215546Sopenharmony_ci */
4818bf215546Sopenharmony_cistatic void
4819bf215546Sopenharmony_ciunbind_atomic_buffers(struct gl_context *ctx, GLuint first, GLsizei count)
4820bf215546Sopenharmony_ci{
4821bf215546Sopenharmony_ci   for (int i = 0; i < count; i++)
4822bf215546Sopenharmony_ci      set_buffer_binding(ctx, &ctx->AtomicBufferBindings[first + i],
4823bf215546Sopenharmony_ci                         NULL, -1, -1, GL_TRUE, 0);
4824bf215546Sopenharmony_ci}
4825bf215546Sopenharmony_ci
4826bf215546Sopenharmony_cistatic void
4827bf215546Sopenharmony_cibind_atomic_buffers(struct gl_context *ctx,
4828bf215546Sopenharmony_ci                    GLuint first,
4829bf215546Sopenharmony_ci                    GLsizei count,
4830bf215546Sopenharmony_ci                    const GLuint *buffers,
4831bf215546Sopenharmony_ci                    bool range,
4832bf215546Sopenharmony_ci                    const GLintptr *offsets,
4833bf215546Sopenharmony_ci                    const GLsizeiptr *sizes,
4834bf215546Sopenharmony_ci                    const char *caller)
4835bf215546Sopenharmony_ci{
4836bf215546Sopenharmony_ci   if (!error_check_bind_atomic_buffers(ctx, first, count, caller))
4837bf215546Sopenharmony_ci     return;
4838bf215546Sopenharmony_ci
4839bf215546Sopenharmony_ci   /* Assume that at least one binding will be changed */
4840bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, 0, 0);
4841bf215546Sopenharmony_ci   ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer;
4842bf215546Sopenharmony_ci
4843bf215546Sopenharmony_ci   if (!buffers) {
4844bf215546Sopenharmony_ci      /* The ARB_multi_bind spec says:
4845bf215546Sopenharmony_ci       *
4846bf215546Sopenharmony_ci       *    "If <buffers> is NULL, all bindings from <first> through
4847bf215546Sopenharmony_ci       *     <first>+<count>-1 are reset to their unbound (zero) state.
4848bf215546Sopenharmony_ci       *     In this case, the offsets and sizes associated with the
4849bf215546Sopenharmony_ci       *     binding points are set to default values, ignoring
4850bf215546Sopenharmony_ci       *     <offsets> and <sizes>."
4851bf215546Sopenharmony_ci       */
4852bf215546Sopenharmony_ci      unbind_atomic_buffers(ctx, first, count);
4853bf215546Sopenharmony_ci      return;
4854bf215546Sopenharmony_ci   }
4855bf215546Sopenharmony_ci
4856bf215546Sopenharmony_ci   /* Note that the error semantics for multi-bind commands differ from
4857bf215546Sopenharmony_ci    * those of other GL commands.
4858bf215546Sopenharmony_ci    *
4859bf215546Sopenharmony_ci    * The Issues section in the ARB_multi_bind spec says:
4860bf215546Sopenharmony_ci    *
4861bf215546Sopenharmony_ci    *    "(11) Typically, OpenGL specifies that if an error is generated by a
4862bf215546Sopenharmony_ci    *          command, that command has no effect.  This is somewhat
4863bf215546Sopenharmony_ci    *          unfortunate for multi-bind commands, because it would require a
4864bf215546Sopenharmony_ci    *          first pass to scan the entire list of bound objects for errors
4865bf215546Sopenharmony_ci    *          and then a second pass to actually perform the bindings.
4866bf215546Sopenharmony_ci    *          Should we have different error semantics?
4867bf215546Sopenharmony_ci    *
4868bf215546Sopenharmony_ci    *       RESOLVED:  Yes.  In this specification, when the parameters for
4869bf215546Sopenharmony_ci    *       one of the <count> binding points are invalid, that binding point
4870bf215546Sopenharmony_ci    *       is not updated and an error will be generated.  However, other
4871bf215546Sopenharmony_ci    *       binding points in the same command will be updated if their
4872bf215546Sopenharmony_ci    *       parameters are valid and no other error occurs."
4873bf215546Sopenharmony_ci    */
4874bf215546Sopenharmony_ci
4875bf215546Sopenharmony_ci   _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects,
4876bf215546Sopenharmony_ci                             ctx->BufferObjectsLocked);
4877bf215546Sopenharmony_ci
4878bf215546Sopenharmony_ci   for (int i = 0; i < count; i++) {
4879bf215546Sopenharmony_ci      struct gl_buffer_binding *binding =
4880bf215546Sopenharmony_ci         &ctx->AtomicBufferBindings[first + i];
4881bf215546Sopenharmony_ci      GLintptr offset = 0;
4882bf215546Sopenharmony_ci      GLsizeiptr size = 0;
4883bf215546Sopenharmony_ci
4884bf215546Sopenharmony_ci      if (range) {
4885bf215546Sopenharmony_ci         if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
4886bf215546Sopenharmony_ci            continue;
4887bf215546Sopenharmony_ci
4888bf215546Sopenharmony_ci         /* The ARB_multi_bind spec says:
4889bf215546Sopenharmony_ci          *
4890bf215546Sopenharmony_ci          *     "An INVALID_VALUE error is generated by BindBuffersRange if any
4891bf215546Sopenharmony_ci          *      pair of values in <offsets> and <sizes> does not respectively
4892bf215546Sopenharmony_ci          *      satisfy the constraints described for those parameters for the
4893bf215546Sopenharmony_ci          *      specified target, as described in section 6.7.1 (per binding)."
4894bf215546Sopenharmony_ci          *
4895bf215546Sopenharmony_ci          * Section 6.7.1 refers to table 6.5, which says:
4896bf215546Sopenharmony_ci          *
4897bf215546Sopenharmony_ci          *     "┌───────────────────────────────────────────────────────────────┐
4898bf215546Sopenharmony_ci          *      │ Atomic counter array bindings (see sec. 7.7.2)                │
4899bf215546Sopenharmony_ci          *      ├───────────────────────┬───────────────────────────────────────┤
4900bf215546Sopenharmony_ci          *      │    ...                │    ...                                │
4901bf215546Sopenharmony_ci          *      │    offset restriction │    multiple of 4                      │
4902bf215546Sopenharmony_ci          *      │    ...                │    ...                                │
4903bf215546Sopenharmony_ci          *      │    size restriction   │    none                               │
4904bf215546Sopenharmony_ci          *      └───────────────────────┴───────────────────────────────────────┘"
4905bf215546Sopenharmony_ci          */
4906bf215546Sopenharmony_ci         if (offsets[i] & (ATOMIC_COUNTER_SIZE - 1)) {
4907bf215546Sopenharmony_ci            _mesa_error(ctx, GL_INVALID_VALUE,
4908bf215546Sopenharmony_ci                        "glBindBuffersRange(offsets[%u]=%" PRId64
4909bf215546Sopenharmony_ci                        " is misaligned; it must be a multiple of %d when "
4910bf215546Sopenharmony_ci                        "target=GL_ATOMIC_COUNTER_BUFFER)",
4911bf215546Sopenharmony_ci                        i, (int64_t) offsets[i], ATOMIC_COUNTER_SIZE);
4912bf215546Sopenharmony_ci            continue;
4913bf215546Sopenharmony_ci         }
4914bf215546Sopenharmony_ci
4915bf215546Sopenharmony_ci         offset = offsets[i];
4916bf215546Sopenharmony_ci         size = sizes[i];
4917bf215546Sopenharmony_ci      }
4918bf215546Sopenharmony_ci
4919bf215546Sopenharmony_ci      set_buffer_multi_binding(ctx, buffers, i, caller,
4920bf215546Sopenharmony_ci                               binding, offset, size, range,
4921bf215546Sopenharmony_ci                               USAGE_ATOMIC_COUNTER_BUFFER);
4922bf215546Sopenharmony_ci   }
4923bf215546Sopenharmony_ci
4924bf215546Sopenharmony_ci   _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects,
4925bf215546Sopenharmony_ci                               ctx->BufferObjectsLocked);
4926bf215546Sopenharmony_ci}
4927bf215546Sopenharmony_ci
4928bf215546Sopenharmony_cistatic ALWAYS_INLINE void
4929bf215546Sopenharmony_cibind_buffer_range(GLenum target, GLuint index, GLuint buffer, GLintptr offset,
4930bf215546Sopenharmony_ci                  GLsizeiptr size, bool no_error)
4931bf215546Sopenharmony_ci{
4932bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
4933bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
4934bf215546Sopenharmony_ci
4935bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API) {
4936bf215546Sopenharmony_ci      _mesa_debug(ctx, "glBindBufferRange(%s, %u, %u, %lu, %lu)\n",
4937bf215546Sopenharmony_ci                  _mesa_enum_to_string(target), index, buffer,
4938bf215546Sopenharmony_ci                  (unsigned long) offset, (unsigned long) size);
4939bf215546Sopenharmony_ci   }
4940bf215546Sopenharmony_ci
4941bf215546Sopenharmony_ci   if (buffer == 0) {
4942bf215546Sopenharmony_ci      bufObj = NULL;
4943bf215546Sopenharmony_ci   } else {
4944bf215546Sopenharmony_ci      bufObj = _mesa_lookup_bufferobj(ctx, buffer);
4945bf215546Sopenharmony_ci      if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
4946bf215546Sopenharmony_ci                                        &bufObj, "glBindBufferRange", false))
4947bf215546Sopenharmony_ci         return;
4948bf215546Sopenharmony_ci
4949bf215546Sopenharmony_ci      if (!no_error && !bufObj) {
4950bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
4951bf215546Sopenharmony_ci                     "glBindBufferRange(invalid buffer=%u)", buffer);
4952bf215546Sopenharmony_ci         return;
4953bf215546Sopenharmony_ci      }
4954bf215546Sopenharmony_ci   }
4955bf215546Sopenharmony_ci
4956bf215546Sopenharmony_ci   if (no_error) {
4957bf215546Sopenharmony_ci      switch (target) {
4958bf215546Sopenharmony_ci      case GL_TRANSFORM_FEEDBACK_BUFFER:
4959bf215546Sopenharmony_ci         _mesa_bind_buffer_range_xfb(ctx, ctx->TransformFeedback.CurrentObject,
4960bf215546Sopenharmony_ci                                     index, bufObj, offset, size);
4961bf215546Sopenharmony_ci         return;
4962bf215546Sopenharmony_ci      case GL_UNIFORM_BUFFER:
4963bf215546Sopenharmony_ci         bind_buffer_range_uniform_buffer(ctx, index, bufObj, offset, size);
4964bf215546Sopenharmony_ci         return;
4965bf215546Sopenharmony_ci      case GL_SHADER_STORAGE_BUFFER:
4966bf215546Sopenharmony_ci         bind_buffer_range_shader_storage_buffer(ctx, index, bufObj, offset,
4967bf215546Sopenharmony_ci                                                 size);
4968bf215546Sopenharmony_ci         return;
4969bf215546Sopenharmony_ci      case GL_ATOMIC_COUNTER_BUFFER:
4970bf215546Sopenharmony_ci         bind_buffer_range_atomic_buffer(ctx, index, bufObj, offset, size);
4971bf215546Sopenharmony_ci         return;
4972bf215546Sopenharmony_ci      default:
4973bf215546Sopenharmony_ci         unreachable("invalid BindBufferRange target with KHR_no_error");
4974bf215546Sopenharmony_ci      }
4975bf215546Sopenharmony_ci   } else {
4976bf215546Sopenharmony_ci      if (buffer != 0) {
4977bf215546Sopenharmony_ci         if (size <= 0) {
4978bf215546Sopenharmony_ci            _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(size=%d)",
4979bf215546Sopenharmony_ci                        (int) size);
4980bf215546Sopenharmony_ci            return;
4981bf215546Sopenharmony_ci         }
4982bf215546Sopenharmony_ci      }
4983bf215546Sopenharmony_ci
4984bf215546Sopenharmony_ci      switch (target) {
4985bf215546Sopenharmony_ci      case GL_TRANSFORM_FEEDBACK_BUFFER:
4986bf215546Sopenharmony_ci         if (!_mesa_validate_buffer_range_xfb(ctx,
4987bf215546Sopenharmony_ci                                              ctx->TransformFeedback.CurrentObject,
4988bf215546Sopenharmony_ci                                              index, bufObj, offset, size,
4989bf215546Sopenharmony_ci                                              false))
4990bf215546Sopenharmony_ci            return;
4991bf215546Sopenharmony_ci
4992bf215546Sopenharmony_ci         _mesa_bind_buffer_range_xfb(ctx, ctx->TransformFeedback.CurrentObject,
4993bf215546Sopenharmony_ci                                     index, bufObj, offset, size);
4994bf215546Sopenharmony_ci         return;
4995bf215546Sopenharmony_ci      case GL_UNIFORM_BUFFER:
4996bf215546Sopenharmony_ci         bind_buffer_range_uniform_buffer_err(ctx, index, bufObj, offset,
4997bf215546Sopenharmony_ci                                              size);
4998bf215546Sopenharmony_ci         return;
4999bf215546Sopenharmony_ci      case GL_SHADER_STORAGE_BUFFER:
5000bf215546Sopenharmony_ci         bind_buffer_range_shader_storage_buffer_err(ctx, index, bufObj,
5001bf215546Sopenharmony_ci                                                     offset, size);
5002bf215546Sopenharmony_ci         return;
5003bf215546Sopenharmony_ci      case GL_ATOMIC_COUNTER_BUFFER:
5004bf215546Sopenharmony_ci         bind_buffer_range_atomic_buffer_err(ctx, index, bufObj,
5005bf215546Sopenharmony_ci                                             offset, size);
5006bf215546Sopenharmony_ci         return;
5007bf215546Sopenharmony_ci      default:
5008bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferRange(target)");
5009bf215546Sopenharmony_ci         return;
5010bf215546Sopenharmony_ci      }
5011bf215546Sopenharmony_ci   }
5012bf215546Sopenharmony_ci}
5013bf215546Sopenharmony_ci
5014bf215546Sopenharmony_civoid GLAPIENTRY
5015bf215546Sopenharmony_ci_mesa_BindBufferRange_no_error(GLenum target, GLuint index, GLuint buffer,
5016bf215546Sopenharmony_ci                               GLintptr offset, GLsizeiptr size)
5017bf215546Sopenharmony_ci{
5018bf215546Sopenharmony_ci   bind_buffer_range(target, index, buffer, offset, size, true);
5019bf215546Sopenharmony_ci}
5020bf215546Sopenharmony_ci
5021bf215546Sopenharmony_civoid GLAPIENTRY
5022bf215546Sopenharmony_ci_mesa_BindBufferRange(GLenum target, GLuint index,
5023bf215546Sopenharmony_ci                      GLuint buffer, GLintptr offset, GLsizeiptr size)
5024bf215546Sopenharmony_ci{
5025bf215546Sopenharmony_ci   bind_buffer_range(target, index, buffer, offset, size, false);
5026bf215546Sopenharmony_ci}
5027bf215546Sopenharmony_ci
5028bf215546Sopenharmony_civoid GLAPIENTRY
5029bf215546Sopenharmony_ci_mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer)
5030bf215546Sopenharmony_ci{
5031bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
5032bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
5033bf215546Sopenharmony_ci
5034bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API) {
5035bf215546Sopenharmony_ci      _mesa_debug(ctx, "glBindBufferBase(%s, %u, %u)\n",
5036bf215546Sopenharmony_ci                  _mesa_enum_to_string(target), index, buffer);
5037bf215546Sopenharmony_ci   }
5038bf215546Sopenharmony_ci
5039bf215546Sopenharmony_ci   if (buffer == 0) {
5040bf215546Sopenharmony_ci      bufObj = NULL;
5041bf215546Sopenharmony_ci   } else {
5042bf215546Sopenharmony_ci      bufObj = _mesa_lookup_bufferobj(ctx, buffer);
5043bf215546Sopenharmony_ci      if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
5044bf215546Sopenharmony_ci                                        &bufObj, "glBindBufferBase", false))
5045bf215546Sopenharmony_ci         return;
5046bf215546Sopenharmony_ci
5047bf215546Sopenharmony_ci      if (!bufObj) {
5048bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
5049bf215546Sopenharmony_ci                     "glBindBufferBase(invalid buffer=%u)", buffer);
5050bf215546Sopenharmony_ci         return;
5051bf215546Sopenharmony_ci      }
5052bf215546Sopenharmony_ci   }
5053bf215546Sopenharmony_ci
5054bf215546Sopenharmony_ci   /* Note that there's some oddness in the GL 3.1-GL 3.3 specifications with
5055bf215546Sopenharmony_ci    * regards to BindBufferBase.  It says (GL 3.1 core spec, page 63):
5056bf215546Sopenharmony_ci    *
5057bf215546Sopenharmony_ci    *     "BindBufferBase is equivalent to calling BindBufferRange with offset
5058bf215546Sopenharmony_ci    *      zero and size equal to the size of buffer."
5059bf215546Sopenharmony_ci    *
5060bf215546Sopenharmony_ci    * but it says for glGetIntegeri_v (GL 3.1 core spec, page 230):
5061bf215546Sopenharmony_ci    *
5062bf215546Sopenharmony_ci    *     "If the parameter (starting offset or size) was not specified when the
5063bf215546Sopenharmony_ci    *      buffer object was bound, zero is returned."
5064bf215546Sopenharmony_ci    *
5065bf215546Sopenharmony_ci    * What happens if the size of the buffer changes?  Does the size of the
5066bf215546Sopenharmony_ci    * buffer at the moment glBindBufferBase was called still play a role, like
5067bf215546Sopenharmony_ci    * the first quote would imply, or is the size meaningless in the
5068bf215546Sopenharmony_ci    * glBindBufferBase case like the second quote would suggest?  The GL 4.1
5069bf215546Sopenharmony_ci    * core spec page 45 says:
5070bf215546Sopenharmony_ci    *
5071bf215546Sopenharmony_ci    *     "It is equivalent to calling BindBufferRange with offset zero, while
5072bf215546Sopenharmony_ci    *      size is determined by the size of the bound buffer at the time the
5073bf215546Sopenharmony_ci    *      binding is used."
5074bf215546Sopenharmony_ci    *
5075bf215546Sopenharmony_ci    * My interpretation is that the GL 4.1 spec was a clarification of the
5076bf215546Sopenharmony_ci    * behavior, not a change.  In particular, this choice will only make
5077bf215546Sopenharmony_ci    * rendering work in cases where it would have had undefined results.
5078bf215546Sopenharmony_ci    */
5079bf215546Sopenharmony_ci
5080bf215546Sopenharmony_ci   switch (target) {
5081bf215546Sopenharmony_ci   case GL_TRANSFORM_FEEDBACK_BUFFER:
5082bf215546Sopenharmony_ci      _mesa_bind_buffer_base_transform_feedback(ctx,
5083bf215546Sopenharmony_ci                                                ctx->TransformFeedback.CurrentObject,
5084bf215546Sopenharmony_ci                                                index, bufObj, false);
5085bf215546Sopenharmony_ci      return;
5086bf215546Sopenharmony_ci   case GL_UNIFORM_BUFFER:
5087bf215546Sopenharmony_ci      bind_buffer_base_uniform_buffer(ctx, index, bufObj);
5088bf215546Sopenharmony_ci      return;
5089bf215546Sopenharmony_ci   case GL_SHADER_STORAGE_BUFFER:
5090bf215546Sopenharmony_ci      bind_buffer_base_shader_storage_buffer(ctx, index, bufObj);
5091bf215546Sopenharmony_ci      return;
5092bf215546Sopenharmony_ci   case GL_ATOMIC_COUNTER_BUFFER:
5093bf215546Sopenharmony_ci      bind_buffer_base_atomic_buffer(ctx, index, bufObj);
5094bf215546Sopenharmony_ci      return;
5095bf215546Sopenharmony_ci   default:
5096bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)");
5097bf215546Sopenharmony_ci      return;
5098bf215546Sopenharmony_ci   }
5099bf215546Sopenharmony_ci}
5100bf215546Sopenharmony_ci
5101bf215546Sopenharmony_civoid GLAPIENTRY
5102bf215546Sopenharmony_ci_mesa_BindBuffersRange(GLenum target, GLuint first, GLsizei count,
5103bf215546Sopenharmony_ci                       const GLuint *buffers,
5104bf215546Sopenharmony_ci                       const GLintptr *offsets, const GLsizeiptr *sizes)
5105bf215546Sopenharmony_ci{
5106bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
5107bf215546Sopenharmony_ci
5108bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API) {
5109bf215546Sopenharmony_ci      _mesa_debug(ctx, "glBindBuffersRange(%s, %u, %d, %p, %p, %p)\n",
5110bf215546Sopenharmony_ci                  _mesa_enum_to_string(target), first, count,
5111bf215546Sopenharmony_ci                  buffers, offsets, sizes);
5112bf215546Sopenharmony_ci   }
5113bf215546Sopenharmony_ci
5114bf215546Sopenharmony_ci   switch (target) {
5115bf215546Sopenharmony_ci   case GL_TRANSFORM_FEEDBACK_BUFFER:
5116bf215546Sopenharmony_ci      bind_xfb_buffers(ctx, first, count, buffers, true, offsets, sizes,
5117bf215546Sopenharmony_ci                       "glBindBuffersRange");
5118bf215546Sopenharmony_ci      return;
5119bf215546Sopenharmony_ci   case GL_UNIFORM_BUFFER:
5120bf215546Sopenharmony_ci      bind_uniform_buffers(ctx, first, count, buffers, true, offsets, sizes,
5121bf215546Sopenharmony_ci                           "glBindBuffersRange");
5122bf215546Sopenharmony_ci      return;
5123bf215546Sopenharmony_ci   case GL_SHADER_STORAGE_BUFFER:
5124bf215546Sopenharmony_ci      bind_shader_storage_buffers(ctx, first, count, buffers, true, offsets, sizes,
5125bf215546Sopenharmony_ci                                  "glBindBuffersRange");
5126bf215546Sopenharmony_ci      return;
5127bf215546Sopenharmony_ci   case GL_ATOMIC_COUNTER_BUFFER:
5128bf215546Sopenharmony_ci      bind_atomic_buffers(ctx, first, count, buffers, true, offsets, sizes,
5129bf215546Sopenharmony_ci                          "glBindBuffersRange");
5130bf215546Sopenharmony_ci      return;
5131bf215546Sopenharmony_ci   default:
5132bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glBindBuffersRange(target=%s)",
5133bf215546Sopenharmony_ci                  _mesa_enum_to_string(target));
5134bf215546Sopenharmony_ci      break;
5135bf215546Sopenharmony_ci   }
5136bf215546Sopenharmony_ci}
5137bf215546Sopenharmony_ci
5138bf215546Sopenharmony_civoid GLAPIENTRY
5139bf215546Sopenharmony_ci_mesa_BindBuffersBase(GLenum target, GLuint first, GLsizei count,
5140bf215546Sopenharmony_ci                      const GLuint *buffers)
5141bf215546Sopenharmony_ci{
5142bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
5143bf215546Sopenharmony_ci
5144bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API) {
5145bf215546Sopenharmony_ci      _mesa_debug(ctx, "glBindBuffersBase(%s, %u, %d, %p)\n",
5146bf215546Sopenharmony_ci                  _mesa_enum_to_string(target), first, count, buffers);
5147bf215546Sopenharmony_ci   }
5148bf215546Sopenharmony_ci
5149bf215546Sopenharmony_ci   switch (target) {
5150bf215546Sopenharmony_ci   case GL_TRANSFORM_FEEDBACK_BUFFER:
5151bf215546Sopenharmony_ci      bind_xfb_buffers(ctx, first, count, buffers, false, NULL, NULL,
5152bf215546Sopenharmony_ci                       "glBindBuffersBase");
5153bf215546Sopenharmony_ci      return;
5154bf215546Sopenharmony_ci   case GL_UNIFORM_BUFFER:
5155bf215546Sopenharmony_ci      bind_uniform_buffers(ctx, first, count, buffers, false, NULL, NULL,
5156bf215546Sopenharmony_ci                           "glBindBuffersBase");
5157bf215546Sopenharmony_ci      return;
5158bf215546Sopenharmony_ci   case GL_SHADER_STORAGE_BUFFER:
5159bf215546Sopenharmony_ci      bind_shader_storage_buffers(ctx, first, count, buffers, false, NULL, NULL,
5160bf215546Sopenharmony_ci                                  "glBindBuffersBase");
5161bf215546Sopenharmony_ci      return;
5162bf215546Sopenharmony_ci   case GL_ATOMIC_COUNTER_BUFFER:
5163bf215546Sopenharmony_ci      bind_atomic_buffers(ctx, first, count, buffers, false, NULL, NULL,
5164bf215546Sopenharmony_ci                          "glBindBuffersBase");
5165bf215546Sopenharmony_ci      return;
5166bf215546Sopenharmony_ci   default:
5167bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glBindBuffersBase(target=%s)",
5168bf215546Sopenharmony_ci                  _mesa_enum_to_string(target));
5169bf215546Sopenharmony_ci      break;
5170bf215546Sopenharmony_ci   }
5171bf215546Sopenharmony_ci}
5172bf215546Sopenharmony_ci
5173bf215546Sopenharmony_ci/**
5174bf215546Sopenharmony_ci * Called via glInvalidateBuffer(Sub)Data.
5175bf215546Sopenharmony_ci */
5176bf215546Sopenharmony_cistatic void
5177bf215546Sopenharmony_cibufferobj_invalidate(struct gl_context *ctx,
5178bf215546Sopenharmony_ci                     struct gl_buffer_object *obj,
5179bf215546Sopenharmony_ci                     GLintptr offset,
5180bf215546Sopenharmony_ci                     GLsizeiptr size)
5181bf215546Sopenharmony_ci{
5182bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
5183bf215546Sopenharmony_ci
5184bf215546Sopenharmony_ci   /* We ignore partial invalidates. */
5185bf215546Sopenharmony_ci   if (offset != 0 || size != obj->Size)
5186bf215546Sopenharmony_ci      return;
5187bf215546Sopenharmony_ci
5188bf215546Sopenharmony_ci   /* If the buffer is mapped, we can't invalidate it. */
5189bf215546Sopenharmony_ci   if (!obj->buffer || _mesa_bufferobj_mapped(obj, MAP_USER))
5190bf215546Sopenharmony_ci      return;
5191bf215546Sopenharmony_ci
5192bf215546Sopenharmony_ci   pipe->invalidate_resource(pipe, obj->buffer);
5193bf215546Sopenharmony_ci}
5194bf215546Sopenharmony_ci
5195bf215546Sopenharmony_cistatic ALWAYS_INLINE void
5196bf215546Sopenharmony_ciinvalidate_buffer_subdata(struct gl_context *ctx,
5197bf215546Sopenharmony_ci                          struct gl_buffer_object *bufObj, GLintptr offset,
5198bf215546Sopenharmony_ci                          GLsizeiptr length)
5199bf215546Sopenharmony_ci{
5200bf215546Sopenharmony_ci   if (ctx->has_invalidate_buffer)
5201bf215546Sopenharmony_ci      bufferobj_invalidate(ctx, bufObj, offset, length);
5202bf215546Sopenharmony_ci}
5203bf215546Sopenharmony_ci
5204bf215546Sopenharmony_civoid GLAPIENTRY
5205bf215546Sopenharmony_ci_mesa_InvalidateBufferSubData_no_error(GLuint buffer, GLintptr offset,
5206bf215546Sopenharmony_ci                                       GLsizeiptr length)
5207bf215546Sopenharmony_ci{
5208bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
5209bf215546Sopenharmony_ci
5210bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer);
5211bf215546Sopenharmony_ci   invalidate_buffer_subdata(ctx, bufObj, offset, length);
5212bf215546Sopenharmony_ci}
5213bf215546Sopenharmony_ci
5214bf215546Sopenharmony_civoid GLAPIENTRY
5215bf215546Sopenharmony_ci_mesa_InvalidateBufferSubData(GLuint buffer, GLintptr offset,
5216bf215546Sopenharmony_ci                              GLsizeiptr length)
5217bf215546Sopenharmony_ci{
5218bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
5219bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
5220bf215546Sopenharmony_ci   const GLintptr end = offset + length;
5221bf215546Sopenharmony_ci
5222bf215546Sopenharmony_ci   /* Section 6.5 (Invalidating Buffer Data) of the OpenGL 4.5 (Compatibility
5223bf215546Sopenharmony_ci    * Profile) spec says:
5224bf215546Sopenharmony_ci    *
5225bf215546Sopenharmony_ci    *     "An INVALID_VALUE error is generated if buffer is zero or is not the
5226bf215546Sopenharmony_ci    *     name of an existing buffer object."
5227bf215546Sopenharmony_ci    */
5228bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
5229bf215546Sopenharmony_ci   if (!bufObj || bufObj == &DummyBufferObject) {
5230bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
5231bf215546Sopenharmony_ci                  "glInvalidateBufferSubData(name = %u) invalid object",
5232bf215546Sopenharmony_ci                  buffer);
5233bf215546Sopenharmony_ci      return;
5234bf215546Sopenharmony_ci   }
5235bf215546Sopenharmony_ci
5236bf215546Sopenharmony_ci   /* The GL_ARB_invalidate_subdata spec says:
5237bf215546Sopenharmony_ci    *
5238bf215546Sopenharmony_ci    *     "An INVALID_VALUE error is generated if <offset> or <length> is
5239bf215546Sopenharmony_ci    *     negative, or if <offset> + <length> is greater than the value of
5240bf215546Sopenharmony_ci    *     BUFFER_SIZE."
5241bf215546Sopenharmony_ci    */
5242bf215546Sopenharmony_ci   if (offset < 0 || length < 0 || end > bufObj->Size) {
5243bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
5244bf215546Sopenharmony_ci                  "glInvalidateBufferSubData(invalid offset or length)");
5245bf215546Sopenharmony_ci      return;
5246bf215546Sopenharmony_ci   }
5247bf215546Sopenharmony_ci
5248bf215546Sopenharmony_ci   /* The OpenGL 4.4 (Core Profile) spec says:
5249bf215546Sopenharmony_ci    *
5250bf215546Sopenharmony_ci    *     "An INVALID_OPERATION error is generated if buffer is currently
5251bf215546Sopenharmony_ci    *     mapped by MapBuffer or if the invalidate range intersects the range
5252bf215546Sopenharmony_ci    *     currently mapped by MapBufferRange, unless it was mapped
5253bf215546Sopenharmony_ci    *     with MAP_PERSISTENT_BIT set in the MapBufferRange access flags."
5254bf215546Sopenharmony_ci    */
5255bf215546Sopenharmony_ci   if (!(bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_PERSISTENT_BIT) &&
5256bf215546Sopenharmony_ci       bufferobj_range_mapped(bufObj, offset, length)) {
5257bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
5258bf215546Sopenharmony_ci                  "glInvalidateBufferSubData(intersection with mapped "
5259bf215546Sopenharmony_ci                  "range)");
5260bf215546Sopenharmony_ci      return;
5261bf215546Sopenharmony_ci   }
5262bf215546Sopenharmony_ci
5263bf215546Sopenharmony_ci   invalidate_buffer_subdata(ctx, bufObj, offset, length);
5264bf215546Sopenharmony_ci}
5265bf215546Sopenharmony_ci
5266bf215546Sopenharmony_civoid GLAPIENTRY
5267bf215546Sopenharmony_ci_mesa_InvalidateBufferData_no_error(GLuint buffer)
5268bf215546Sopenharmony_ci{
5269bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
5270bf215546Sopenharmony_ci
5271bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj =_mesa_lookup_bufferobj(ctx, buffer);
5272bf215546Sopenharmony_ci   invalidate_buffer_subdata(ctx, bufObj, 0, bufObj->Size);
5273bf215546Sopenharmony_ci}
5274bf215546Sopenharmony_ci
5275bf215546Sopenharmony_civoid GLAPIENTRY
5276bf215546Sopenharmony_ci_mesa_InvalidateBufferData(GLuint buffer)
5277bf215546Sopenharmony_ci{
5278bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
5279bf215546Sopenharmony_ci   struct gl_buffer_object *bufObj;
5280bf215546Sopenharmony_ci
5281bf215546Sopenharmony_ci   /* Section 6.5 (Invalidating Buffer Data) of the OpenGL 4.5 (Compatibility
5282bf215546Sopenharmony_ci    * Profile) spec says:
5283bf215546Sopenharmony_ci    *
5284bf215546Sopenharmony_ci    *     "An INVALID_VALUE error is generated if buffer is zero or is not the
5285bf215546Sopenharmony_ci    *     name of an existing buffer object."
5286bf215546Sopenharmony_ci    */
5287bf215546Sopenharmony_ci   bufObj = _mesa_lookup_bufferobj(ctx, buffer);
5288bf215546Sopenharmony_ci   if (!bufObj || bufObj == &DummyBufferObject) {
5289bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
5290bf215546Sopenharmony_ci                  "glInvalidateBufferData(name = %u) invalid object",
5291bf215546Sopenharmony_ci                  buffer);
5292bf215546Sopenharmony_ci      return;
5293bf215546Sopenharmony_ci   }
5294bf215546Sopenharmony_ci
5295bf215546Sopenharmony_ci   /* The OpenGL 4.4 (Core Profile) spec says:
5296bf215546Sopenharmony_ci    *
5297bf215546Sopenharmony_ci    *     "An INVALID_OPERATION error is generated if buffer is currently
5298bf215546Sopenharmony_ci    *     mapped by MapBuffer or if the invalidate range intersects the range
5299bf215546Sopenharmony_ci    *     currently mapped by MapBufferRange, unless it was mapped
5300bf215546Sopenharmony_ci    *     with MAP_PERSISTENT_BIT set in the MapBufferRange access flags."
5301bf215546Sopenharmony_ci    */
5302bf215546Sopenharmony_ci   if (_mesa_check_disallowed_mapping(bufObj)) {
5303bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
5304bf215546Sopenharmony_ci                  "glInvalidateBufferData(intersection with mapped "
5305bf215546Sopenharmony_ci                  "range)");
5306bf215546Sopenharmony_ci      return;
5307bf215546Sopenharmony_ci   }
5308bf215546Sopenharmony_ci
5309bf215546Sopenharmony_ci   invalidate_buffer_subdata(ctx, bufObj, 0, bufObj->Size);
5310bf215546Sopenharmony_ci}
5311bf215546Sopenharmony_ci
5312bf215546Sopenharmony_cistatic void
5313bf215546Sopenharmony_cibuffer_page_commitment(struct gl_context *ctx,
5314bf215546Sopenharmony_ci                       struct gl_buffer_object *bufferObj,
5315bf215546Sopenharmony_ci                       GLintptr offset, GLsizeiptr size,
5316bf215546Sopenharmony_ci                       GLboolean commit, const char *func)
5317bf215546Sopenharmony_ci{
5318bf215546Sopenharmony_ci   if (!(bufferObj->StorageFlags & GL_SPARSE_STORAGE_BIT_ARB)) {
5319bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(not a sparse buffer object)",
5320bf215546Sopenharmony_ci                  func);
5321bf215546Sopenharmony_ci      return;
5322bf215546Sopenharmony_ci   }
5323bf215546Sopenharmony_ci
5324bf215546Sopenharmony_ci   if (size < 0 || size > bufferObj->Size ||
5325bf215546Sopenharmony_ci       offset < 0 || offset > bufferObj->Size - size) {
5326bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(out of bounds)",
5327bf215546Sopenharmony_ci                  func);
5328bf215546Sopenharmony_ci      return;
5329bf215546Sopenharmony_ci   }
5330bf215546Sopenharmony_ci
5331bf215546Sopenharmony_ci   /* The GL_ARB_sparse_buffer extension specification says:
5332bf215546Sopenharmony_ci    *
5333bf215546Sopenharmony_ci    *     "INVALID_VALUE is generated by BufferPageCommitmentARB if <offset> is
5334bf215546Sopenharmony_ci    *     not an integer multiple of SPARSE_BUFFER_PAGE_SIZE_ARB, or if <size>
5335bf215546Sopenharmony_ci    *     is not an integer multiple of SPARSE_BUFFER_PAGE_SIZE_ARB and does
5336bf215546Sopenharmony_ci    *     not extend to the end of the buffer's data store."
5337bf215546Sopenharmony_ci    */
5338bf215546Sopenharmony_ci   if (offset % ctx->Const.SparseBufferPageSize != 0) {
5339bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset not aligned to page size)",
5340bf215546Sopenharmony_ci                  func);
5341bf215546Sopenharmony_ci      return;
5342bf215546Sopenharmony_ci   }
5343bf215546Sopenharmony_ci
5344bf215546Sopenharmony_ci   if (size % ctx->Const.SparseBufferPageSize != 0 &&
5345bf215546Sopenharmony_ci       offset + size != bufferObj->Size) {
5346bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(size not aligned to page size)",
5347bf215546Sopenharmony_ci                  func);
5348bf215546Sopenharmony_ci      return;
5349bf215546Sopenharmony_ci   }
5350bf215546Sopenharmony_ci
5351bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
5352bf215546Sopenharmony_ci   struct pipe_box box;
5353bf215546Sopenharmony_ci
5354bf215546Sopenharmony_ci   u_box_1d(offset, size, &box);
5355bf215546Sopenharmony_ci
5356bf215546Sopenharmony_ci   if (!pipe->resource_commit(pipe, bufferObj->buffer, 0, &box, commit)) {
5357bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferPageCommitmentARB(out of memory)");
5358bf215546Sopenharmony_ci   }
5359bf215546Sopenharmony_ci}
5360bf215546Sopenharmony_ci
5361bf215546Sopenharmony_civoid GLAPIENTRY
5362bf215546Sopenharmony_ci_mesa_BufferPageCommitmentARB(GLenum target, GLintptr offset, GLsizeiptr size,
5363bf215546Sopenharmony_ci                              GLboolean commit)
5364bf215546Sopenharmony_ci{
5365bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
5366bf215546Sopenharmony_ci   struct gl_buffer_object *bufferObj;
5367bf215546Sopenharmony_ci
5368bf215546Sopenharmony_ci   bufferObj = get_buffer(ctx, "glBufferPageCommitmentARB", target,
5369bf215546Sopenharmony_ci                          GL_INVALID_ENUM);
5370bf215546Sopenharmony_ci   if (!bufferObj)
5371bf215546Sopenharmony_ci      return;
5372bf215546Sopenharmony_ci
5373bf215546Sopenharmony_ci   buffer_page_commitment(ctx, bufferObj, offset, size, commit,
5374bf215546Sopenharmony_ci                          "glBufferPageCommitmentARB");
5375bf215546Sopenharmony_ci}
5376bf215546Sopenharmony_ci
5377bf215546Sopenharmony_civoid GLAPIENTRY
5378bf215546Sopenharmony_ci_mesa_NamedBufferPageCommitmentARB(GLuint buffer, GLintptr offset,
5379bf215546Sopenharmony_ci                                   GLsizeiptr size, GLboolean commit)
5380bf215546Sopenharmony_ci{
5381bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
5382bf215546Sopenharmony_ci   struct gl_buffer_object *bufferObj;
5383bf215546Sopenharmony_ci
5384bf215546Sopenharmony_ci   bufferObj = _mesa_lookup_bufferobj(ctx, buffer);
5385bf215546Sopenharmony_ci   if (!bufferObj || bufferObj == &DummyBufferObject) {
5386bf215546Sopenharmony_ci      /* Note: the extension spec is not clear about the excpected error value. */
5387bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE,
5388bf215546Sopenharmony_ci                  "glNamedBufferPageCommitmentARB(name = %u) invalid object",
5389bf215546Sopenharmony_ci                  buffer);
5390bf215546Sopenharmony_ci      return;
5391bf215546Sopenharmony_ci   }
5392bf215546Sopenharmony_ci
5393bf215546Sopenharmony_ci   buffer_page_commitment(ctx, bufferObj, offset, size, commit,
5394bf215546Sopenharmony_ci                          "glNamedBufferPageCommitmentARB");
5395bf215546Sopenharmony_ci}
5396bf215546Sopenharmony_ci
5397bf215546Sopenharmony_civoid GLAPIENTRY
5398bf215546Sopenharmony_ci_mesa_NamedBufferPageCommitmentEXT(GLuint buffer, GLintptr offset,
5399bf215546Sopenharmony_ci                                   GLsizeiptr size, GLboolean commit)
5400bf215546Sopenharmony_ci{
5401bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
5402bf215546Sopenharmony_ci   struct gl_buffer_object *bufferObj;
5403bf215546Sopenharmony_ci
5404bf215546Sopenharmony_ci   /* Use NamedBuffer* functions logic from EXT_direct_state_access */
5405bf215546Sopenharmony_ci   if (buffer != 0) {
5406bf215546Sopenharmony_ci      bufferObj = _mesa_lookup_bufferobj(ctx, buffer);
5407bf215546Sopenharmony_ci      if (!_mesa_handle_bind_buffer_gen(ctx, buffer, &bufferObj,
5408bf215546Sopenharmony_ci                                        "glNamedBufferPageCommitmentEXT", false))
5409bf215546Sopenharmony_ci         return;
5410bf215546Sopenharmony_ci   } else {
5411bf215546Sopenharmony_ci      /* GL_EXT_direct_state_access says about NamedBuffer* functions:
5412bf215546Sopenharmony_ci       *
5413bf215546Sopenharmony_ci       *   There is no buffer corresponding to the name zero, these commands
5414bf215546Sopenharmony_ci       *   generate the INVALID_OPERATION error if the buffer parameter is
5415bf215546Sopenharmony_ci       *   zero.
5416bf215546Sopenharmony_ci       */
5417bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
5418bf215546Sopenharmony_ci                  "glNamedBufferPageCommitmentEXT(buffer = 0)");
5419bf215546Sopenharmony_ci      return;
5420bf215546Sopenharmony_ci   }
5421bf215546Sopenharmony_ci   buffer_page_commitment(ctx, bufferObj, offset, size, commit,
5422bf215546Sopenharmony_ci                          "glNamedBufferPageCommitmentEXT");
5423bf215546Sopenharmony_ci}
5424