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