main: Add entry point for NamedBufferSubData.
[mesa.git] / src / mesa / main / bufferobj.c
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 "glheader.h"
36 #include "enums.h"
37 #include "hash.h"
38 #include "imports.h"
39 #include "image.h"
40 #include "context.h"
41 #include "bufferobj.h"
42 #include "fbobject.h"
43 #include "mtypes.h"
44 #include "texobj.h"
45 #include "teximage.h"
46 #include "glformats.h"
47 #include "texstore.h"
48 #include "transformfeedback.h"
49 #include "dispatch.h"
50
51
52 /* Debug flags */
53 /*#define VBO_DEBUG*/
54 /*#define BOUNDS_CHECK*/
55
56
57 /**
58 * Used as a placeholder for buffer objects between glGenBuffers() and
59 * glBindBuffer() so that glIsBuffer() can work correctly.
60 */
61 static struct gl_buffer_object DummyBufferObject;
62
63
64 /**
65 * Return pointer to address of a buffer object target.
66 * \param ctx the GL context
67 * \param target the buffer object target to be retrieved.
68 * \return pointer to pointer to the buffer object bound to \c target in the
69 * specified context or \c NULL if \c target is invalid.
70 */
71 static inline struct gl_buffer_object **
72 get_buffer_target(struct gl_context *ctx, GLenum target)
73 {
74 /* Other targets are only supported in desktop OpenGL and OpenGL ES 3.0.
75 */
76 if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx)
77 && target != GL_ARRAY_BUFFER && target != GL_ELEMENT_ARRAY_BUFFER)
78 return NULL;
79
80 switch (target) {
81 case GL_ARRAY_BUFFER_ARB:
82 return &ctx->Array.ArrayBufferObj;
83 case GL_ELEMENT_ARRAY_BUFFER_ARB:
84 return &ctx->Array.VAO->IndexBufferObj;
85 case GL_PIXEL_PACK_BUFFER_EXT:
86 return &ctx->Pack.BufferObj;
87 case GL_PIXEL_UNPACK_BUFFER_EXT:
88 return &ctx->Unpack.BufferObj;
89 case GL_COPY_READ_BUFFER:
90 return &ctx->CopyReadBuffer;
91 case GL_COPY_WRITE_BUFFER:
92 return &ctx->CopyWriteBuffer;
93 case GL_DRAW_INDIRECT_BUFFER:
94 if (ctx->API == API_OPENGL_CORE &&
95 ctx->Extensions.ARB_draw_indirect) {
96 return &ctx->DrawIndirectBuffer;
97 }
98 break;
99 case GL_TRANSFORM_FEEDBACK_BUFFER:
100 if (ctx->Extensions.EXT_transform_feedback) {
101 return &ctx->TransformFeedback.CurrentBuffer;
102 }
103 break;
104 case GL_TEXTURE_BUFFER:
105 if (ctx->API == API_OPENGL_CORE &&
106 ctx->Extensions.ARB_texture_buffer_object) {
107 return &ctx->Texture.BufferObject;
108 }
109 break;
110 case GL_UNIFORM_BUFFER:
111 if (ctx->Extensions.ARB_uniform_buffer_object) {
112 return &ctx->UniformBuffer;
113 }
114 break;
115 case GL_ATOMIC_COUNTER_BUFFER:
116 if (ctx->Extensions.ARB_shader_atomic_counters) {
117 return &ctx->AtomicBuffer;
118 }
119 break;
120 case GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD:
121 if (ctx->Extensions.AMD_pinned_memory) {
122 return &ctx->ExternalVirtualMemoryBuffer;
123 }
124 break;
125 default:
126 return NULL;
127 }
128 return NULL;
129 }
130
131
132 /**
133 * Get the buffer object bound to the specified target in a GL context.
134 * \param ctx the GL context
135 * \param target the buffer object target to be retrieved.
136 * \param error the GL error to record if target is illegal.
137 * \return pointer to the buffer object bound to \c target in the
138 * specified context or \c NULL if \c target is invalid.
139 */
140 static inline struct gl_buffer_object *
141 get_buffer(struct gl_context *ctx, const char *func, GLenum target,
142 GLenum error)
143 {
144 struct gl_buffer_object **bufObj = get_buffer_target(ctx, target);
145
146 if (!bufObj) {
147 _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
148 return NULL;
149 }
150
151 if (!_mesa_is_bufferobj(*bufObj)) {
152 _mesa_error(ctx, error, "%s(no buffer bound)", func);
153 return NULL;
154 }
155
156 return *bufObj;
157 }
158
159
160 /**
161 * Convert a GLbitfield describing the mapped buffer access flags
162 * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY.
163 */
164 static GLenum
165 simplified_access_mode(struct gl_context *ctx, GLbitfield access)
166 {
167 const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
168 if ((access & rwFlags) == rwFlags)
169 return GL_READ_WRITE;
170 if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT)
171 return GL_READ_ONLY;
172 if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT)
173 return GL_WRITE_ONLY;
174
175 /* Otherwise, AccessFlags is zero (the default state).
176 *
177 * Table 2.6 on page 31 (page 44 of the PDF) of the OpenGL 1.5 spec says:
178 *
179 * Name Type Initial Value Legal Values
180 * ... ... ... ...
181 * BUFFER_ACCESS enum READ_WRITE READ_ONLY, WRITE_ONLY
182 * READ_WRITE
183 *
184 * However, table 6.8 in the GL_OES_mapbuffer extension says:
185 *
186 * Get Value Type Get Command Value Description
187 * --------- ---- ----------- ----- -----------
188 * BUFFER_ACCESS_OES Z1 GetBufferParameteriv WRITE_ONLY_OES buffer map flag
189 *
190 * The difference is because GL_OES_mapbuffer only supports mapping buffers
191 * write-only.
192 */
193 assert(access == 0);
194
195 return _mesa_is_gles(ctx) ? GL_WRITE_ONLY : GL_READ_WRITE;
196 }
197
198
199 /**
200 * Test if the buffer is mapped, and if so, if the mapped range overlaps the
201 * given range.
202 * The regions do not overlap if and only if the end of the given
203 * region is before the mapped region or the start of the given region
204 * is after the mapped region.
205 *
206 * \param obj Buffer object target on which to operate.
207 * \param offset Offset of the first byte of the subdata range.
208 * \param size Size, in bytes, of the subdata range.
209 * \return true if ranges overlap, false otherwise
210 *
211 */
212 static bool
213 bufferobj_range_mapped(const struct gl_buffer_object *obj,
214 GLintptr offset, GLsizeiptr size)
215 {
216 if (_mesa_bufferobj_mapped(obj, MAP_USER)) {
217 const GLintptr end = offset + size;
218 const GLintptr mapEnd = obj->Mappings[MAP_USER].Offset +
219 obj->Mappings[MAP_USER].Length;
220
221 if (!(end <= obj->Mappings[MAP_USER].Offset || offset >= mapEnd)) {
222 return true;
223 }
224 }
225 return false;
226 }
227
228
229 /**
230 * Tests the subdata range parameters and sets the GL error code for
231 * \c glBufferSubDataARB, \c glGetBufferSubDataARB and
232 * \c glClearBufferSubData.
233 *
234 * \param ctx GL context.
235 * \param bufObj The buffer object.
236 * \param offset Offset of the first byte of the subdata range.
237 * \param size Size, in bytes, of the subdata range.
238 * \param mappedRange If true, checks if an overlapping range is mapped.
239 * If false, checks if buffer is mapped.
240 * \param caller Name of calling function for recording errors.
241 * \return false if error, true otherwise
242 *
243 * \sa glBufferSubDataARB, glGetBufferSubDataARB, glClearBufferSubData
244 */
245 static bool
246 buffer_object_subdata_range_good(struct gl_context *ctx,
247 struct gl_buffer_object *bufObj,
248 GLintptr offset, GLsizeiptr size,
249 bool mappedRange, const char *caller)
250 {
251 if (size < 0) {
252 _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller);
253 return false;
254 }
255
256 if (offset < 0) {
257 _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller);
258 return false;
259 }
260
261 if (offset + size > bufObj->Size) {
262 _mesa_error(ctx, GL_INVALID_VALUE,
263 "%s(offset %lu + size %lu > buffer size %lu)", caller,
264 (unsigned long) offset,
265 (unsigned long) size,
266 (unsigned long) bufObj->Size);
267 return false;
268 }
269
270 if (bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_PERSISTENT_BIT)
271 return true;
272
273 if (mappedRange) {
274 if (bufferobj_range_mapped(bufObj, offset, size)) {
275 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
276 return false;
277 }
278 }
279 else {
280 if (_mesa_bufferobj_mapped(bufObj, MAP_USER)) {
281 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
282 return false;
283 }
284 }
285
286 return true;
287 }
288
289
290 /**
291 * Test the format and type parameters and set the GL error code for
292 * \c glClearBufferData and \c glClearBufferSubData.
293 *
294 * \param ctx GL context.
295 * \param internalformat Format to which the data is to be converted.
296 * \param format Format of the supplied data.
297 * \param type Type of the supplied data.
298 * \param caller Name of calling function for recording errors.
299 * \return If internalformat, format and type are legal the mesa_format
300 * corresponding to internalformat, otherwise MESA_FORMAT_NONE.
301 *
302 * \sa glClearBufferData and glClearBufferSubData
303 */
304 static mesa_format
305 validate_clear_buffer_format(struct gl_context *ctx,
306 GLenum internalformat,
307 GLenum format, GLenum type,
308 const char *caller)
309 {
310 mesa_format mesaFormat;
311 GLenum errorFormatType;
312
313 mesaFormat = _mesa_validate_texbuffer_format(ctx, internalformat);
314 if (mesaFormat == MESA_FORMAT_NONE) {
315 _mesa_error(ctx, GL_INVALID_ENUM,
316 "%s(invalid internalformat)", caller);
317 return MESA_FORMAT_NONE;
318 }
319
320 /* NOTE: not mentioned in ARB_clear_buffer_object but according to
321 * EXT_texture_integer there is no conversion between integer and
322 * non-integer formats
323 */
324 if (_mesa_is_enum_format_signed_int(format) !=
325 _mesa_is_format_integer_color(mesaFormat)) {
326 _mesa_error(ctx, GL_INVALID_OPERATION,
327 "%s(integer vs non-integer)", caller);
328 return MESA_FORMAT_NONE;
329 }
330
331 if (!_mesa_is_color_format(format)) {
332 _mesa_error(ctx, GL_INVALID_ENUM,
333 "%s(format is not a color format)", caller);
334 return MESA_FORMAT_NONE;
335 }
336
337 errorFormatType = _mesa_error_check_format_and_type(ctx, format, type);
338 if (errorFormatType != GL_NO_ERROR) {
339 _mesa_error(ctx, GL_INVALID_ENUM,
340 "%s(invalid format or type)", caller);
341 return MESA_FORMAT_NONE;
342 }
343
344 return mesaFormat;
345 }
346
347
348 /**
349 * Convert user-specified clear value to the specified internal format.
350 *
351 * \param ctx GL context.
352 * \param internalformat Format to which the data is converted.
353 * \param clearValue Points to the converted clear value.
354 * \param format Format of the supplied data.
355 * \param type Type of the supplied data.
356 * \param data Data which is to be converted to internalformat.
357 * \param caller Name of calling function for recording errors.
358 * \return true if data could be converted, false otherwise.
359 *
360 * \sa glClearBufferData, glClearBufferSubData
361 */
362 static bool
363 convert_clear_buffer_data(struct gl_context *ctx,
364 mesa_format internalformat,
365 GLubyte *clearValue, GLenum format, GLenum type,
366 const GLvoid *data, const char *caller)
367 {
368 GLenum internalformatBase = _mesa_get_format_base_format(internalformat);
369
370 if (_mesa_texstore(ctx, 1, internalformatBase, internalformat,
371 0, &clearValue, 1, 1, 1,
372 format, type, data, &ctx->Unpack)) {
373 return true;
374 }
375 else {
376 _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller);
377 return false;
378 }
379 }
380
381
382 /**
383 * Allocate and initialize a new buffer object.
384 *
385 * Default callback for the \c dd_function_table::NewBufferObject() hook.
386 */
387 static struct gl_buffer_object *
388 _mesa_new_buffer_object(struct gl_context *ctx, GLuint name)
389 {
390 struct gl_buffer_object *obj;
391
392 (void) ctx;
393
394 obj = MALLOC_STRUCT(gl_buffer_object);
395 _mesa_initialize_buffer_object(ctx, obj, name);
396 return obj;
397 }
398
399
400 /**
401 * Delete a buffer object.
402 *
403 * Default callback for the \c dd_function_table::DeleteBuffer() hook.
404 */
405 static void
406 _mesa_delete_buffer_object(struct gl_context *ctx,
407 struct gl_buffer_object *bufObj)
408 {
409 (void) ctx;
410
411 _mesa_align_free(bufObj->Data);
412
413 /* assign strange values here to help w/ debugging */
414 bufObj->RefCount = -1000;
415 bufObj->Name = ~0;
416
417 mtx_destroy(&bufObj->Mutex);
418 free(bufObj->Label);
419 free(bufObj);
420 }
421
422
423
424 /**
425 * Set ptr to bufObj w/ reference counting.
426 * This is normally only called from the _mesa_reference_buffer_object() macro
427 * when there's a real pointer change.
428 */
429 void
430 _mesa_reference_buffer_object_(struct gl_context *ctx,
431 struct gl_buffer_object **ptr,
432 struct gl_buffer_object *bufObj)
433 {
434 if (*ptr) {
435 /* Unreference the old buffer */
436 GLboolean deleteFlag = GL_FALSE;
437 struct gl_buffer_object *oldObj = *ptr;
438
439 mtx_lock(&oldObj->Mutex);
440 assert(oldObj->RefCount > 0);
441 oldObj->RefCount--;
442 #if 0
443 printf("BufferObj %p %d DECR to %d\n",
444 (void *) oldObj, oldObj->Name, oldObj->RefCount);
445 #endif
446 deleteFlag = (oldObj->RefCount == 0);
447 mtx_unlock(&oldObj->Mutex);
448
449 if (deleteFlag) {
450
451 /* some sanity checking: don't delete a buffer still in use */
452 #if 0
453 /* unfortunately, these tests are invalid during context tear-down */
454 assert(ctx->Array.ArrayBufferObj != bufObj);
455 assert(ctx->Array.VAO->IndexBufferObj != bufObj);
456 assert(ctx->Array.VAO->Vertex.BufferObj != bufObj);
457 #endif
458
459 assert(ctx->Driver.DeleteBuffer);
460 ctx->Driver.DeleteBuffer(ctx, oldObj);
461 }
462
463 *ptr = NULL;
464 }
465 assert(!*ptr);
466
467 if (bufObj) {
468 /* reference new buffer */
469 mtx_lock(&bufObj->Mutex);
470 if (bufObj->RefCount == 0) {
471 /* this buffer's being deleted (look just above) */
472 /* Not sure this can every really happen. Warn if it does. */
473 _mesa_problem(NULL, "referencing deleted buffer object");
474 *ptr = NULL;
475 }
476 else {
477 bufObj->RefCount++;
478 #if 0
479 printf("BufferObj %p %d INCR to %d\n",
480 (void *) bufObj, bufObj->Name, bufObj->RefCount);
481 #endif
482 *ptr = bufObj;
483 }
484 mtx_unlock(&bufObj->Mutex);
485 }
486 }
487
488
489 /**
490 * Initialize a buffer object to default values.
491 */
492 void
493 _mesa_initialize_buffer_object(struct gl_context *ctx,
494 struct gl_buffer_object *obj,
495 GLuint name)
496 {
497 memset(obj, 0, sizeof(struct gl_buffer_object));
498 mtx_init(&obj->Mutex, mtx_plain);
499 obj->RefCount = 1;
500 obj->Name = name;
501 obj->Usage = GL_STATIC_DRAW_ARB;
502 }
503
504
505
506 /**
507 * Callback called from _mesa_HashWalk()
508 */
509 static void
510 count_buffer_size(GLuint key, void *data, void *userData)
511 {
512 const struct gl_buffer_object *bufObj =
513 (const struct gl_buffer_object *) data;
514 GLuint *total = (GLuint *) userData;
515
516 *total = *total + bufObj->Size;
517 }
518
519
520 /**
521 * Compute total size (in bytes) of all buffer objects for the given context.
522 * For debugging purposes.
523 */
524 GLuint
525 _mesa_total_buffer_object_memory(struct gl_context *ctx)
526 {
527 GLuint total = 0;
528
529 _mesa_HashWalk(ctx->Shared->BufferObjects, count_buffer_size, &total);
530
531 return total;
532 }
533
534
535 /**
536 * Allocate space for and store data in a buffer object. Any data that was
537 * previously stored in the buffer object is lost. If \c data is \c NULL,
538 * memory will be allocated, but no copy will occur.
539 *
540 * This is the default callback for \c dd_function_table::BufferData()
541 * Note that all GL error checking will have been done already.
542 *
543 * \param ctx GL context.
544 * \param target Buffer object target on which to operate.
545 * \param size Size, in bytes, of the new data store.
546 * \param data Pointer to the data to store in the buffer object. This
547 * pointer may be \c NULL.
548 * \param usage Hints about how the data will be used.
549 * \param bufObj Object to be used.
550 *
551 * \return GL_TRUE for success, GL_FALSE for failure
552 * \sa glBufferDataARB, dd_function_table::BufferData.
553 */
554 static GLboolean
555 buffer_data_fallback(struct gl_context *ctx, GLenum target, GLsizeiptr size,
556 const GLvoid *data, GLenum usage, GLenum storageFlags,
557 struct gl_buffer_object *bufObj)
558 {
559 void * new_data;
560
561 (void) target;
562
563 _mesa_align_free( bufObj->Data );
564
565 new_data = _mesa_align_malloc( size, ctx->Const.MinMapBufferAlignment );
566 if (new_data) {
567 bufObj->Data = (GLubyte *) new_data;
568 bufObj->Size = size;
569 bufObj->Usage = usage;
570 bufObj->StorageFlags = storageFlags;
571
572 if (data) {
573 memcpy( bufObj->Data, data, size );
574 }
575
576 return GL_TRUE;
577 }
578 else {
579 return GL_FALSE;
580 }
581 }
582
583
584 /**
585 * Replace data in a subrange of buffer object. If the data range
586 * specified by \c size + \c offset extends beyond the end of the buffer or
587 * if \c data is \c NULL, no copy is performed.
588 *
589 * This is the default callback for \c dd_function_table::BufferSubData()
590 * Note that all GL error checking will have been done already.
591 *
592 * \param ctx GL context.
593 * \param offset Offset of the first byte to be modified.
594 * \param size Size, in bytes, of the data range.
595 * \param data Pointer to the data to store in the buffer object.
596 * \param bufObj Object to be used.
597 *
598 * \sa glBufferSubDataARB, dd_function_table::BufferSubData.
599 */
600 static void
601 buffer_sub_data_fallback(struct gl_context *ctx, GLintptr offset,
602 GLsizeiptr size, const GLvoid *data,
603 struct gl_buffer_object *bufObj)
604 {
605 (void) ctx;
606
607 /* this should have been caught in _mesa_BufferSubData() */
608 assert(size + offset <= bufObj->Size);
609
610 if (bufObj->Data) {
611 memcpy( (GLubyte *) bufObj->Data + offset, data, size );
612 }
613 }
614
615
616 /**
617 * Retrieve data from a subrange of buffer object. If the data range
618 * specified by \c size + \c offset extends beyond the end of the buffer or
619 * if \c data is \c NULL, no copy is performed.
620 *
621 * This is the default callback for \c dd_function_table::GetBufferSubData()
622 * Note that all GL error checking will have been done already.
623 *
624 * \param ctx GL context.
625 * \param target Buffer object target on which to operate.
626 * \param offset Offset of the first byte to be fetched.
627 * \param size Size, in bytes, of the data range.
628 * \param data Destination for data
629 * \param bufObj Object to be used.
630 *
631 * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData.
632 */
633 static void
634 _mesa_buffer_get_subdata( struct gl_context *ctx, GLintptrARB offset,
635 GLsizeiptrARB size, GLvoid * data,
636 struct gl_buffer_object * bufObj )
637 {
638 (void) ctx;
639
640 if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) {
641 memcpy( data, (GLubyte *) bufObj->Data + offset, size );
642 }
643 }
644
645
646 /**
647 * Clear a subrange of the buffer object with copies of the supplied data.
648 * If data is NULL the buffer is filled with zeros.
649 *
650 * This is the default callback for \c dd_function_table::ClearBufferSubData()
651 * Note that all GL error checking will have been done already.
652 *
653 * \param ctx GL context.
654 * \param offset Offset of the first byte to be cleared.
655 * \param size Size, in bytes, of the to be cleared range.
656 * \param clearValue Source of the data.
657 * \param clearValueSize Size, in bytes, of the supplied data.
658 * \param bufObj Object to be cleared.
659 *
660 * \sa glClearBufferSubData, glClearBufferData and
661 * dd_function_table::ClearBufferSubData.
662 */
663 void
664 _mesa_buffer_clear_subdata(struct gl_context *ctx,
665 GLintptr offset, GLsizeiptr size,
666 const GLvoid *clearValue,
667 GLsizeiptr clearValueSize,
668 struct gl_buffer_object *bufObj)
669 {
670 GLsizeiptr i;
671 GLubyte *dest;
672
673 assert(ctx->Driver.MapBufferRange);
674 dest = ctx->Driver.MapBufferRange(ctx, offset, size,
675 GL_MAP_WRITE_BIT |
676 GL_MAP_INVALIDATE_RANGE_BIT,
677 bufObj, MAP_INTERNAL);
678
679 if (!dest) {
680 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClearBuffer[Sub]Data");
681 return;
682 }
683
684 if (clearValue == NULL) {
685 /* Clear with zeros, per the spec */
686 memset(dest, 0, size);
687 ctx->Driver.UnmapBuffer(ctx, bufObj, MAP_INTERNAL);
688 return;
689 }
690
691 for (i = 0; i < size/clearValueSize; ++i) {
692 memcpy(dest, clearValue, clearValueSize);
693 dest += clearValueSize;
694 }
695
696 ctx->Driver.UnmapBuffer(ctx, bufObj, MAP_INTERNAL);
697 }
698
699
700 /**
701 * Default fallback for \c dd_function_table::MapBufferRange().
702 * Called via glMapBufferRange().
703 */
704 static void *
705 _mesa_buffer_map_range( struct gl_context *ctx, GLintptr offset,
706 GLsizeiptr length, GLbitfield access,
707 struct gl_buffer_object *bufObj,
708 gl_map_buffer_index index)
709 {
710 (void) ctx;
711 assert(!_mesa_bufferobj_mapped(bufObj, index));
712 /* Just return a direct pointer to the data */
713 bufObj->Mappings[index].Pointer = bufObj->Data + offset;
714 bufObj->Mappings[index].Length = length;
715 bufObj->Mappings[index].Offset = offset;
716 bufObj->Mappings[index].AccessFlags = access;
717 return bufObj->Mappings[index].Pointer;
718 }
719
720
721 /**
722 * Default fallback for \c dd_function_table::FlushMappedBufferRange().
723 * Called via glFlushMappedBufferRange().
724 */
725 static void
726 _mesa_buffer_flush_mapped_range( struct gl_context *ctx,
727 GLintptr offset, GLsizeiptr length,
728 struct gl_buffer_object *obj,
729 gl_map_buffer_index index)
730 {
731 (void) ctx;
732 (void) offset;
733 (void) length;
734 (void) obj;
735 /* no-op */
736 }
737
738
739 /**
740 * Default callback for \c dd_function_table::MapBuffer().
741 *
742 * The input parameters will have been already tested for errors.
743 *
744 * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer
745 */
746 static GLboolean
747 _mesa_buffer_unmap(struct gl_context *ctx, struct gl_buffer_object *bufObj,
748 gl_map_buffer_index index)
749 {
750 (void) ctx;
751 /* XXX we might assert here that bufObj->Pointer is non-null */
752 bufObj->Mappings[index].Pointer = NULL;
753 bufObj->Mappings[index].Length = 0;
754 bufObj->Mappings[index].Offset = 0;
755 bufObj->Mappings[index].AccessFlags = 0x0;
756 return GL_TRUE;
757 }
758
759
760 /**
761 * Default fallback for \c dd_function_table::CopyBufferSubData().
762 * Called via glCopyBufferSubData().
763 */
764 static void
765 _mesa_copy_buffer_subdata(struct gl_context *ctx,
766 struct gl_buffer_object *src,
767 struct gl_buffer_object *dst,
768 GLintptr readOffset, GLintptr writeOffset,
769 GLsizeiptr size)
770 {
771 GLubyte *srcPtr, *dstPtr;
772
773 if (src == dst) {
774 srcPtr = dstPtr = ctx->Driver.MapBufferRange(ctx, 0, src->Size,
775 GL_MAP_READ_BIT |
776 GL_MAP_WRITE_BIT, src,
777 MAP_INTERNAL);
778
779 if (!srcPtr)
780 return;
781
782 srcPtr += readOffset;
783 dstPtr += writeOffset;
784 } else {
785 srcPtr = ctx->Driver.MapBufferRange(ctx, readOffset, size,
786 GL_MAP_READ_BIT, src,
787 MAP_INTERNAL);
788 dstPtr = ctx->Driver.MapBufferRange(ctx, writeOffset, size,
789 (GL_MAP_WRITE_BIT |
790 GL_MAP_INVALIDATE_RANGE_BIT), dst,
791 MAP_INTERNAL);
792 }
793
794 /* Note: the src and dst regions will never overlap. Trying to do so
795 * would generate GL_INVALID_VALUE earlier.
796 */
797 if (srcPtr && dstPtr)
798 memcpy(dstPtr, srcPtr, size);
799
800 ctx->Driver.UnmapBuffer(ctx, src, MAP_INTERNAL);
801 if (dst != src)
802 ctx->Driver.UnmapBuffer(ctx, dst, MAP_INTERNAL);
803 }
804
805
806
807 /**
808 * Initialize the state associated with buffer objects
809 */
810 void
811 _mesa_init_buffer_objects( struct gl_context *ctx )
812 {
813 GLuint i;
814
815 memset(&DummyBufferObject, 0, sizeof(DummyBufferObject));
816 mtx_init(&DummyBufferObject.Mutex, mtx_plain);
817 DummyBufferObject.RefCount = 1000*1000*1000; /* never delete */
818
819 _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj,
820 ctx->Shared->NullBufferObj);
821
822 _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer,
823 ctx->Shared->NullBufferObj);
824 _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer,
825 ctx->Shared->NullBufferObj);
826
827 _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer,
828 ctx->Shared->NullBufferObj);
829
830 _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer,
831 ctx->Shared->NullBufferObj);
832
833 _mesa_reference_buffer_object(ctx, &ctx->DrawIndirectBuffer,
834 ctx->Shared->NullBufferObj);
835
836 for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) {
837 _mesa_reference_buffer_object(ctx,
838 &ctx->UniformBufferBindings[i].BufferObject,
839 ctx->Shared->NullBufferObj);
840 ctx->UniformBufferBindings[i].Offset = -1;
841 ctx->UniformBufferBindings[i].Size = -1;
842 }
843
844 for (i = 0; i < MAX_COMBINED_ATOMIC_BUFFERS; i++) {
845 _mesa_reference_buffer_object(ctx,
846 &ctx->AtomicBufferBindings[i].BufferObject,
847 ctx->Shared->NullBufferObj);
848 ctx->AtomicBufferBindings[i].Offset = -1;
849 ctx->AtomicBufferBindings[i].Size = -1;
850 }
851 }
852
853
854 void
855 _mesa_free_buffer_objects( struct gl_context *ctx )
856 {
857 GLuint i;
858
859 _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL);
860
861 _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, NULL);
862 _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, NULL);
863
864 _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, NULL);
865
866 _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, NULL);
867
868 _mesa_reference_buffer_object(ctx, &ctx->DrawIndirectBuffer, NULL);
869
870 for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) {
871 _mesa_reference_buffer_object(ctx,
872 &ctx->UniformBufferBindings[i].BufferObject,
873 NULL);
874 }
875
876 for (i = 0; i < MAX_COMBINED_ATOMIC_BUFFERS; i++) {
877 _mesa_reference_buffer_object(ctx,
878 &ctx->AtomicBufferBindings[i].BufferObject,
879 NULL);
880 }
881
882 }
883
884 bool
885 _mesa_handle_bind_buffer_gen(struct gl_context *ctx,
886 GLenum target,
887 GLuint buffer,
888 struct gl_buffer_object **buf_handle,
889 const char *caller)
890 {
891 struct gl_buffer_object *buf = *buf_handle;
892
893 if (!buf && ctx->API == API_OPENGL_CORE) {
894 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", caller);
895 return false;
896 }
897
898 if (!buf || buf == &DummyBufferObject) {
899 /* If this is a new buffer object id, or one which was generated but
900 * never used before, allocate a buffer object now.
901 */
902 assert(ctx->Driver.NewBufferObject);
903 buf = ctx->Driver.NewBufferObject(ctx, buffer);
904 if (!buf) {
905 _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller);
906 return false;
907 }
908 _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, buf);
909 *buf_handle = buf;
910 }
911
912 return true;
913 }
914
915 /**
916 * Bind the specified target to buffer for the specified context.
917 * Called by glBindBuffer() and other functions.
918 */
919 static void
920 bind_buffer_object(struct gl_context *ctx, GLenum target, GLuint buffer)
921 {
922 struct gl_buffer_object *oldBufObj;
923 struct gl_buffer_object *newBufObj = NULL;
924 struct gl_buffer_object **bindTarget = NULL;
925
926 bindTarget = get_buffer_target(ctx, target);
927 if (!bindTarget) {
928 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)", target);
929 return;
930 }
931
932 /* Get pointer to old buffer object (to be unbound) */
933 oldBufObj = *bindTarget;
934 if (oldBufObj && oldBufObj->Name == buffer && !oldBufObj->DeletePending)
935 return; /* rebinding the same buffer object- no change */
936
937 /*
938 * Get pointer to new buffer object (newBufObj)
939 */
940 if (buffer == 0) {
941 /* The spec says there's not a buffer object named 0, but we use
942 * one internally because it simplifies things.
943 */
944 newBufObj = ctx->Shared->NullBufferObj;
945 }
946 else {
947 /* non-default buffer object */
948 newBufObj = _mesa_lookup_bufferobj(ctx, buffer);
949 if (!_mesa_handle_bind_buffer_gen(ctx, target, buffer,
950 &newBufObj, "glBindBuffer"))
951 return;
952 }
953
954 /* bind new buffer */
955 _mesa_reference_buffer_object(ctx, bindTarget, newBufObj);
956 }
957
958
959 /**
960 * Update the default buffer objects in the given context to reference those
961 * specified in the shared state and release those referencing the old
962 * shared state.
963 */
964 void
965 _mesa_update_default_objects_buffer_objects(struct gl_context *ctx)
966 {
967 /* Bind the NullBufferObj to remove references to those
968 * in the shared context hash table.
969 */
970 bind_buffer_object( ctx, GL_ARRAY_BUFFER_ARB, 0);
971 bind_buffer_object( ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
972 bind_buffer_object( ctx, GL_PIXEL_PACK_BUFFER_ARB, 0);
973 bind_buffer_object( ctx, GL_PIXEL_UNPACK_BUFFER_ARB, 0);
974 }
975
976
977
978 /**
979 * Return the gl_buffer_object for the given ID.
980 * Always return NULL for ID 0.
981 */
982 struct gl_buffer_object *
983 _mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer)
984 {
985 if (buffer == 0)
986 return NULL;
987 else
988 return (struct gl_buffer_object *)
989 _mesa_HashLookup(ctx->Shared->BufferObjects, buffer);
990 }
991
992
993 struct gl_buffer_object *
994 _mesa_lookup_bufferobj_locked(struct gl_context *ctx, GLuint buffer)
995 {
996 return (struct gl_buffer_object *)
997 _mesa_HashLookupLocked(ctx->Shared->BufferObjects, buffer);
998 }
999
1000 /**
1001 * A convenience function for direct state access functions that throws
1002 * GL_INVALID_OPERATION if buffer is not the name of a buffer object in the
1003 * hash table.
1004 */
1005 struct gl_buffer_object *
1006 _mesa_lookup_bufferobj_err(struct gl_context *ctx, GLuint buffer,
1007 const char *caller)
1008 {
1009 struct gl_buffer_object *bufObj;
1010
1011 bufObj = _mesa_lookup_bufferobj(ctx, buffer);
1012 if (!bufObj)
1013 _mesa_error(ctx, GL_INVALID_OPERATION,
1014 "%s(non-generated buffer name %u)", caller, buffer);
1015
1016 return bufObj;
1017 }
1018
1019
1020 void
1021 _mesa_begin_bufferobj_lookups(struct gl_context *ctx)
1022 {
1023 _mesa_HashLockMutex(ctx->Shared->BufferObjects);
1024 }
1025
1026
1027 void
1028 _mesa_end_bufferobj_lookups(struct gl_context *ctx)
1029 {
1030 _mesa_HashUnlockMutex(ctx->Shared->BufferObjects);
1031 }
1032
1033
1034 /**
1035 * Look up a buffer object for a multi-bind function.
1036 *
1037 * Unlike _mesa_lookup_bufferobj(), this function also takes care
1038 * of generating an error if the buffer ID is not zero or the name
1039 * of an existing buffer object.
1040 *
1041 * If the buffer ID refers to an existing buffer object, a pointer
1042 * to the buffer object is returned. If the ID is zero, a pointer
1043 * to the shared NullBufferObj is returned. If the ID is not zero
1044 * and does not refer to a valid buffer object, this function
1045 * returns NULL.
1046 *
1047 * This function assumes that the caller has already locked the
1048 * hash table mutex by calling _mesa_begin_bufferobj_lookups().
1049 */
1050 struct gl_buffer_object *
1051 _mesa_multi_bind_lookup_bufferobj(struct gl_context *ctx,
1052 const GLuint *buffers,
1053 GLuint index, const char *caller)
1054 {
1055 struct gl_buffer_object *bufObj;
1056
1057 if (buffers[index] != 0) {
1058 bufObj = _mesa_lookup_bufferobj_locked(ctx, buffers[index]);
1059
1060 /* The multi-bind functions don't create the buffer objects
1061 when they don't exist. */
1062 if (bufObj == &DummyBufferObject)
1063 bufObj = NULL;
1064 } else
1065 bufObj = ctx->Shared->NullBufferObj;
1066
1067 if (!bufObj) {
1068 /* The ARB_multi_bind spec says:
1069 *
1070 * "An INVALID_OPERATION error is generated if any value
1071 * in <buffers> is not zero or the name of an existing
1072 * buffer object (per binding)."
1073 */
1074 _mesa_error(ctx, GL_INVALID_OPERATION,
1075 "%s(buffers[%u]=%u is not zero or the name "
1076 "of an existing buffer object)",
1077 caller, index, buffers[index]);
1078 }
1079
1080 return bufObj;
1081 }
1082
1083
1084 /**
1085 * If *ptr points to obj, set ptr = the Null/default buffer object.
1086 * This is a helper for buffer object deletion.
1087 * The GL spec says that deleting a buffer object causes it to get
1088 * unbound from all arrays in the current context.
1089 */
1090 static void
1091 unbind(struct gl_context *ctx,
1092 struct gl_buffer_object **ptr,
1093 struct gl_buffer_object *obj)
1094 {
1095 if (*ptr == obj) {
1096 _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj);
1097 }
1098 }
1099
1100
1101 /**
1102 * Plug default/fallback buffer object functions into the device
1103 * driver hooks.
1104 */
1105 void
1106 _mesa_init_buffer_object_functions(struct dd_function_table *driver)
1107 {
1108 /* GL_ARB_vertex/pixel_buffer_object */
1109 driver->NewBufferObject = _mesa_new_buffer_object;
1110 driver->DeleteBuffer = _mesa_delete_buffer_object;
1111 driver->BufferData = buffer_data_fallback;
1112 driver->BufferSubData = buffer_sub_data_fallback;
1113 driver->GetBufferSubData = _mesa_buffer_get_subdata;
1114 driver->UnmapBuffer = _mesa_buffer_unmap;
1115
1116 /* GL_ARB_clear_buffer_object */
1117 driver->ClearBufferSubData = _mesa_buffer_clear_subdata;
1118
1119 /* GL_ARB_map_buffer_range */
1120 driver->MapBufferRange = _mesa_buffer_map_range;
1121 driver->FlushMappedBufferRange = _mesa_buffer_flush_mapped_range;
1122
1123 /* GL_ARB_copy_buffer */
1124 driver->CopyBufferSubData = _mesa_copy_buffer_subdata;
1125 }
1126
1127
1128 void
1129 _mesa_buffer_unmap_all_mappings(struct gl_context *ctx,
1130 struct gl_buffer_object *bufObj)
1131 {
1132 int i;
1133
1134 for (i = 0; i < MAP_COUNT; i++) {
1135 if (_mesa_bufferobj_mapped(bufObj, i)) {
1136 ctx->Driver.UnmapBuffer(ctx, bufObj, i);
1137 assert(bufObj->Mappings[i].Pointer == NULL);
1138 bufObj->Mappings[i].AccessFlags = 0;
1139 }
1140 }
1141 }
1142
1143
1144 /**********************************************************************/
1145 /* API Functions */
1146 /**********************************************************************/
1147
1148 void GLAPIENTRY
1149 _mesa_BindBuffer(GLenum target, GLuint buffer)
1150 {
1151 GET_CURRENT_CONTEXT(ctx);
1152
1153 if (MESA_VERBOSE & VERBOSE_API)
1154 _mesa_debug(ctx, "glBindBuffer(%s, %u)\n",
1155 _mesa_lookup_enum_by_nr(target), buffer);
1156
1157 bind_buffer_object(ctx, target, buffer);
1158 }
1159
1160
1161 /**
1162 * Delete a set of buffer objects.
1163 *
1164 * \param n Number of buffer objects to delete.
1165 * \param ids Array of \c n buffer object IDs.
1166 */
1167 void GLAPIENTRY
1168 _mesa_DeleteBuffers(GLsizei n, const GLuint *ids)
1169 {
1170 GET_CURRENT_CONTEXT(ctx);
1171 GLsizei i;
1172 FLUSH_VERTICES(ctx, 0);
1173
1174 if (n < 0) {
1175 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)");
1176 return;
1177 }
1178
1179 mtx_lock(&ctx->Shared->Mutex);
1180
1181 for (i = 0; i < n; i++) {
1182 struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]);
1183 if (bufObj) {
1184 struct gl_vertex_array_object *vao = ctx->Array.VAO;
1185 GLuint j;
1186
1187 assert(bufObj->Name == ids[i] || bufObj == &DummyBufferObject);
1188
1189 _mesa_buffer_unmap_all_mappings(ctx, bufObj);
1190
1191 /* unbind any vertex pointers bound to this buffer */
1192 for (j = 0; j < ARRAY_SIZE(vao->VertexBinding); j++) {
1193 unbind(ctx, &vao->VertexBinding[j].BufferObj, bufObj);
1194 }
1195
1196 if (ctx->Array.ArrayBufferObj == bufObj) {
1197 _mesa_BindBuffer( GL_ARRAY_BUFFER_ARB, 0 );
1198 }
1199 if (vao->IndexBufferObj == bufObj) {
1200 _mesa_BindBuffer( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
1201 }
1202
1203 /* unbind ARB_draw_indirect binding point */
1204 if (ctx->DrawIndirectBuffer == bufObj) {
1205 _mesa_BindBuffer( GL_DRAW_INDIRECT_BUFFER, 0 );
1206 }
1207
1208 /* unbind ARB_copy_buffer binding points */
1209 if (ctx->CopyReadBuffer == bufObj) {
1210 _mesa_BindBuffer( GL_COPY_READ_BUFFER, 0 );
1211 }
1212 if (ctx->CopyWriteBuffer == bufObj) {
1213 _mesa_BindBuffer( GL_COPY_WRITE_BUFFER, 0 );
1214 }
1215
1216 /* unbind transform feedback binding points */
1217 if (ctx->TransformFeedback.CurrentBuffer == bufObj) {
1218 _mesa_BindBuffer( GL_TRANSFORM_FEEDBACK_BUFFER, 0 );
1219 }
1220 for (j = 0; j < MAX_FEEDBACK_BUFFERS; j++) {
1221 if (ctx->TransformFeedback.CurrentObject->Buffers[j] == bufObj) {
1222 _mesa_BindBufferBase( GL_TRANSFORM_FEEDBACK_BUFFER, j, 0 );
1223 }
1224 }
1225
1226 /* unbind UBO binding points */
1227 for (j = 0; j < ctx->Const.MaxUniformBufferBindings; j++) {
1228 if (ctx->UniformBufferBindings[j].BufferObject == bufObj) {
1229 _mesa_BindBufferBase( GL_UNIFORM_BUFFER, j, 0 );
1230 }
1231 }
1232
1233 if (ctx->UniformBuffer == bufObj) {
1234 _mesa_BindBuffer( GL_UNIFORM_BUFFER, 0 );
1235 }
1236
1237 /* unbind Atomci Buffer binding points */
1238 for (j = 0; j < ctx->Const.MaxAtomicBufferBindings; j++) {
1239 if (ctx->AtomicBufferBindings[j].BufferObject == bufObj) {
1240 _mesa_BindBufferBase( GL_ATOMIC_COUNTER_BUFFER, j, 0 );
1241 }
1242 }
1243
1244 if (ctx->AtomicBuffer == bufObj) {
1245 _mesa_BindBuffer( GL_ATOMIC_COUNTER_BUFFER, 0 );
1246 }
1247
1248 /* unbind any pixel pack/unpack pointers bound to this buffer */
1249 if (ctx->Pack.BufferObj == bufObj) {
1250 _mesa_BindBuffer( GL_PIXEL_PACK_BUFFER_EXT, 0 );
1251 }
1252 if (ctx->Unpack.BufferObj == bufObj) {
1253 _mesa_BindBuffer( GL_PIXEL_UNPACK_BUFFER_EXT, 0 );
1254 }
1255
1256 if (ctx->Texture.BufferObject == bufObj) {
1257 _mesa_BindBuffer( GL_TEXTURE_BUFFER, 0 );
1258 }
1259
1260 if (ctx->ExternalVirtualMemoryBuffer == bufObj) {
1261 _mesa_BindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0);
1262 }
1263
1264 /* The ID is immediately freed for re-use */
1265 _mesa_HashRemove(ctx->Shared->BufferObjects, ids[i]);
1266 /* Make sure we do not run into the classic ABA problem on bind.
1267 * We don't want to allow re-binding a buffer object that's been
1268 * "deleted" by glDeleteBuffers().
1269 *
1270 * The explicit rebinding to the default object in the current context
1271 * prevents the above in the current context, but another context
1272 * sharing the same objects might suffer from this problem.
1273 * The alternative would be to do the hash lookup in any case on bind
1274 * which would introduce more runtime overhead than this.
1275 */
1276 bufObj->DeletePending = GL_TRUE;
1277 _mesa_reference_buffer_object(ctx, &bufObj, NULL);
1278 }
1279 }
1280
1281 mtx_unlock(&ctx->Shared->Mutex);
1282 }
1283
1284
1285 /**
1286 * This is the implementation for glGenBuffers and glCreateBuffers. It is not
1287 * exposed to the rest of Mesa to encourage the use of nameless buffers in
1288 * driver internals.
1289 */
1290 static void
1291 create_buffers(GLsizei n, GLuint *buffers, bool dsa)
1292 {
1293 GET_CURRENT_CONTEXT(ctx);
1294 GLuint first;
1295 GLint i;
1296 struct gl_buffer_object *buf;
1297
1298 const char *func = dsa ? "glCreateBuffers" : "glGenBuffers";
1299
1300 if (MESA_VERBOSE & VERBOSE_API)
1301 _mesa_debug(ctx, "%s(%d)\n", func, n);
1302
1303 if (n < 0) {
1304 _mesa_error(ctx, GL_INVALID_VALUE, "%s(n %d < 0)", func, n);
1305 return;
1306 }
1307
1308 if (!buffers) {
1309 return;
1310 }
1311
1312 /*
1313 * This must be atomic (generation and allocation of buffer object IDs)
1314 */
1315 mtx_lock(&ctx->Shared->Mutex);
1316
1317 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n);
1318
1319 /* Insert the ID and pointer into the hash table. If non-DSA, insert a
1320 * DummyBufferObject. Otherwise, create a new buffer object and insert
1321 * it.
1322 */
1323 for (i = 0; i < n; i++) {
1324 buffers[i] = first + i;
1325 if (dsa) {
1326 assert(ctx->Driver.NewBufferObject);
1327 buf = ctx->Driver.NewBufferObject(ctx, buffers[i]);
1328 if (!buf) {
1329 _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
1330 return;
1331 }
1332 }
1333 else
1334 buf = &DummyBufferObject;
1335
1336 _mesa_HashInsert(ctx->Shared->BufferObjects, buffers[i], buf);
1337 }
1338
1339 mtx_unlock(&ctx->Shared->Mutex);
1340 }
1341
1342 /**
1343 * Generate a set of unique buffer object IDs and store them in \c buffers.
1344 *
1345 * \param n Number of IDs to generate.
1346 * \param buffers Array of \c n locations to store the IDs.
1347 */
1348 void GLAPIENTRY
1349 _mesa_GenBuffers(GLsizei n, GLuint *buffers)
1350 {
1351 create_buffers(n, buffers, false);
1352 }
1353
1354 /**
1355 * Create a set of buffer objects and store their unique IDs in \c buffers.
1356 *
1357 * \param n Number of IDs to generate.
1358 * \param buffers Array of \c n locations to store the IDs.
1359 */
1360 void GLAPIENTRY
1361 _mesa_CreateBuffers(GLsizei n, GLuint *buffers)
1362 {
1363 create_buffers(n, buffers, true);
1364 }
1365
1366
1367 /**
1368 * Determine if ID is the name of a buffer object.
1369 *
1370 * \param id ID of the potential buffer object.
1371 * \return \c GL_TRUE if \c id is the name of a buffer object,
1372 * \c GL_FALSE otherwise.
1373 */
1374 GLboolean GLAPIENTRY
1375 _mesa_IsBuffer(GLuint id)
1376 {
1377 struct gl_buffer_object *bufObj;
1378 GET_CURRENT_CONTEXT(ctx);
1379 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1380
1381 mtx_lock(&ctx->Shared->Mutex);
1382 bufObj = _mesa_lookup_bufferobj(ctx, id);
1383 mtx_unlock(&ctx->Shared->Mutex);
1384
1385 return bufObj && bufObj != &DummyBufferObject;
1386 }
1387
1388
1389 void
1390 _mesa_buffer_storage(struct gl_context *ctx, struct gl_buffer_object *bufObj,
1391 GLenum target, GLsizeiptr size, const GLvoid *data,
1392 GLbitfield flags, const char *func)
1393 {
1394 if (size <= 0) {
1395 _mesa_error(ctx, GL_INVALID_VALUE, "%s(size <= 0)", func);
1396 return;
1397 }
1398
1399 if (flags & ~(GL_MAP_READ_BIT |
1400 GL_MAP_WRITE_BIT |
1401 GL_MAP_PERSISTENT_BIT |
1402 GL_MAP_COHERENT_BIT |
1403 GL_DYNAMIC_STORAGE_BIT |
1404 GL_CLIENT_STORAGE_BIT)) {
1405 _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid flag bits set)", func);
1406 return;
1407 }
1408
1409 if (flags & GL_MAP_PERSISTENT_BIT &&
1410 !(flags & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT))) {
1411 _mesa_error(ctx, GL_INVALID_VALUE,
1412 "%s(PERSISTENT and flags!=READ/WRITE)", func);
1413 return;
1414 }
1415
1416 if (flags & GL_MAP_COHERENT_BIT && !(flags & GL_MAP_PERSISTENT_BIT)) {
1417 _mesa_error(ctx, GL_INVALID_VALUE,
1418 "%s(COHERENT and flags!=PERSISTENT)", func);
1419 return;
1420 }
1421
1422 if (bufObj->Immutable) {
1423 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(immutable)", func);
1424 return;
1425 }
1426
1427 /* Unmap the existing buffer. We'll replace it now. Not an error. */
1428 _mesa_buffer_unmap_all_mappings(ctx, bufObj);
1429
1430 FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT);
1431
1432 bufObj->Written = GL_TRUE;
1433 bufObj->Immutable = GL_TRUE;
1434
1435 assert(ctx->Driver.BufferData);
1436 if (!ctx->Driver.BufferData(ctx, target, size, data, GL_DYNAMIC_DRAW,
1437 flags, bufObj)) {
1438 if (target == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD) {
1439 /* Even though the interaction between AMD_pinned_memory and
1440 * glBufferStorage is not described in the spec, Graham Sellers
1441 * said that it should behave the same as glBufferData.
1442 */
1443 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func);
1444 }
1445 else {
1446 _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
1447 }
1448 }
1449 }
1450
1451 void GLAPIENTRY
1452 _mesa_BufferStorage(GLenum target, GLsizeiptr size, const GLvoid *data,
1453 GLbitfield flags)
1454 {
1455 GET_CURRENT_CONTEXT(ctx);
1456 struct gl_buffer_object *bufObj;
1457
1458 bufObj = get_buffer(ctx, "glBufferStorage", target, GL_INVALID_OPERATION);
1459 if (!bufObj)
1460 return;
1461
1462 _mesa_buffer_storage(ctx, bufObj, target, size, data, flags,
1463 "glBufferStorage");
1464 }
1465
1466 void GLAPIENTRY
1467 _mesa_NamedBufferStorage(GLuint buffer, GLsizeiptr size, const GLvoid *data,
1468 GLbitfield flags)
1469 {
1470 GET_CURRENT_CONTEXT(ctx);
1471 struct gl_buffer_object *bufObj;
1472
1473 bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glNamedBufferStorage");
1474 if (!bufObj)
1475 return;
1476
1477 /*
1478 * In direct state access, buffer objects have an unspecified target since
1479 * they are not required to be bound.
1480 */
1481 _mesa_buffer_storage(ctx, bufObj, GL_NONE, size, data, flags,
1482 "glNamedBufferStorage");
1483 }
1484
1485
1486 void
1487 _mesa_buffer_data(struct gl_context *ctx, struct gl_buffer_object *bufObj,
1488 GLenum target, GLsizeiptr size, const GLvoid *data,
1489 GLenum usage, const char *func)
1490 {
1491 bool valid_usage;
1492
1493 if (MESA_VERBOSE & VERBOSE_API)
1494 _mesa_debug(ctx, "%s(%s, %ld, %p, %s)\n",
1495 func,
1496 _mesa_lookup_enum_by_nr(target),
1497 (long int) size, data,
1498 _mesa_lookup_enum_by_nr(usage));
1499
1500 if (size < 0) {
1501 _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", func);
1502 return;
1503 }
1504
1505 switch (usage) {
1506 case GL_STREAM_DRAW_ARB:
1507 valid_usage = (ctx->API != API_OPENGLES);
1508 break;
1509
1510 case GL_STATIC_DRAW_ARB:
1511 case GL_DYNAMIC_DRAW_ARB:
1512 valid_usage = true;
1513 break;
1514
1515 case GL_STREAM_READ_ARB:
1516 case GL_STREAM_COPY_ARB:
1517 case GL_STATIC_READ_ARB:
1518 case GL_STATIC_COPY_ARB:
1519 case GL_DYNAMIC_READ_ARB:
1520 case GL_DYNAMIC_COPY_ARB:
1521 valid_usage = _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx);
1522 break;
1523
1524 default:
1525 valid_usage = false;
1526 break;
1527 }
1528
1529 if (!valid_usage) {
1530 _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid usage: %s)", func,
1531 _mesa_lookup_enum_by_nr(usage));
1532 return;
1533 }
1534
1535 if (bufObj->Immutable) {
1536 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(immutable)", func);
1537 return;
1538 }
1539
1540 /* Unmap the existing buffer. We'll replace it now. Not an error. */
1541 _mesa_buffer_unmap_all_mappings(ctx, bufObj);
1542
1543 FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT);
1544
1545 bufObj->Written = GL_TRUE;
1546
1547 #ifdef VBO_DEBUG
1548 printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n",
1549 bufObj->Name, size, data, usage);
1550 #endif
1551
1552 #ifdef BOUNDS_CHECK
1553 size += 100;
1554 #endif
1555
1556 assert(ctx->Driver.BufferData);
1557 if (!ctx->Driver.BufferData(ctx, target, size, data, usage,
1558 GL_MAP_READ_BIT |
1559 GL_MAP_WRITE_BIT |
1560 GL_DYNAMIC_STORAGE_BIT,
1561 bufObj)) {
1562 if (target == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD) {
1563 /* From GL_AMD_pinned_memory:
1564 *
1565 * INVALID_OPERATION is generated by BufferData if <target> is
1566 * EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, and the store cannot be
1567 * mapped to the GPU address space.
1568 */
1569 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func);
1570 }
1571 else {
1572 _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
1573 }
1574 }
1575 }
1576
1577 void GLAPIENTRY
1578 _mesa_BufferData(GLenum target, GLsizeiptr size,
1579 const GLvoid *data, GLenum usage)
1580 {
1581 GET_CURRENT_CONTEXT(ctx);
1582 struct gl_buffer_object *bufObj;
1583
1584 bufObj = get_buffer(ctx, "glBufferData", target, GL_INVALID_OPERATION);
1585 if (!bufObj)
1586 return;
1587
1588 _mesa_buffer_data(ctx, bufObj, target, size, data, usage,
1589 "glBufferData");
1590 }
1591
1592 void GLAPIENTRY
1593 _mesa_NamedBufferData(GLuint buffer, GLsizeiptr size, const GLvoid *data,
1594 GLenum usage)
1595 {
1596 GET_CURRENT_CONTEXT(ctx);
1597 struct gl_buffer_object *bufObj;
1598
1599 bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glNamedBufferData");
1600 if (!bufObj)
1601 return;
1602
1603 /* In direct state access, buffer objects have an unspecified target since
1604 * they are not required to be bound.
1605 */
1606 _mesa_buffer_data(ctx, bufObj, GL_NONE, size, data, usage,
1607 "glNamedBufferData");
1608 }
1609
1610
1611 /**
1612 * Implementation for glBufferSubData and glNamedBufferSubData.
1613 *
1614 * \param ctx GL context.
1615 * \param bufObj The buffer object.
1616 * \param offset Offset of the first byte of the subdata range.
1617 * \param size Size, in bytes, of the subdata range.
1618 * \param data The data store.
1619 * \param func Name of calling function for recording errors.
1620 *
1621 */
1622 void
1623 _mesa_buffer_sub_data(struct gl_context *ctx, struct gl_buffer_object *bufObj,
1624 GLintptr offset, GLsizeiptr size, const GLvoid *data,
1625 const char *func)
1626 {
1627 if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size,
1628 false, func)) {
1629 /* error already recorded */
1630 return;
1631 }
1632
1633 if (bufObj->Immutable &&
1634 !(bufObj->StorageFlags & GL_DYNAMIC_STORAGE_BIT)) {
1635 _mesa_error(ctx, GL_INVALID_OPERATION, func);
1636 return;
1637 }
1638
1639 if (size == 0)
1640 return;
1641
1642 bufObj->Written = GL_TRUE;
1643
1644 assert(ctx->Driver.BufferSubData);
1645 ctx->Driver.BufferSubData( ctx, offset, size, data, bufObj );
1646 }
1647
1648 void GLAPIENTRY
1649 _mesa_BufferSubData(GLenum target, GLintptr offset,
1650 GLsizeiptr size, const GLvoid *data)
1651 {
1652 GET_CURRENT_CONTEXT(ctx);
1653 struct gl_buffer_object *bufObj;
1654
1655 bufObj = get_buffer(ctx, "glBufferSubData", target, GL_INVALID_OPERATION);
1656 if (!bufObj)
1657 return;
1658
1659 _mesa_buffer_sub_data(ctx, bufObj, offset, size, data, "glBufferSubData");
1660 }
1661
1662 void GLAPIENTRY
1663 _mesa_NamedBufferSubData(GLuint buffer, GLintptr offset,
1664 GLsizeiptr size, const GLvoid *data)
1665 {
1666 GET_CURRENT_CONTEXT(ctx);
1667 struct gl_buffer_object *bufObj;
1668
1669 bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glNamedBufferSubData");
1670 if (!bufObj)
1671 return;
1672
1673 _mesa_buffer_sub_data(ctx, bufObj, offset, size, data,
1674 "glNamedBufferSubData");
1675 }
1676
1677
1678 void GLAPIENTRY
1679 _mesa_GetBufferSubData(GLenum target, GLintptr offset,
1680 GLsizeiptr size, GLvoid *data)
1681 {
1682 GET_CURRENT_CONTEXT(ctx);
1683 struct gl_buffer_object *bufObj;
1684
1685 bufObj = get_buffer(ctx, "glGetBufferSubData", target,
1686 GL_INVALID_OPERATION);
1687 if (!bufObj)
1688 return;
1689
1690 if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size, false,
1691 "glGetBufferSubData")) {
1692 return;
1693 }
1694
1695 assert(ctx->Driver.GetBufferSubData);
1696 ctx->Driver.GetBufferSubData( ctx, offset, size, data, bufObj );
1697 }
1698
1699
1700 void GLAPIENTRY
1701 _mesa_ClearBufferData(GLenum target, GLenum internalformat, GLenum format,
1702 GLenum type, const GLvoid* data)
1703 {
1704 GET_CURRENT_CONTEXT(ctx);
1705 struct gl_buffer_object* bufObj;
1706 mesa_format mesaFormat;
1707 GLubyte clearValue[MAX_PIXEL_BYTES];
1708 GLsizeiptr clearValueSize;
1709
1710 bufObj = get_buffer(ctx, "glClearBufferData", target, GL_INVALID_VALUE);
1711 if (!bufObj) {
1712 return;
1713 }
1714
1715 if (_mesa_check_disallowed_mapping(bufObj)) {
1716 _mesa_error(ctx, GL_INVALID_OPERATION,
1717 "glClearBufferData(buffer currently mapped)");
1718 return;
1719 }
1720
1721 mesaFormat = validate_clear_buffer_format(ctx, internalformat,
1722 format, type,
1723 "glClearBufferData");
1724 if (mesaFormat == MESA_FORMAT_NONE) {
1725 return;
1726 }
1727
1728 clearValueSize = _mesa_get_format_bytes(mesaFormat);
1729 if (bufObj->Size % clearValueSize != 0) {
1730 _mesa_error(ctx, GL_INVALID_VALUE,
1731 "glClearBufferData(size is not a multiple of "
1732 "internalformat size)");
1733 return;
1734 }
1735
1736 if (data == NULL) {
1737 /* clear to zeros, per the spec */
1738 ctx->Driver.ClearBufferSubData(ctx, 0, bufObj->Size,
1739 NULL, clearValueSize, bufObj);
1740 return;
1741 }
1742
1743 if (!convert_clear_buffer_data(ctx, mesaFormat, clearValue,
1744 format, type, data, "glClearBufferData")) {
1745 return;
1746 }
1747
1748 ctx->Driver.ClearBufferSubData(ctx, 0, bufObj->Size,
1749 clearValue, clearValueSize, bufObj);
1750 }
1751
1752
1753 void GLAPIENTRY
1754 _mesa_ClearBufferSubData(GLenum target, GLenum internalformat,
1755 GLintptr offset, GLsizeiptr size,
1756 GLenum format, GLenum type,
1757 const GLvoid* data)
1758 {
1759 GET_CURRENT_CONTEXT(ctx);
1760 struct gl_buffer_object* bufObj;
1761 mesa_format mesaFormat;
1762 GLubyte clearValue[MAX_PIXEL_BYTES];
1763 GLsizeiptr clearValueSize;
1764
1765 bufObj = get_buffer(ctx, "glClearBufferSubData", target, GL_INVALID_VALUE);
1766 if (!bufObj)
1767 return;
1768
1769 if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size,
1770 true, "glClearBufferSubData")) {
1771 return;
1772 }
1773
1774 mesaFormat = validate_clear_buffer_format(ctx, internalformat,
1775 format, type,
1776 "glClearBufferSubData");
1777 if (mesaFormat == MESA_FORMAT_NONE) {
1778 return;
1779 }
1780
1781 clearValueSize = _mesa_get_format_bytes(mesaFormat);
1782 if (offset % clearValueSize != 0 || size % clearValueSize != 0) {
1783 _mesa_error(ctx, GL_INVALID_VALUE,
1784 "glClearBufferSubData(offset or size is not a multiple of "
1785 "internalformat size)");
1786 return;
1787 }
1788
1789 if (data == NULL) {
1790 /* clear to zeros, per the spec */
1791 if (size > 0) {
1792 ctx->Driver.ClearBufferSubData(ctx, offset, size,
1793 NULL, clearValueSize, bufObj);
1794 }
1795 return;
1796 }
1797
1798 if (!convert_clear_buffer_data(ctx, mesaFormat, clearValue,
1799 format, type, data,
1800 "glClearBufferSubData")) {
1801 return;
1802 }
1803
1804 if (size > 0) {
1805 ctx->Driver.ClearBufferSubData(ctx, offset, size,
1806 clearValue, clearValueSize, bufObj);
1807 }
1808 }
1809
1810
1811 void * GLAPIENTRY
1812 _mesa_MapBuffer(GLenum target, GLenum access)
1813 {
1814 GET_CURRENT_CONTEXT(ctx);
1815 struct gl_buffer_object * bufObj;
1816 GLbitfield accessFlags;
1817 void *map;
1818 bool valid_access;
1819
1820 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
1821
1822 switch (access) {
1823 case GL_READ_ONLY_ARB:
1824 accessFlags = GL_MAP_READ_BIT;
1825 valid_access = _mesa_is_desktop_gl(ctx);
1826 break;
1827 case GL_WRITE_ONLY_ARB:
1828 accessFlags = GL_MAP_WRITE_BIT;
1829 valid_access = true;
1830 break;
1831 case GL_READ_WRITE_ARB:
1832 accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
1833 valid_access = _mesa_is_desktop_gl(ctx);
1834 break;
1835 default:
1836 valid_access = false;
1837 break;
1838 }
1839
1840 if (!valid_access) {
1841 _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)");
1842 return NULL;
1843 }
1844
1845 bufObj = get_buffer(ctx, "glMapBufferARB", target, GL_INVALID_OPERATION);
1846 if (!bufObj)
1847 return NULL;
1848
1849 if (accessFlags & GL_MAP_READ_BIT &&
1850 !(bufObj->StorageFlags & GL_MAP_READ_BIT)) {
1851 _mesa_error(ctx, GL_INVALID_OPERATION,
1852 "glMapBuffer(invalid read flag)");
1853 return NULL;
1854 }
1855
1856 if (accessFlags & GL_MAP_WRITE_BIT &&
1857 !(bufObj->StorageFlags & GL_MAP_WRITE_BIT)) {
1858 _mesa_error(ctx, GL_INVALID_OPERATION,
1859 "glMapBuffer(invalid write flag)");
1860 return NULL;
1861 }
1862
1863 if (_mesa_bufferobj_mapped(bufObj, MAP_USER)) {
1864 _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)");
1865 return NULL;
1866 }
1867
1868 if (!bufObj->Size) {
1869 _mesa_error(ctx, GL_OUT_OF_MEMORY,
1870 "glMapBuffer(buffer size = 0)");
1871 return NULL;
1872 }
1873
1874 assert(ctx->Driver.MapBufferRange);
1875 map = ctx->Driver.MapBufferRange(ctx, 0, bufObj->Size, accessFlags, bufObj,
1876 MAP_USER);
1877 if (!map) {
1878 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
1879 return NULL;
1880 }
1881 else {
1882 /* The driver callback should have set these fields.
1883 * This is important because other modules (like VBO) might call
1884 * the driver function directly.
1885 */
1886 assert(bufObj->Mappings[MAP_USER].Pointer == map);
1887 assert(bufObj->Mappings[MAP_USER].Length == bufObj->Size);
1888 assert(bufObj->Mappings[MAP_USER].Offset == 0);
1889 bufObj->Mappings[MAP_USER].AccessFlags = accessFlags;
1890 }
1891
1892 if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB)
1893 bufObj->Written = GL_TRUE;
1894
1895 #ifdef VBO_DEBUG
1896 printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n",
1897 bufObj->Name, bufObj->Size, access);
1898 if (access == GL_WRITE_ONLY_ARB) {
1899 GLuint i;
1900 GLubyte *b = (GLubyte *) bufObj->Pointer;
1901 for (i = 0; i < bufObj->Size; i++)
1902 b[i] = i & 0xff;
1903 }
1904 #endif
1905
1906 #ifdef BOUNDS_CHECK
1907 {
1908 GLubyte *buf = (GLubyte *) bufObj->Pointer;
1909 GLuint i;
1910 /* buffer is 100 bytes larger than requested, fill with magic value */
1911 for (i = 0; i < 100; i++) {
1912 buf[bufObj->Size - i - 1] = 123;
1913 }
1914 }
1915 #endif
1916
1917 return bufObj->Mappings[MAP_USER].Pointer;
1918 }
1919
1920
1921 GLboolean GLAPIENTRY
1922 _mesa_UnmapBuffer(GLenum target)
1923 {
1924 GET_CURRENT_CONTEXT(ctx);
1925 struct gl_buffer_object *bufObj;
1926 GLboolean status = GL_TRUE;
1927 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1928
1929 bufObj = get_buffer(ctx, "glUnmapBufferARB", target, GL_INVALID_OPERATION);
1930 if (!bufObj)
1931 return GL_FALSE;
1932
1933 if (!_mesa_bufferobj_mapped(bufObj, MAP_USER)) {
1934 _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB");
1935 return GL_FALSE;
1936 }
1937
1938 #ifdef BOUNDS_CHECK
1939 if (bufObj->Access != GL_READ_ONLY_ARB) {
1940 GLubyte *buf = (GLubyte *) bufObj->Pointer;
1941 GLuint i;
1942 /* check that last 100 bytes are still = magic value */
1943 for (i = 0; i < 100; i++) {
1944 GLuint pos = bufObj->Size - i - 1;
1945 if (buf[pos] != 123) {
1946 _mesa_warning(ctx, "Out of bounds buffer object write detected"
1947 " at position %d (value = %u)\n",
1948 pos, buf[pos]);
1949 }
1950 }
1951 }
1952 #endif
1953
1954 #ifdef VBO_DEBUG
1955 if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) {
1956 GLuint i, unchanged = 0;
1957 GLubyte *b = (GLubyte *) bufObj->Pointer;
1958 GLint pos = -1;
1959 /* check which bytes changed */
1960 for (i = 0; i < bufObj->Size - 1; i++) {
1961 if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) {
1962 unchanged++;
1963 if (pos == -1)
1964 pos = i;
1965 }
1966 }
1967 if (unchanged) {
1968 printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n",
1969 bufObj->Name, unchanged, bufObj->Size, pos);
1970 }
1971 }
1972 #endif
1973
1974 status = ctx->Driver.UnmapBuffer(ctx, bufObj, MAP_USER);
1975 bufObj->Mappings[MAP_USER].AccessFlags = 0;
1976 assert(bufObj->Mappings[MAP_USER].Pointer == NULL);
1977 assert(bufObj->Mappings[MAP_USER].Offset == 0);
1978 assert(bufObj->Mappings[MAP_USER].Length == 0);
1979
1980 return status;
1981 }
1982
1983
1984 void GLAPIENTRY
1985 _mesa_GetBufferParameteriv(GLenum target, GLenum pname, GLint *params)
1986 {
1987 GET_CURRENT_CONTEXT(ctx);
1988 struct gl_buffer_object *bufObj;
1989
1990 bufObj = get_buffer(ctx, "glGetBufferParameterivARB", target,
1991 GL_INVALID_OPERATION);
1992 if (!bufObj)
1993 return;
1994
1995 switch (pname) {
1996 case GL_BUFFER_SIZE_ARB:
1997 *params = (GLint) bufObj->Size;
1998 return;
1999 case GL_BUFFER_USAGE_ARB:
2000 *params = bufObj->Usage;
2001 return;
2002 case GL_BUFFER_ACCESS_ARB:
2003 *params = simplified_access_mode(ctx,
2004 bufObj->Mappings[MAP_USER].AccessFlags);
2005 return;
2006 case GL_BUFFER_MAPPED_ARB:
2007 *params = _mesa_bufferobj_mapped(bufObj, MAP_USER);
2008 return;
2009 case GL_BUFFER_ACCESS_FLAGS:
2010 if (!ctx->Extensions.ARB_map_buffer_range)
2011 goto invalid_pname;
2012 *params = bufObj->Mappings[MAP_USER].AccessFlags;
2013 return;
2014 case GL_BUFFER_MAP_OFFSET:
2015 if (!ctx->Extensions.ARB_map_buffer_range)
2016 goto invalid_pname;
2017 *params = (GLint) bufObj->Mappings[MAP_USER].Offset;
2018 return;
2019 case GL_BUFFER_MAP_LENGTH:
2020 if (!ctx->Extensions.ARB_map_buffer_range)
2021 goto invalid_pname;
2022 *params = (GLint) bufObj->Mappings[MAP_USER].Length;
2023 return;
2024 case GL_BUFFER_IMMUTABLE_STORAGE:
2025 if (!ctx->Extensions.ARB_buffer_storage)
2026 goto invalid_pname;
2027 *params = bufObj->Immutable;
2028 return;
2029 case GL_BUFFER_STORAGE_FLAGS:
2030 if (!ctx->Extensions.ARB_buffer_storage)
2031 goto invalid_pname;
2032 *params = bufObj->StorageFlags;
2033 return;
2034 default:
2035 ; /* fall-through */
2036 }
2037
2038 invalid_pname:
2039 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname=%s)",
2040 _mesa_lookup_enum_by_nr(pname));
2041 }
2042
2043
2044 /**
2045 * New in GL 3.2
2046 * This is pretty much a duplicate of GetBufferParameteriv() but the
2047 * GL_BUFFER_SIZE_ARB attribute will be 64-bits on a 64-bit system.
2048 */
2049 void GLAPIENTRY
2050 _mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params)
2051 {
2052 GET_CURRENT_CONTEXT(ctx);
2053 struct gl_buffer_object *bufObj;
2054
2055 bufObj = get_buffer(ctx, "glGetBufferParameteri64v", target,
2056 GL_INVALID_OPERATION);
2057 if (!bufObj)
2058 return;
2059
2060 switch (pname) {
2061 case GL_BUFFER_SIZE_ARB:
2062 *params = bufObj->Size;
2063 return;
2064 case GL_BUFFER_USAGE_ARB:
2065 *params = bufObj->Usage;
2066 return;
2067 case GL_BUFFER_ACCESS_ARB:
2068 *params = simplified_access_mode(ctx,
2069 bufObj->Mappings[MAP_USER].AccessFlags);
2070 return;
2071 case GL_BUFFER_ACCESS_FLAGS:
2072 if (!ctx->Extensions.ARB_map_buffer_range)
2073 goto invalid_pname;
2074 *params = bufObj->Mappings[MAP_USER].AccessFlags;
2075 return;
2076 case GL_BUFFER_MAPPED_ARB:
2077 *params = _mesa_bufferobj_mapped(bufObj, MAP_USER);
2078 return;
2079 case GL_BUFFER_MAP_OFFSET:
2080 if (!ctx->Extensions.ARB_map_buffer_range)
2081 goto invalid_pname;
2082 *params = bufObj->Mappings[MAP_USER].Offset;
2083 return;
2084 case GL_BUFFER_MAP_LENGTH:
2085 if (!ctx->Extensions.ARB_map_buffer_range)
2086 goto invalid_pname;
2087 *params = bufObj->Mappings[MAP_USER].Length;
2088 return;
2089 case GL_BUFFER_IMMUTABLE_STORAGE:
2090 if (!ctx->Extensions.ARB_buffer_storage)
2091 goto invalid_pname;
2092 *params = bufObj->Immutable;
2093 return;
2094 case GL_BUFFER_STORAGE_FLAGS:
2095 if (!ctx->Extensions.ARB_buffer_storage)
2096 goto invalid_pname;
2097 *params = bufObj->StorageFlags;
2098 return;
2099 default:
2100 ; /* fall-through */
2101 }
2102
2103 invalid_pname:
2104 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(pname=%s)",
2105 _mesa_lookup_enum_by_nr(pname));
2106 }
2107
2108
2109 void GLAPIENTRY
2110 _mesa_GetBufferPointerv(GLenum target, GLenum pname, GLvoid **params)
2111 {
2112 GET_CURRENT_CONTEXT(ctx);
2113 struct gl_buffer_object * bufObj;
2114
2115 if (pname != GL_BUFFER_MAP_POINTER_ARB) {
2116 _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)");
2117 return;
2118 }
2119
2120 bufObj = get_buffer(ctx, "glGetBufferPointervARB", target,
2121 GL_INVALID_OPERATION);
2122 if (!bufObj)
2123 return;
2124
2125 *params = bufObj->Mappings[MAP_USER].Pointer;
2126 }
2127
2128
2129 void GLAPIENTRY
2130 _mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
2131 GLintptr readOffset, GLintptr writeOffset,
2132 GLsizeiptr size)
2133 {
2134 GET_CURRENT_CONTEXT(ctx);
2135 struct gl_buffer_object *src, *dst;
2136
2137 src = get_buffer(ctx, "glCopyBufferSubData", readTarget,
2138 GL_INVALID_OPERATION);
2139 if (!src)
2140 return;
2141
2142 dst = get_buffer(ctx, "glCopyBufferSubData", writeTarget,
2143 GL_INVALID_OPERATION);
2144 if (!dst)
2145 return;
2146
2147 if (_mesa_check_disallowed_mapping(src)) {
2148 _mesa_error(ctx, GL_INVALID_OPERATION,
2149 "glCopyBufferSubData(readBuffer is mapped)");
2150 return;
2151 }
2152
2153 if (_mesa_check_disallowed_mapping(dst)) {
2154 _mesa_error(ctx, GL_INVALID_OPERATION,
2155 "glCopyBufferSubData(writeBuffer is mapped)");
2156 return;
2157 }
2158
2159 if (readOffset < 0) {
2160 _mesa_error(ctx, GL_INVALID_VALUE,
2161 "glCopyBufferSubData(readOffset = %d)", (int) readOffset);
2162 return;
2163 }
2164
2165 if (writeOffset < 0) {
2166 _mesa_error(ctx, GL_INVALID_VALUE,
2167 "glCopyBufferSubData(writeOffset = %d)", (int) writeOffset);
2168 return;
2169 }
2170
2171 if (size < 0) {
2172 _mesa_error(ctx, GL_INVALID_VALUE,
2173 "glCopyBufferSubData(writeOffset = %d)", (int) size);
2174 return;
2175 }
2176
2177 if (readOffset + size > src->Size) {
2178 _mesa_error(ctx, GL_INVALID_VALUE,
2179 "glCopyBufferSubData(readOffset + size = %d)",
2180 (int) (readOffset + size));
2181 return;
2182 }
2183
2184 if (writeOffset + size > dst->Size) {
2185 _mesa_error(ctx, GL_INVALID_VALUE,
2186 "glCopyBufferSubData(writeOffset + size = %d)",
2187 (int) (writeOffset + size));
2188 return;
2189 }
2190
2191 if (src == dst) {
2192 if (readOffset + size <= writeOffset) {
2193 /* OK */
2194 }
2195 else if (writeOffset + size <= readOffset) {
2196 /* OK */
2197 }
2198 else {
2199 /* overlapping src/dst is illegal */
2200 _mesa_error(ctx, GL_INVALID_VALUE,
2201 "glCopyBufferSubData(overlapping src/dst)");
2202 return;
2203 }
2204 }
2205
2206 ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size);
2207 }
2208
2209
2210 /**
2211 * See GL_ARB_map_buffer_range spec
2212 */
2213 void * GLAPIENTRY
2214 _mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
2215 GLbitfield access)
2216 {
2217 GET_CURRENT_CONTEXT(ctx);
2218 struct gl_buffer_object *bufObj;
2219 void *map;
2220 GLbitfield allowed_access;
2221
2222 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL);
2223
2224 if (!ctx->Extensions.ARB_map_buffer_range) {
2225 _mesa_error(ctx, GL_INVALID_OPERATION,
2226 "glMapBufferRange(extension not supported)");
2227 return NULL;
2228 }
2229
2230 if (offset < 0) {
2231 _mesa_error(ctx, GL_INVALID_VALUE,
2232 "glMapBufferRange(offset = %ld)", (long)offset);
2233 return NULL;
2234 }
2235
2236 if (length < 0) {
2237 _mesa_error(ctx, GL_INVALID_VALUE,
2238 "glMapBufferRange(length = %ld)", (long)length);
2239 return NULL;
2240 }
2241
2242 /* Page 38 of the PDF of the OpenGL ES 3.0 spec says:
2243 *
2244 * "An INVALID_OPERATION error is generated for any of the following
2245 * conditions:
2246 *
2247 * * <length> is zero."
2248 */
2249 if (_mesa_is_gles(ctx) && length == 0) {
2250 _mesa_error(ctx, GL_INVALID_OPERATION,
2251 "glMapBufferRange(length = 0)");
2252 return NULL;
2253 }
2254
2255 allowed_access = GL_MAP_READ_BIT |
2256 GL_MAP_WRITE_BIT |
2257 GL_MAP_INVALIDATE_RANGE_BIT |
2258 GL_MAP_INVALIDATE_BUFFER_BIT |
2259 GL_MAP_FLUSH_EXPLICIT_BIT |
2260 GL_MAP_UNSYNCHRONIZED_BIT;
2261
2262 if (ctx->Extensions.ARB_buffer_storage) {
2263 allowed_access |= GL_MAP_PERSISTENT_BIT |
2264 GL_MAP_COHERENT_BIT;
2265 }
2266
2267 if (access & ~allowed_access) {
2268 /* generate an error if any other than allowed bit is set */
2269 _mesa_error(ctx, GL_INVALID_VALUE, "glMapBufferRange(access)");
2270 return NULL;
2271 }
2272
2273 if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) {
2274 _mesa_error(ctx, GL_INVALID_OPERATION,
2275 "glMapBufferRange(access indicates neither read or write)");
2276 return NULL;
2277 }
2278
2279 if ((access & GL_MAP_READ_BIT) &&
2280 (access & (GL_MAP_INVALIDATE_RANGE_BIT |
2281 GL_MAP_INVALIDATE_BUFFER_BIT |
2282 GL_MAP_UNSYNCHRONIZED_BIT))) {
2283 _mesa_error(ctx, GL_INVALID_OPERATION,
2284 "glMapBufferRange(invalid access flags)");
2285 return NULL;
2286 }
2287
2288 if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) &&
2289 ((access & GL_MAP_WRITE_BIT) == 0)) {
2290 _mesa_error(ctx, GL_INVALID_OPERATION,
2291 "glMapBufferRange(invalid access flags)");
2292 return NULL;
2293 }
2294
2295 bufObj = get_buffer(ctx, "glMapBufferRange", target, GL_INVALID_OPERATION);
2296 if (!bufObj)
2297 return NULL;
2298
2299 if (access & GL_MAP_READ_BIT &&
2300 !(bufObj->StorageFlags & GL_MAP_READ_BIT)) {
2301 _mesa_error(ctx, GL_INVALID_OPERATION,
2302 "glMapBufferRange(invalid read flag)");
2303 return NULL;
2304 }
2305
2306 if (access & GL_MAP_WRITE_BIT &&
2307 !(bufObj->StorageFlags & GL_MAP_WRITE_BIT)) {
2308 _mesa_error(ctx, GL_INVALID_OPERATION,
2309 "glMapBufferRange(invalid write flag)");
2310 return NULL;
2311 }
2312
2313 if (access & GL_MAP_COHERENT_BIT &&
2314 !(bufObj->StorageFlags & GL_MAP_COHERENT_BIT)) {
2315 _mesa_error(ctx, GL_INVALID_OPERATION,
2316 "glMapBufferRange(invalid coherent flag)");
2317 return NULL;
2318 }
2319
2320 if (access & GL_MAP_PERSISTENT_BIT &&
2321 !(bufObj->StorageFlags & GL_MAP_PERSISTENT_BIT)) {
2322 _mesa_error(ctx, GL_INVALID_OPERATION,
2323 "glMapBufferRange(invalid persistent flag)");
2324 return NULL;
2325 }
2326
2327 if (offset + length > bufObj->Size) {
2328 _mesa_error(ctx, GL_INVALID_VALUE,
2329 "glMapBufferRange(offset + length > size)");
2330 return NULL;
2331 }
2332
2333 if (_mesa_bufferobj_mapped(bufObj, MAP_USER)) {
2334 _mesa_error(ctx, GL_INVALID_OPERATION,
2335 "glMapBufferRange(buffer already mapped)");
2336 return NULL;
2337 }
2338
2339 if (!bufObj->Size) {
2340 _mesa_error(ctx, GL_OUT_OF_MEMORY,
2341 "glMapBufferRange(buffer size = 0)");
2342 return NULL;
2343 }
2344
2345 /* Mapping zero bytes should return a non-null pointer. */
2346 if (!length) {
2347 static long dummy = 0;
2348 bufObj->Mappings[MAP_USER].Pointer = &dummy;
2349 bufObj->Mappings[MAP_USER].Length = length;
2350 bufObj->Mappings[MAP_USER].Offset = offset;
2351 bufObj->Mappings[MAP_USER].AccessFlags = access;
2352 return bufObj->Mappings[MAP_USER].Pointer;
2353 }
2354
2355 assert(ctx->Driver.MapBufferRange);
2356 map = ctx->Driver.MapBufferRange(ctx, offset, length, access, bufObj,
2357 MAP_USER);
2358 if (!map) {
2359 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)");
2360 }
2361 else {
2362 /* The driver callback should have set all these fields.
2363 * This is important because other modules (like VBO) might call
2364 * the driver function directly.
2365 */
2366 assert(bufObj->Mappings[MAP_USER].Pointer == map);
2367 assert(bufObj->Mappings[MAP_USER].Length == length);
2368 assert(bufObj->Mappings[MAP_USER].Offset == offset);
2369 assert(bufObj->Mappings[MAP_USER].AccessFlags == access);
2370 }
2371
2372 return map;
2373 }
2374
2375
2376 /**
2377 * See GL_ARB_map_buffer_range spec
2378 */
2379 void GLAPIENTRY
2380 _mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
2381 {
2382 GET_CURRENT_CONTEXT(ctx);
2383 struct gl_buffer_object *bufObj;
2384
2385 if (!ctx->Extensions.ARB_map_buffer_range) {
2386 _mesa_error(ctx, GL_INVALID_OPERATION,
2387 "glFlushMappedBufferRange(extension not supported)");
2388 return;
2389 }
2390
2391 if (offset < 0) {
2392 _mesa_error(ctx, GL_INVALID_VALUE,
2393 "glFlushMappedBufferRange(offset = %ld)", (long)offset);
2394 return;
2395 }
2396
2397 if (length < 0) {
2398 _mesa_error(ctx, GL_INVALID_VALUE,
2399 "glFlushMappedBufferRange(length = %ld)", (long)length);
2400 return;
2401 }
2402
2403 bufObj = get_buffer(ctx, "glFlushMappedBufferRange", target,
2404 GL_INVALID_OPERATION);
2405 if (!bufObj)
2406 return;
2407
2408 if (!_mesa_bufferobj_mapped(bufObj, MAP_USER)) {
2409 /* buffer is not mapped */
2410 _mesa_error(ctx, GL_INVALID_OPERATION,
2411 "glFlushMappedBufferRange(buffer is not mapped)");
2412 return;
2413 }
2414
2415 if ((bufObj->Mappings[MAP_USER].AccessFlags &
2416 GL_MAP_FLUSH_EXPLICIT_BIT) == 0) {
2417 _mesa_error(ctx, GL_INVALID_OPERATION,
2418 "glFlushMappedBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)");
2419 return;
2420 }
2421
2422 if (offset + length > bufObj->Mappings[MAP_USER].Length) {
2423 _mesa_error(ctx, GL_INVALID_VALUE,
2424 "glFlushMappedBufferRange(offset %ld + length %ld > mapped length %ld)",
2425 (long)offset, (long)length,
2426 (long)bufObj->Mappings[MAP_USER].Length);
2427 return;
2428 }
2429
2430 assert(bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_WRITE_BIT);
2431
2432 if (ctx->Driver.FlushMappedBufferRange)
2433 ctx->Driver.FlushMappedBufferRange(ctx, offset, length, bufObj,
2434 MAP_USER);
2435 }
2436
2437
2438 static GLenum
2439 buffer_object_purgeable(struct gl_context *ctx, GLuint name, GLenum option)
2440 {
2441 struct gl_buffer_object *bufObj;
2442 GLenum retval;
2443
2444 bufObj = _mesa_lookup_bufferobj(ctx, name);
2445 if (!bufObj) {
2446 _mesa_error(ctx, GL_INVALID_VALUE,
2447 "glObjectPurgeable(name = 0x%x)", name);
2448 return 0;
2449 }
2450 if (!_mesa_is_bufferobj(bufObj)) {
2451 _mesa_error(ctx, GL_INVALID_OPERATION, "glObjectPurgeable(buffer 0)" );
2452 return 0;
2453 }
2454
2455 if (bufObj->Purgeable) {
2456 _mesa_error(ctx, GL_INVALID_OPERATION,
2457 "glObjectPurgeable(name = 0x%x) is already purgeable", name);
2458 return GL_VOLATILE_APPLE;
2459 }
2460
2461 bufObj->Purgeable = GL_TRUE;
2462
2463 retval = GL_VOLATILE_APPLE;
2464 if (ctx->Driver.BufferObjectPurgeable)
2465 retval = ctx->Driver.BufferObjectPurgeable(ctx, bufObj, option);
2466
2467 return retval;
2468 }
2469
2470
2471 static GLenum
2472 renderbuffer_purgeable(struct gl_context *ctx, GLuint name, GLenum option)
2473 {
2474 struct gl_renderbuffer *bufObj;
2475 GLenum retval;
2476
2477 bufObj = _mesa_lookup_renderbuffer(ctx, name);
2478 if (!bufObj) {
2479 _mesa_error(ctx, GL_INVALID_VALUE,
2480 "glObjectUnpurgeable(name = 0x%x)", name);
2481 return 0;
2482 }
2483
2484 if (bufObj->Purgeable) {
2485 _mesa_error(ctx, GL_INVALID_OPERATION,
2486 "glObjectPurgeable(name = 0x%x) is already purgeable", name);
2487 return GL_VOLATILE_APPLE;
2488 }
2489
2490 bufObj->Purgeable = GL_TRUE;
2491
2492 retval = GL_VOLATILE_APPLE;
2493 if (ctx->Driver.RenderObjectPurgeable)
2494 retval = ctx->Driver.RenderObjectPurgeable(ctx, bufObj, option);
2495
2496 return retval;
2497 }
2498
2499
2500 static GLenum
2501 texture_object_purgeable(struct gl_context *ctx, GLuint name, GLenum option)
2502 {
2503 struct gl_texture_object *bufObj;
2504 GLenum retval;
2505
2506 bufObj = _mesa_lookup_texture(ctx, name);
2507 if (!bufObj) {
2508 _mesa_error(ctx, GL_INVALID_VALUE,
2509 "glObjectPurgeable(name = 0x%x)", name);
2510 return 0;
2511 }
2512
2513 if (bufObj->Purgeable) {
2514 _mesa_error(ctx, GL_INVALID_OPERATION,
2515 "glObjectPurgeable(name = 0x%x) is already purgeable", name);
2516 return GL_VOLATILE_APPLE;
2517 }
2518
2519 bufObj->Purgeable = GL_TRUE;
2520
2521 retval = GL_VOLATILE_APPLE;
2522 if (ctx->Driver.TextureObjectPurgeable)
2523 retval = ctx->Driver.TextureObjectPurgeable(ctx, bufObj, option);
2524
2525 return retval;
2526 }
2527
2528
2529 GLenum GLAPIENTRY
2530 _mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option)
2531 {
2532 GLenum retval;
2533
2534 GET_CURRENT_CONTEXT(ctx);
2535 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
2536
2537 if (name == 0) {
2538 _mesa_error(ctx, GL_INVALID_VALUE,
2539 "glObjectPurgeable(name = 0x%x)", name);
2540 return 0;
2541 }
2542
2543 switch (option) {
2544 case GL_VOLATILE_APPLE:
2545 case GL_RELEASED_APPLE:
2546 /* legal */
2547 break;
2548 default:
2549 _mesa_error(ctx, GL_INVALID_ENUM,
2550 "glObjectPurgeable(name = 0x%x) invalid option: %d",
2551 name, option);
2552 return 0;
2553 }
2554
2555 switch (objectType) {
2556 case GL_TEXTURE:
2557 retval = texture_object_purgeable(ctx, name, option);
2558 break;
2559 case GL_RENDERBUFFER_EXT:
2560 retval = renderbuffer_purgeable(ctx, name, option);
2561 break;
2562 case GL_BUFFER_OBJECT_APPLE:
2563 retval = buffer_object_purgeable(ctx, name, option);
2564 break;
2565 default:
2566 _mesa_error(ctx, GL_INVALID_ENUM,
2567 "glObjectPurgeable(name = 0x%x) invalid type: %d",
2568 name, objectType);
2569 return 0;
2570 }
2571
2572 /* In strict conformance to the spec, we must only return VOLATILE when
2573 * when passed the VOLATILE option. Madness.
2574 *
2575 * XXX First fix the spec, then fix me.
2576 */
2577 return option == GL_VOLATILE_APPLE ? GL_VOLATILE_APPLE : retval;
2578 }
2579
2580
2581 static GLenum
2582 buffer_object_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
2583 {
2584 struct gl_buffer_object *bufObj;
2585 GLenum retval;
2586
2587 bufObj = _mesa_lookup_bufferobj(ctx, name);
2588 if (!bufObj) {
2589 _mesa_error(ctx, GL_INVALID_VALUE,
2590 "glObjectUnpurgeable(name = 0x%x)", name);
2591 return 0;
2592 }
2593
2594 if (! bufObj->Purgeable) {
2595 _mesa_error(ctx, GL_INVALID_OPERATION,
2596 "glObjectUnpurgeable(name = 0x%x) object is "
2597 " already \"unpurged\"", name);
2598 return 0;
2599 }
2600
2601 bufObj->Purgeable = GL_FALSE;
2602
2603 retval = option;
2604 if (ctx->Driver.BufferObjectUnpurgeable)
2605 retval = ctx->Driver.BufferObjectUnpurgeable(ctx, bufObj, option);
2606
2607 return retval;
2608 }
2609
2610
2611 static GLenum
2612 renderbuffer_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
2613 {
2614 struct gl_renderbuffer *bufObj;
2615 GLenum retval;
2616
2617 bufObj = _mesa_lookup_renderbuffer(ctx, name);
2618 if (!bufObj) {
2619 _mesa_error(ctx, GL_INVALID_VALUE,
2620 "glObjectUnpurgeable(name = 0x%x)", name);
2621 return 0;
2622 }
2623
2624 if (! bufObj->Purgeable) {
2625 _mesa_error(ctx, GL_INVALID_OPERATION,
2626 "glObjectUnpurgeable(name = 0x%x) object is "
2627 " already \"unpurged\"", name);
2628 return 0;
2629 }
2630
2631 bufObj->Purgeable = GL_FALSE;
2632
2633 retval = option;
2634 if (ctx->Driver.RenderObjectUnpurgeable)
2635 retval = ctx->Driver.RenderObjectUnpurgeable(ctx, bufObj, option);
2636
2637 return retval;
2638 }
2639
2640
2641 static GLenum
2642 texture_object_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
2643 {
2644 struct gl_texture_object *bufObj;
2645 GLenum retval;
2646
2647 bufObj = _mesa_lookup_texture(ctx, name);
2648 if (!bufObj) {
2649 _mesa_error(ctx, GL_INVALID_VALUE,
2650 "glObjectUnpurgeable(name = 0x%x)", name);
2651 return 0;
2652 }
2653
2654 if (! bufObj->Purgeable) {
2655 _mesa_error(ctx, GL_INVALID_OPERATION,
2656 "glObjectUnpurgeable(name = 0x%x) object is"
2657 " already \"unpurged\"", name);
2658 return 0;
2659 }
2660
2661 bufObj->Purgeable = GL_FALSE;
2662
2663 retval = option;
2664 if (ctx->Driver.TextureObjectUnpurgeable)
2665 retval = ctx->Driver.TextureObjectUnpurgeable(ctx, bufObj, option);
2666
2667 return retval;
2668 }
2669
2670
2671 GLenum GLAPIENTRY
2672 _mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option)
2673 {
2674 GET_CURRENT_CONTEXT(ctx);
2675 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
2676
2677 if (name == 0) {
2678 _mesa_error(ctx, GL_INVALID_VALUE,
2679 "glObjectUnpurgeable(name = 0x%x)", name);
2680 return 0;
2681 }
2682
2683 switch (option) {
2684 case GL_RETAINED_APPLE:
2685 case GL_UNDEFINED_APPLE:
2686 /* legal */
2687 break;
2688 default:
2689 _mesa_error(ctx, GL_INVALID_ENUM,
2690 "glObjectUnpurgeable(name = 0x%x) invalid option: %d",
2691 name, option);
2692 return 0;
2693 }
2694
2695 switch (objectType) {
2696 case GL_BUFFER_OBJECT_APPLE:
2697 return buffer_object_unpurgeable(ctx, name, option);
2698 case GL_TEXTURE:
2699 return texture_object_unpurgeable(ctx, name, option);
2700 case GL_RENDERBUFFER_EXT:
2701 return renderbuffer_unpurgeable(ctx, name, option);
2702 default:
2703 _mesa_error(ctx, GL_INVALID_ENUM,
2704 "glObjectUnpurgeable(name = 0x%x) invalid type: %d",
2705 name, objectType);
2706 return 0;
2707 }
2708 }
2709
2710
2711 static void
2712 get_buffer_object_parameteriv(struct gl_context *ctx, GLuint name,
2713 GLenum pname, GLint *params)
2714 {
2715 struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, name);
2716 if (!bufObj) {
2717 _mesa_error(ctx, GL_INVALID_VALUE,
2718 "glGetObjectParameteriv(name = 0x%x) invalid object", name);
2719 return;
2720 }
2721
2722 switch (pname) {
2723 case GL_PURGEABLE_APPLE:
2724 *params = bufObj->Purgeable;
2725 break;
2726 default:
2727 _mesa_error(ctx, GL_INVALID_ENUM,
2728 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
2729 name, pname);
2730 break;
2731 }
2732 }
2733
2734
2735 static void
2736 get_renderbuffer_parameteriv(struct gl_context *ctx, GLuint name,
2737 GLenum pname, GLint *params)
2738 {
2739 struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name);
2740 if (!rb) {
2741 _mesa_error(ctx, GL_INVALID_VALUE,
2742 "glObjectUnpurgeable(name = 0x%x)", name);
2743 return;
2744 }
2745
2746 switch (pname) {
2747 case GL_PURGEABLE_APPLE:
2748 *params = rb->Purgeable;
2749 break;
2750 default:
2751 _mesa_error(ctx, GL_INVALID_ENUM,
2752 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
2753 name, pname);
2754 break;
2755 }
2756 }
2757
2758
2759 static void
2760 get_texture_object_parameteriv(struct gl_context *ctx, GLuint name,
2761 GLenum pname, GLint *params)
2762 {
2763 struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name);
2764 if (!texObj) {
2765 _mesa_error(ctx, GL_INVALID_VALUE,
2766 "glObjectUnpurgeable(name = 0x%x)", name);
2767 return;
2768 }
2769
2770 switch (pname) {
2771 case GL_PURGEABLE_APPLE:
2772 *params = texObj->Purgeable;
2773 break;
2774 default:
2775 _mesa_error(ctx, GL_INVALID_ENUM,
2776 "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
2777 name, pname);
2778 break;
2779 }
2780 }
2781
2782
2783 void GLAPIENTRY
2784 _mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname,
2785 GLint *params)
2786 {
2787 GET_CURRENT_CONTEXT(ctx);
2788
2789 if (name == 0) {
2790 _mesa_error(ctx, GL_INVALID_VALUE,
2791 "glGetObjectParameteriv(name = 0x%x)", name);
2792 return;
2793 }
2794
2795 switch (objectType) {
2796 case GL_TEXTURE:
2797 get_texture_object_parameteriv(ctx, name, pname, params);
2798 break;
2799 case GL_BUFFER_OBJECT_APPLE:
2800 get_buffer_object_parameteriv(ctx, name, pname, params);
2801 break;
2802 case GL_RENDERBUFFER_EXT:
2803 get_renderbuffer_parameteriv(ctx, name, pname, params);
2804 break;
2805 default:
2806 _mesa_error(ctx, GL_INVALID_ENUM,
2807 "glGetObjectParameteriv(name = 0x%x) invalid type: %d",
2808 name, objectType);
2809 }
2810 }
2811
2812 /**
2813 * Binds a buffer object to a uniform buffer binding point.
2814 *
2815 * The caller is responsible for flushing vertices and updating
2816 * NewDriverState.
2817 */
2818 static void
2819 set_ubo_binding(struct gl_context *ctx,
2820 struct gl_uniform_buffer_binding *binding,
2821 struct gl_buffer_object *bufObj,
2822 GLintptr offset,
2823 GLsizeiptr size,
2824 GLboolean autoSize)
2825 {
2826 _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj);
2827
2828 binding->Offset = offset;
2829 binding->Size = size;
2830 binding->AutomaticSize = autoSize;
2831
2832 /* If this is a real buffer object, mark it has having been used
2833 * at some point as a UBO.
2834 */
2835 if (size >= 0)
2836 bufObj->UsageHistory |= USAGE_UNIFORM_BUFFER;
2837 }
2838
2839 /**
2840 * Binds a buffer object to a uniform buffer binding point.
2841 *
2842 * Unlike set_ubo_binding(), this function also flushes vertices
2843 * and updates NewDriverState. It also checks if the binding
2844 * has actually changed before updating it.
2845 */
2846 static void
2847 bind_uniform_buffer(struct gl_context *ctx,
2848 GLuint index,
2849 struct gl_buffer_object *bufObj,
2850 GLintptr offset,
2851 GLsizeiptr size,
2852 GLboolean autoSize)
2853 {
2854 struct gl_uniform_buffer_binding *binding =
2855 &ctx->UniformBufferBindings[index];
2856
2857 if (binding->BufferObject == bufObj &&
2858 binding->Offset == offset &&
2859 binding->Size == size &&
2860 binding->AutomaticSize == autoSize) {
2861 return;
2862 }
2863
2864 FLUSH_VERTICES(ctx, 0);
2865 ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer;
2866
2867 set_ubo_binding(ctx, binding, bufObj, offset, size, autoSize);
2868 }
2869
2870 /**
2871 * Bind a region of a buffer object to a uniform block binding point.
2872 * \param index the uniform buffer binding point index
2873 * \param bufObj the buffer object
2874 * \param offset offset to the start of buffer object region
2875 * \param size size of the buffer object region
2876 */
2877 static void
2878 bind_buffer_range_uniform_buffer(struct gl_context *ctx,
2879 GLuint index,
2880 struct gl_buffer_object *bufObj,
2881 GLintptr offset,
2882 GLsizeiptr size)
2883 {
2884 if (index >= ctx->Const.MaxUniformBufferBindings) {
2885 _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index);
2886 return;
2887 }
2888
2889 if (offset & (ctx->Const.UniformBufferOffsetAlignment - 1)) {
2890 _mesa_error(ctx, GL_INVALID_VALUE,
2891 "glBindBufferRange(offset misaligned %d/%d)", (int) offset,
2892 ctx->Const.UniformBufferOffsetAlignment);
2893 return;
2894 }
2895
2896 if (bufObj == ctx->Shared->NullBufferObj) {
2897 offset = -1;
2898 size = -1;
2899 }
2900
2901 _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj);
2902 bind_uniform_buffer(ctx, index, bufObj, offset, size, GL_FALSE);
2903 }
2904
2905
2906 /**
2907 * Bind a buffer object to a uniform block binding point.
2908 * As above, but offset = 0.
2909 */
2910 static void
2911 bind_buffer_base_uniform_buffer(struct gl_context *ctx,
2912 GLuint index,
2913 struct gl_buffer_object *bufObj)
2914 {
2915 if (index >= ctx->Const.MaxUniformBufferBindings) {
2916 _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index);
2917 return;
2918 }
2919
2920 _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj);
2921
2922 if (bufObj == ctx->Shared->NullBufferObj)
2923 bind_uniform_buffer(ctx, index, bufObj, -1, -1, GL_TRUE);
2924 else
2925 bind_uniform_buffer(ctx, index, bufObj, 0, 0, GL_TRUE);
2926 }
2927
2928 /**
2929 * Binds a buffer object to an atomic buffer binding point.
2930 *
2931 * The caller is responsible for validating the offset,
2932 * flushing the vertices and updating NewDriverState.
2933 */
2934 static void
2935 set_atomic_buffer_binding(struct gl_context *ctx,
2936 struct gl_atomic_buffer_binding *binding,
2937 struct gl_buffer_object *bufObj,
2938 GLintptr offset,
2939 GLsizeiptr size)
2940 {
2941 _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj);
2942
2943 if (bufObj == ctx->Shared->NullBufferObj) {
2944 binding->Offset = -1;
2945 binding->Size = -1;
2946 } else {
2947 binding->Offset = offset;
2948 binding->Size = size;
2949 bufObj->UsageHistory |= USAGE_ATOMIC_COUNTER_BUFFER;
2950 }
2951 }
2952
2953 /**
2954 * Binds a buffer object to an atomic buffer binding point.
2955 *
2956 * Unlike set_atomic_buffer_binding(), this function also validates the
2957 * index and offset, flushes vertices, and updates NewDriverState.
2958 * It also checks if the binding has actually changing before
2959 * updating it.
2960 */
2961 static void
2962 bind_atomic_buffer(struct gl_context *ctx,
2963 unsigned index,
2964 struct gl_buffer_object *bufObj,
2965 GLintptr offset,
2966 GLsizeiptr size,
2967 const char *name)
2968 {
2969 struct gl_atomic_buffer_binding *binding;
2970
2971 if (index >= ctx->Const.MaxAtomicBufferBindings) {
2972 _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%d)", name, index);
2973 return;
2974 }
2975
2976 if (offset & (ATOMIC_COUNTER_SIZE - 1)) {
2977 _mesa_error(ctx, GL_INVALID_VALUE,
2978 "%s(offset misaligned %d/%d)", name, (int) offset,
2979 ATOMIC_COUNTER_SIZE);
2980 return;
2981 }
2982
2983 _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, bufObj);
2984
2985 binding = &ctx->AtomicBufferBindings[index];
2986 if (binding->BufferObject == bufObj &&
2987 binding->Offset == offset &&
2988 binding->Size == size) {
2989 return;
2990 }
2991
2992 FLUSH_VERTICES(ctx, 0);
2993 ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer;
2994
2995 set_atomic_buffer_binding(ctx, binding, bufObj, offset, size);
2996 }
2997
2998 static inline bool
2999 bind_buffers_check_offset_and_size(struct gl_context *ctx,
3000 GLuint index,
3001 const GLintptr *offsets,
3002 const GLsizeiptr *sizes)
3003 {
3004 if (offsets[index] < 0) {
3005 /* The ARB_multi_bind spec says:
3006 *
3007 * "An INVALID_VALUE error is generated by BindBuffersRange if any
3008 * value in <offsets> is less than zero (per binding)."
3009 */
3010 _mesa_error(ctx, GL_INVALID_VALUE,
3011 "glBindBuffersRange(offsets[%u]=%" PRId64 " < 0)",
3012 index, (int64_t) offsets[index]);
3013 return false;
3014 }
3015
3016 if (sizes[index] <= 0) {
3017 /* The ARB_multi_bind spec says:
3018 *
3019 * "An INVALID_VALUE error is generated by BindBuffersRange if any
3020 * value in <sizes> is less than or equal to zero (per binding)."
3021 */
3022 _mesa_error(ctx, GL_INVALID_VALUE,
3023 "glBindBuffersRange(sizes[%u]=%" PRId64 " <= 0)",
3024 index, (int64_t) sizes[index]);
3025 return false;
3026 }
3027
3028 return true;
3029 }
3030
3031 static bool
3032 error_check_bind_uniform_buffers(struct gl_context *ctx,
3033 GLuint first, GLsizei count,
3034 const char *caller)
3035 {
3036 if (!ctx->Extensions.ARB_uniform_buffer_object) {
3037 _mesa_error(ctx, GL_INVALID_ENUM,
3038 "%s(target=GL_UNIFORM_BUFFER)", caller);
3039 return false;
3040 }
3041
3042 /* The ARB_multi_bind_spec says:
3043 *
3044 * "An INVALID_OPERATION error is generated if <first> + <count> is
3045 * greater than the number of target-specific indexed binding points,
3046 * as described in section 6.7.1."
3047 */
3048 if (first + count > ctx->Const.MaxUniformBufferBindings) {
3049 _mesa_error(ctx, GL_INVALID_OPERATION,
3050 "%s(first=%u + count=%d > the value of "
3051 "GL_MAX_UNIFORM_BUFFER_BINDINGS=%u)",
3052 caller, first, count,
3053 ctx->Const.MaxUniformBufferBindings);
3054 return false;
3055 }
3056
3057 return true;
3058 }
3059
3060 /**
3061 * Unbind all uniform buffers in the range
3062 * <first> through <first>+<count>-1
3063 */
3064 static void
3065 unbind_uniform_buffers(struct gl_context *ctx, GLuint first, GLsizei count)
3066 {
3067 struct gl_buffer_object *bufObj = ctx->Shared->NullBufferObj;
3068 GLint i;
3069
3070 for (i = 0; i < count; i++)
3071 set_ubo_binding(ctx, &ctx->UniformBufferBindings[first + i],
3072 bufObj, -1, -1, GL_TRUE);
3073 }
3074
3075 static void
3076 bind_uniform_buffers_base(struct gl_context *ctx, GLuint first, GLsizei count,
3077 const GLuint *buffers)
3078 {
3079 GLint i;
3080
3081 if (!error_check_bind_uniform_buffers(ctx, first, count, "glBindBuffersBase"))
3082 return;
3083
3084 /* Assume that at least one binding will be changed */
3085 FLUSH_VERTICES(ctx, 0);
3086 ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer;
3087
3088 if (!buffers) {
3089 /* The ARB_multi_bind spec says:
3090 *
3091 * "If <buffers> is NULL, all bindings from <first> through
3092 * <first>+<count>-1 are reset to their unbound (zero) state."
3093 */
3094 unbind_uniform_buffers(ctx, first, count);
3095 return;
3096 }
3097
3098 /* Note that the error semantics for multi-bind commands differ from
3099 * those of other GL commands.
3100 *
3101 * The Issues section in the ARB_multi_bind spec says:
3102 *
3103 * "(11) Typically, OpenGL specifies that if an error is generated by a
3104 * command, that command has no effect. This is somewhat
3105 * unfortunate for multi-bind commands, because it would require a
3106 * first pass to scan the entire list of bound objects for errors
3107 * and then a second pass to actually perform the bindings.
3108 * Should we have different error semantics?
3109 *
3110 * RESOLVED: Yes. In this specification, when the parameters for
3111 * one of the <count> binding points are invalid, that binding point
3112 * is not updated and an error will be generated. However, other
3113 * binding points in the same command will be updated if their
3114 * parameters are valid and no other error occurs."
3115 */
3116
3117 _mesa_begin_bufferobj_lookups(ctx);
3118
3119 for (i = 0; i < count; i++) {
3120 struct gl_uniform_buffer_binding *binding =
3121 &ctx->UniformBufferBindings[first + i];
3122 struct gl_buffer_object *bufObj;
3123
3124 if (binding->BufferObject && binding->BufferObject->Name == buffers[i])
3125 bufObj = binding->BufferObject;
3126 else
3127 bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
3128 "glBindBuffersBase");
3129
3130 if (bufObj) {
3131 if (bufObj == ctx->Shared->NullBufferObj)
3132 set_ubo_binding(ctx, binding, bufObj, -1, -1, GL_TRUE);
3133 else
3134 set_ubo_binding(ctx, binding, bufObj, 0, 0, GL_TRUE);
3135 }
3136 }
3137
3138 _mesa_end_bufferobj_lookups(ctx);
3139 }
3140
3141 static void
3142 bind_uniform_buffers_range(struct gl_context *ctx, GLuint first, GLsizei count,
3143 const GLuint *buffers,
3144 const GLintptr *offsets, const GLsizeiptr *sizes)
3145 {
3146 GLint i;
3147
3148 if (!error_check_bind_uniform_buffers(ctx, first, count,
3149 "glBindBuffersRange"))
3150 return;
3151
3152 /* Assume that at least one binding will be changed */
3153 FLUSH_VERTICES(ctx, 0);
3154 ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer;
3155
3156 if (!buffers) {
3157 /* The ARB_multi_bind spec says:
3158 *
3159 * "If <buffers> is NULL, all bindings from <first> through
3160 * <first>+<count>-1 are reset to their unbound (zero) state.
3161 * In this case, the offsets and sizes associated with the
3162 * binding points are set to default values, ignoring
3163 * <offsets> and <sizes>."
3164 */
3165 unbind_uniform_buffers(ctx, first, count);
3166 return;
3167 }
3168
3169 /* Note that the error semantics for multi-bind commands differ from
3170 * those of other GL commands.
3171 *
3172 * The Issues section in the ARB_multi_bind spec says:
3173 *
3174 * "(11) Typically, OpenGL specifies that if an error is generated by a
3175 * command, that command has no effect. This is somewhat
3176 * unfortunate for multi-bind commands, because it would require a
3177 * first pass to scan the entire list of bound objects for errors
3178 * and then a second pass to actually perform the bindings.
3179 * Should we have different error semantics?
3180 *
3181 * RESOLVED: Yes. In this specification, when the parameters for
3182 * one of the <count> binding points are invalid, that binding point
3183 * is not updated and an error will be generated. However, other
3184 * binding points in the same command will be updated if their
3185 * parameters are valid and no other error occurs."
3186 */
3187
3188 _mesa_begin_bufferobj_lookups(ctx);
3189
3190 for (i = 0; i < count; i++) {
3191 struct gl_uniform_buffer_binding *binding =
3192 &ctx->UniformBufferBindings[first + i];
3193 struct gl_buffer_object *bufObj;
3194
3195 if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
3196 continue;
3197
3198 /* The ARB_multi_bind spec says:
3199 *
3200 * "An INVALID_VALUE error is generated by BindBuffersRange if any
3201 * pair of values in <offsets> and <sizes> does not respectively
3202 * satisfy the constraints described for those parameters for the
3203 * specified target, as described in section 6.7.1 (per binding)."
3204 *
3205 * Section 6.7.1 refers to table 6.5, which says:
3206 *
3207 * "┌───────────────────────────────────────────────────────────────┐
3208 * │ Uniform buffer array bindings (see sec. 7.6) │
3209 * ├─────────────────────┬─────────────────────────────────────────┤
3210 * │ ... │ ... │
3211 * │ offset restriction │ multiple of value of UNIFORM_BUFFER_- │
3212 * │ │ OFFSET_ALIGNMENT │
3213 * │ ... │ ... │
3214 * │ size restriction │ none │
3215 * └─────────────────────┴─────────────────────────────────────────┘"
3216 */
3217 if (offsets[i] & (ctx->Const.UniformBufferOffsetAlignment - 1)) {
3218 _mesa_error(ctx, GL_INVALID_VALUE,
3219 "glBindBuffersRange(offsets[%u]=%" PRId64
3220 " is misaligned; it must be a multiple of the value of "
3221 "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT=%u when "
3222 "target=GL_UNIFORM_BUFFER)",
3223 i, (int64_t) offsets[i],
3224 ctx->Const.UniformBufferOffsetAlignment);
3225 continue;
3226 }
3227
3228 if (binding->BufferObject && binding->BufferObject->Name == buffers[i])
3229 bufObj = binding->BufferObject;
3230 else
3231 bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
3232 "glBindBuffersRange");
3233
3234 if (bufObj) {
3235 if (bufObj == ctx->Shared->NullBufferObj)
3236 set_ubo_binding(ctx, binding, bufObj, -1, -1, GL_FALSE);
3237 else
3238 set_ubo_binding(ctx, binding, bufObj,
3239 offsets[i], sizes[i], GL_FALSE);
3240 }
3241 }
3242
3243 _mesa_end_bufferobj_lookups(ctx);
3244 }
3245
3246 static bool
3247 error_check_bind_xfb_buffers(struct gl_context *ctx,
3248 struct gl_transform_feedback_object *tfObj,
3249 GLuint first, GLsizei count, const char *caller)
3250 {
3251 if (!ctx->Extensions.EXT_transform_feedback) {
3252 _mesa_error(ctx, GL_INVALID_ENUM,
3253 "%s(target=GL_TRANSFORM_FEEDBACK_BUFFER)", caller);
3254 return false;
3255 }
3256
3257 /* Page 398 of the PDF of the OpenGL 4.4 (Core Profile) spec says:
3258 *
3259 * "An INVALID_OPERATION error is generated :
3260 *
3261 * ...
3262 * • by BindBufferRange or BindBufferBase if target is TRANSFORM_-
3263 * FEEDBACK_BUFFER and transform feedback is currently active."
3264 *
3265 * We assume that this is also meant to apply to BindBuffersRange
3266 * and BindBuffersBase.
3267 */
3268 if (tfObj->Active) {
3269 _mesa_error(ctx, GL_INVALID_OPERATION,
3270 "%s(Changing transform feedback buffers while "
3271 "transform feedback is active)", caller);
3272 return false;
3273 }
3274
3275 /* The ARB_multi_bind_spec says:
3276 *
3277 * "An INVALID_OPERATION error is generated if <first> + <count> is
3278 * greater than the number of target-specific indexed binding points,
3279 * as described in section 6.7.1."
3280 */
3281 if (first + count > ctx->Const.MaxTransformFeedbackBuffers) {
3282 _mesa_error(ctx, GL_INVALID_OPERATION,
3283 "%s(first=%u + count=%d > the value of "
3284 "GL_MAX_TRANSFORM_FEEDBACK_BUFFERS=%u)",
3285 caller, first, count,
3286 ctx->Const.MaxTransformFeedbackBuffers);
3287 return false;
3288 }
3289
3290 return true;
3291 }
3292
3293 /**
3294 * Unbind all transform feedback buffers in the range
3295 * <first> through <first>+<count>-1
3296 */
3297 static void
3298 unbind_xfb_buffers(struct gl_context *ctx,
3299 struct gl_transform_feedback_object *tfObj,
3300 GLuint first, GLsizei count)
3301 {
3302 struct gl_buffer_object * const bufObj = ctx->Shared->NullBufferObj;
3303 GLint i;
3304
3305 for (i = 0; i < count; i++)
3306 _mesa_set_transform_feedback_binding(ctx, tfObj, first + i,
3307 bufObj, 0, 0);
3308 }
3309
3310 static void
3311 bind_xfb_buffers_base(struct gl_context *ctx,
3312 GLuint first, GLsizei count,
3313 const GLuint *buffers)
3314 {
3315 struct gl_transform_feedback_object *tfObj =
3316 ctx->TransformFeedback.CurrentObject;
3317 GLint i;
3318
3319 if (!error_check_bind_xfb_buffers(ctx, tfObj, first, count,
3320 "glBindBuffersBase"))
3321 return;
3322
3323 /* Assume that at least one binding will be changed */
3324 FLUSH_VERTICES(ctx, 0);
3325 ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
3326
3327 if (!buffers) {
3328 /* The ARB_multi_bind spec says:
3329 *
3330 * "If <buffers> is NULL, all bindings from <first> through
3331 * <first>+<count>-1 are reset to their unbound (zero) state."
3332 */
3333 unbind_xfb_buffers(ctx, tfObj, first, count);
3334 return;
3335 }
3336
3337 /* Note that the error semantics for multi-bind commands differ from
3338 * those of other GL commands.
3339 *
3340 * The Issues section in the ARB_multi_bind spec says:
3341 *
3342 * "(11) Typically, OpenGL specifies that if an error is generated by a
3343 * command, that command has no effect. This is somewhat
3344 * unfortunate for multi-bind commands, because it would require a
3345 * first pass to scan the entire list of bound objects for errors
3346 * and then a second pass to actually perform the bindings.
3347 * Should we have different error semantics?
3348 *
3349 * RESOLVED: Yes. In this specification, when the parameters for
3350 * one of the <count> binding points are invalid, that binding point
3351 * is not updated and an error will be generated. However, other
3352 * binding points in the same command will be updated if their
3353 * parameters are valid and no other error occurs."
3354 */
3355
3356 _mesa_begin_bufferobj_lookups(ctx);
3357
3358 for (i = 0; i < count; i++) {
3359 struct gl_buffer_object * const boundBufObj = tfObj->Buffers[first + i];
3360 struct gl_buffer_object *bufObj;
3361
3362 if (boundBufObj && boundBufObj->Name == buffers[i])
3363 bufObj = boundBufObj;
3364 else
3365 bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
3366 "glBindBuffersBase");
3367
3368 if (bufObj)
3369 _mesa_set_transform_feedback_binding(ctx, tfObj, first + i,
3370 bufObj, 0, 0);
3371 }
3372
3373 _mesa_end_bufferobj_lookups(ctx);
3374 }
3375
3376 static void
3377 bind_xfb_buffers_range(struct gl_context *ctx,
3378 GLuint first, GLsizei count,
3379 const GLuint *buffers,
3380 const GLintptr *offsets,
3381 const GLsizeiptr *sizes)
3382 {
3383 struct gl_transform_feedback_object *tfObj =
3384 ctx->TransformFeedback.CurrentObject;
3385 GLint i;
3386
3387 if (!error_check_bind_xfb_buffers(ctx, tfObj, first, count,
3388 "glBindBuffersRange"))
3389 return;
3390
3391 /* Assume that at least one binding will be changed */
3392 FLUSH_VERTICES(ctx, 0);
3393 ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
3394
3395 if (!buffers) {
3396 /* The ARB_multi_bind spec says:
3397 *
3398 * "If <buffers> is NULL, all bindings from <first> through
3399 * <first>+<count>-1 are reset to their unbound (zero) state.
3400 * In this case, the offsets and sizes associated with the
3401 * binding points are set to default values, ignoring
3402 * <offsets> and <sizes>."
3403 */
3404 unbind_xfb_buffers(ctx, tfObj, first, count);
3405 return;
3406 }
3407
3408 /* Note that the error semantics for multi-bind commands differ from
3409 * those of other GL commands.
3410 *
3411 * The Issues section in the ARB_multi_bind spec says:
3412 *
3413 * "(11) Typically, OpenGL specifies that if an error is generated by a
3414 * command, that command has no effect. This is somewhat
3415 * unfortunate for multi-bind commands, because it would require a
3416 * first pass to scan the entire list of bound objects for errors
3417 * and then a second pass to actually perform the bindings.
3418 * Should we have different error semantics?
3419 *
3420 * RESOLVED: Yes. In this specification, when the parameters for
3421 * one of the <count> binding points are invalid, that binding point
3422 * is not updated and an error will be generated. However, other
3423 * binding points in the same command will be updated if their
3424 * parameters are valid and no other error occurs."
3425 */
3426
3427 _mesa_begin_bufferobj_lookups(ctx);
3428
3429 for (i = 0; i < count; i++) {
3430 const GLuint index = first + i;
3431 struct gl_buffer_object * const boundBufObj = tfObj->Buffers[index];
3432 struct gl_buffer_object *bufObj;
3433
3434 if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
3435 continue;
3436
3437 /* The ARB_multi_bind spec says:
3438 *
3439 * "An INVALID_VALUE error is generated by BindBuffersRange if any
3440 * pair of values in <offsets> and <sizes> does not respectively
3441 * satisfy the constraints described for those parameters for the
3442 * specified target, as described in section 6.7.1 (per binding)."
3443 *
3444 * Section 6.7.1 refers to table 6.5, which says:
3445 *
3446 * "┌───────────────────────────────────────────────────────────────┐
3447 * │ Transform feedback array bindings (see sec. 13.2.2) │
3448 * ├───────────────────────┬───────────────────────────────────────┤
3449 * │ ... │ ... │
3450 * │ offset restriction │ multiple of 4 │
3451 * │ ... │ ... │
3452 * │ size restriction │ multiple of 4 │
3453 * └───────────────────────┴───────────────────────────────────────┘"
3454 */
3455 if (offsets[i] & 0x3) {
3456 _mesa_error(ctx, GL_INVALID_VALUE,
3457 "glBindBuffersRange(offsets[%u]=%" PRId64
3458 " is misaligned; it must be a multiple of 4 when "
3459 "target=GL_TRANSFORM_FEEDBACK_BUFFER)",
3460 i, (int64_t) offsets[i]);
3461 continue;
3462 }
3463
3464 if (sizes[i] & 0x3) {
3465 _mesa_error(ctx, GL_INVALID_VALUE,
3466 "glBindBuffersRange(sizes[%u]=%" PRId64
3467 " is misaligned; it must be a multiple of 4 when "
3468 "target=GL_TRANSFORM_FEEDBACK_BUFFER)",
3469 i, (int64_t) sizes[i]);
3470 continue;
3471 }
3472
3473 if (boundBufObj && boundBufObj->Name == buffers[i])
3474 bufObj = boundBufObj;
3475 else
3476 bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
3477 "glBindBuffersRange");
3478
3479 if (bufObj)
3480 _mesa_set_transform_feedback_binding(ctx, tfObj, index, bufObj,
3481 offsets[i], sizes[i]);
3482 }
3483
3484 _mesa_end_bufferobj_lookups(ctx);
3485 }
3486
3487 static bool
3488 error_check_bind_atomic_buffers(struct gl_context *ctx,
3489 GLuint first, GLsizei count,
3490 const char *caller)
3491 {
3492 if (!ctx->Extensions.ARB_shader_atomic_counters) {
3493 _mesa_error(ctx, GL_INVALID_ENUM,
3494 "%s(target=GL_ATOMIC_COUNTER_BUFFER)", caller);
3495 return false;
3496 }
3497
3498 /* The ARB_multi_bind_spec says:
3499 *
3500 * "An INVALID_OPERATION error is generated if <first> + <count> is
3501 * greater than the number of target-specific indexed binding points,
3502 * as described in section 6.7.1."
3503 */
3504 if (first + count > ctx->Const.MaxAtomicBufferBindings) {
3505 _mesa_error(ctx, GL_INVALID_OPERATION,
3506 "%s(first=%u + count=%d > the value of "
3507 "GL_MAX_ATOMIC_BUFFER_BINDINGS=%u)",
3508 caller, first, count, ctx->Const.MaxAtomicBufferBindings);
3509 return false;
3510 }
3511
3512 return true;
3513 }
3514
3515 /**
3516 * Unbind all atomic counter buffers in the range
3517 * <first> through <first>+<count>-1
3518 */
3519 static void
3520 unbind_atomic_buffers(struct gl_context *ctx, GLuint first, GLsizei count)
3521 {
3522 struct gl_buffer_object * const bufObj = ctx->Shared->NullBufferObj;
3523 GLint i;
3524
3525 for (i = 0; i < count; i++)
3526 set_atomic_buffer_binding(ctx, &ctx->AtomicBufferBindings[first + i],
3527 bufObj, -1, -1);
3528 }
3529
3530 static void
3531 bind_atomic_buffers_base(struct gl_context *ctx,
3532 GLuint first,
3533 GLsizei count,
3534 const GLuint *buffers)
3535 {
3536 GLint i;
3537
3538 if (!error_check_bind_atomic_buffers(ctx, first, count,
3539 "glBindBuffersBase"))
3540 return;
3541
3542 /* Assume that at least one binding will be changed */
3543 FLUSH_VERTICES(ctx, 0);
3544 ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer;
3545
3546 if (!buffers) {
3547 /* The ARB_multi_bind spec says:
3548 *
3549 * "If <buffers> is NULL, all bindings from <first> through
3550 * <first>+<count>-1 are reset to their unbound (zero) state."
3551 */
3552 unbind_atomic_buffers(ctx, first, count);
3553 return;
3554 }
3555
3556 /* Note that the error semantics for multi-bind commands differ from
3557 * those of other GL commands.
3558 *
3559 * The Issues section in the ARB_multi_bind spec says:
3560 *
3561 * "(11) Typically, OpenGL specifies that if an error is generated by a
3562 * command, that command has no effect. This is somewhat
3563 * unfortunate for multi-bind commands, because it would require a
3564 * first pass to scan the entire list of bound objects for errors
3565 * and then a second pass to actually perform the bindings.
3566 * Should we have different error semantics?
3567 *
3568 * RESOLVED: Yes. In this specification, when the parameters for
3569 * one of the <count> binding points are invalid, that binding point
3570 * is not updated and an error will be generated. However, other
3571 * binding points in the same command will be updated if their
3572 * parameters are valid and no other error occurs."
3573 */
3574
3575 _mesa_begin_bufferobj_lookups(ctx);
3576
3577 for (i = 0; i < count; i++) {
3578 struct gl_atomic_buffer_binding *binding =
3579 &ctx->AtomicBufferBindings[first + i];
3580 struct gl_buffer_object *bufObj;
3581
3582 if (binding->BufferObject && binding->BufferObject->Name == buffers[i])
3583 bufObj = binding->BufferObject;
3584 else
3585 bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
3586 "glBindBuffersBase");
3587
3588 if (bufObj)
3589 set_atomic_buffer_binding(ctx, binding, bufObj, 0, 0);
3590 }
3591
3592 _mesa_end_bufferobj_lookups(ctx);
3593 }
3594
3595 static void
3596 bind_atomic_buffers_range(struct gl_context *ctx,
3597 GLuint first,
3598 GLsizei count,
3599 const GLuint *buffers,
3600 const GLintptr *offsets,
3601 const GLsizeiptr *sizes)
3602 {
3603 GLint i;
3604
3605 if (!error_check_bind_atomic_buffers(ctx, first, count,
3606 "glBindBuffersRange"))
3607 return;
3608
3609 /* Assume that at least one binding will be changed */
3610 FLUSH_VERTICES(ctx, 0);
3611 ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer;
3612
3613 if (!buffers) {
3614 /* The ARB_multi_bind spec says:
3615 *
3616 * "If <buffers> is NULL, all bindings from <first> through
3617 * <first>+<count>-1 are reset to their unbound (zero) state.
3618 * In this case, the offsets and sizes associated with the
3619 * binding points are set to default values, ignoring
3620 * <offsets> and <sizes>."
3621 */
3622 unbind_atomic_buffers(ctx, first, count);
3623 return;
3624 }
3625
3626 /* Note that the error semantics for multi-bind commands differ from
3627 * those of other GL commands.
3628 *
3629 * The Issues section in the ARB_multi_bind spec says:
3630 *
3631 * "(11) Typically, OpenGL specifies that if an error is generated by a
3632 * command, that command has no effect. This is somewhat
3633 * unfortunate for multi-bind commands, because it would require a
3634 * first pass to scan the entire list of bound objects for errors
3635 * and then a second pass to actually perform the bindings.
3636 * Should we have different error semantics?
3637 *
3638 * RESOLVED: Yes. In this specification, when the parameters for
3639 * one of the <count> binding points are invalid, that binding point
3640 * is not updated and an error will be generated. However, other
3641 * binding points in the same command will be updated if their
3642 * parameters are valid and no other error occurs."
3643 */
3644
3645 _mesa_begin_bufferobj_lookups(ctx);
3646
3647 for (i = 0; i < count; i++) {
3648 struct gl_atomic_buffer_binding *binding =
3649 &ctx->AtomicBufferBindings[first + i];
3650 struct gl_buffer_object *bufObj;
3651
3652 if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
3653 continue;
3654
3655 /* The ARB_multi_bind spec says:
3656 *
3657 * "An INVALID_VALUE error is generated by BindBuffersRange if any
3658 * pair of values in <offsets> and <sizes> does not respectively
3659 * satisfy the constraints described for those parameters for the
3660 * specified target, as described in section 6.7.1 (per binding)."
3661 *
3662 * Section 6.7.1 refers to table 6.5, which says:
3663 *
3664 * "┌───────────────────────────────────────────────────────────────┐
3665 * │ Atomic counter array bindings (see sec. 7.7.2) │
3666 * ├───────────────────────┬───────────────────────────────────────┤
3667 * │ ... │ ... │
3668 * │ offset restriction │ multiple of 4 │
3669 * │ ... │ ... │
3670 * │ size restriction │ none │
3671 * └───────────────────────┴───────────────────────────────────────┘"
3672 */
3673 if (offsets[i] & (ATOMIC_COUNTER_SIZE - 1)) {
3674 _mesa_error(ctx, GL_INVALID_VALUE,
3675 "glBindBuffersRange(offsets[%u]=%" PRId64
3676 " is misaligned; it must be a multiple of %d when "
3677 "target=GL_ATOMIC_COUNTER_BUFFER)",
3678 i, (int64_t) offsets[i], ATOMIC_COUNTER_SIZE);
3679 continue;
3680 }
3681
3682 if (binding->BufferObject && binding->BufferObject->Name == buffers[i])
3683 bufObj = binding->BufferObject;
3684 else
3685 bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
3686 "glBindBuffersRange");
3687
3688 if (bufObj)
3689 set_atomic_buffer_binding(ctx, binding, bufObj, offsets[i], sizes[i]);
3690 }
3691
3692 _mesa_end_bufferobj_lookups(ctx);
3693 }
3694
3695 void GLAPIENTRY
3696 _mesa_BindBufferRange(GLenum target, GLuint index,
3697 GLuint buffer, GLintptr offset, GLsizeiptr size)
3698 {
3699 GET_CURRENT_CONTEXT(ctx);
3700 struct gl_buffer_object *bufObj;
3701
3702 if (buffer == 0) {
3703 bufObj = ctx->Shared->NullBufferObj;
3704 } else {
3705 bufObj = _mesa_lookup_bufferobj(ctx, buffer);
3706 }
3707 if (!_mesa_handle_bind_buffer_gen(ctx, target, buffer,
3708 &bufObj, "glBindBufferRange"))
3709 return;
3710
3711 if (!bufObj) {
3712 _mesa_error(ctx, GL_INVALID_OPERATION,
3713 "glBindBufferRange(invalid buffer=%u)", buffer);
3714 return;
3715 }
3716
3717 if (buffer != 0) {
3718 if (size <= 0) {
3719 _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(size=%d)",
3720 (int) size);
3721 return;
3722 }
3723 }
3724
3725 switch (target) {
3726 case GL_TRANSFORM_FEEDBACK_BUFFER:
3727 _mesa_bind_buffer_range_transform_feedback(ctx, index, bufObj,
3728 offset, size);
3729 return;
3730 case GL_UNIFORM_BUFFER:
3731 bind_buffer_range_uniform_buffer(ctx, index, bufObj, offset, size);
3732 return;
3733 case GL_ATOMIC_COUNTER_BUFFER:
3734 bind_atomic_buffer(ctx, index, bufObj, offset, size,
3735 "glBindBufferRange");
3736 return;
3737 default:
3738 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferRange(target)");
3739 return;
3740 }
3741 }
3742
3743 void GLAPIENTRY
3744 _mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer)
3745 {
3746 GET_CURRENT_CONTEXT(ctx);
3747 struct gl_buffer_object *bufObj;
3748
3749 if (buffer == 0) {
3750 bufObj = ctx->Shared->NullBufferObj;
3751 } else {
3752 bufObj = _mesa_lookup_bufferobj(ctx, buffer);
3753 }
3754 if (!_mesa_handle_bind_buffer_gen(ctx, target, buffer,
3755 &bufObj, "glBindBufferBase"))
3756 return;
3757
3758 if (!bufObj) {
3759 _mesa_error(ctx, GL_INVALID_OPERATION,
3760 "glBindBufferBase(invalid buffer=%u)", buffer);
3761 return;
3762 }
3763
3764 /* Note that there's some oddness in the GL 3.1-GL 3.3 specifications with
3765 * regards to BindBufferBase. It says (GL 3.1 core spec, page 63):
3766 *
3767 * "BindBufferBase is equivalent to calling BindBufferRange with offset
3768 * zero and size equal to the size of buffer."
3769 *
3770 * but it says for glGetIntegeri_v (GL 3.1 core spec, page 230):
3771 *
3772 * "If the parameter (starting offset or size) was not specified when the
3773 * buffer object was bound, zero is returned."
3774 *
3775 * What happens if the size of the buffer changes? Does the size of the
3776 * buffer at the moment glBindBufferBase was called still play a role, like
3777 * the first quote would imply, or is the size meaningless in the
3778 * glBindBufferBase case like the second quote would suggest? The GL 4.1
3779 * core spec page 45 says:
3780 *
3781 * "It is equivalent to calling BindBufferRange with offset zero, while
3782 * size is determined by the size of the bound buffer at the time the
3783 * binding is used."
3784 *
3785 * My interpretation is that the GL 4.1 spec was a clarification of the
3786 * behavior, not a change. In particular, this choice will only make
3787 * rendering work in cases where it would have had undefined results.
3788 */
3789
3790 switch (target) {
3791 case GL_TRANSFORM_FEEDBACK_BUFFER:
3792 _mesa_bind_buffer_base_transform_feedback(ctx, index, bufObj);
3793 return;
3794 case GL_UNIFORM_BUFFER:
3795 bind_buffer_base_uniform_buffer(ctx, index, bufObj);
3796 return;
3797 case GL_ATOMIC_COUNTER_BUFFER:
3798 bind_atomic_buffer(ctx, index, bufObj, 0, 0,
3799 "glBindBufferBase");
3800 return;
3801 default:
3802 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)");
3803 return;
3804 }
3805 }
3806
3807 void GLAPIENTRY
3808 _mesa_BindBuffersRange(GLenum target, GLuint first, GLsizei count,
3809 const GLuint *buffers,
3810 const GLintptr *offsets, const GLsizeiptr *sizes)
3811 {
3812 GET_CURRENT_CONTEXT(ctx);
3813
3814 switch (target) {
3815 case GL_TRANSFORM_FEEDBACK_BUFFER:
3816 bind_xfb_buffers_range(ctx, first, count, buffers, offsets, sizes);
3817 return;
3818 case GL_UNIFORM_BUFFER:
3819 bind_uniform_buffers_range(ctx, first, count, buffers, offsets, sizes);
3820 return;
3821 case GL_ATOMIC_COUNTER_BUFFER:
3822 bind_atomic_buffers_range(ctx, first, count, buffers,
3823 offsets, sizes);
3824 return;
3825 default:
3826 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBuffersRange(target=%s)",
3827 _mesa_lookup_enum_by_nr(target));
3828 break;
3829 }
3830 }
3831
3832 void GLAPIENTRY
3833 _mesa_BindBuffersBase(GLenum target, GLuint first, GLsizei count,
3834 const GLuint *buffers)
3835 {
3836 GET_CURRENT_CONTEXT(ctx);
3837
3838 switch (target) {
3839 case GL_TRANSFORM_FEEDBACK_BUFFER:
3840 bind_xfb_buffers_base(ctx, first, count, buffers);
3841 return;
3842 case GL_UNIFORM_BUFFER:
3843 bind_uniform_buffers_base(ctx, first, count, buffers);
3844 return;
3845 case GL_ATOMIC_COUNTER_BUFFER:
3846 bind_atomic_buffers_base(ctx, first, count, buffers);
3847 return;
3848 default:
3849 _mesa_error(ctx, GL_INVALID_ENUM, "glBindBuffersBase(target=%s)",
3850 _mesa_lookup_enum_by_nr(target));
3851 break;
3852 }
3853 }
3854
3855 void GLAPIENTRY
3856 _mesa_InvalidateBufferSubData(GLuint buffer, GLintptr offset,
3857 GLsizeiptr length)
3858 {
3859 GET_CURRENT_CONTEXT(ctx);
3860 struct gl_buffer_object *bufObj;
3861 const GLintptr end = offset + length;
3862
3863 bufObj = _mesa_lookup_bufferobj(ctx, buffer);
3864 if (!bufObj) {
3865 _mesa_error(ctx, GL_INVALID_VALUE,
3866 "glInvalidateBufferSubData(name = 0x%x) invalid object",
3867 buffer);
3868 return;
3869 }
3870
3871 /* The GL_ARB_invalidate_subdata spec says:
3872 *
3873 * "An INVALID_VALUE error is generated if <offset> or <length> is
3874 * negative, or if <offset> + <length> is greater than the value of
3875 * BUFFER_SIZE."
3876 */
3877 if (end < 0 || end > bufObj->Size) {
3878 _mesa_error(ctx, GL_INVALID_VALUE,
3879 "glInvalidateBufferSubData(invalid offset or length)");
3880 return;
3881 }
3882
3883 /* The OpenGL 4.4 (Core Profile) spec says:
3884 *
3885 * "An INVALID_OPERATION error is generated if buffer is currently
3886 * mapped by MapBuffer or if the invalidate range intersects the range
3887 * currently mapped by MapBufferRange, unless it was mapped
3888 * with MAP_PERSISTENT_BIT set in the MapBufferRange access flags."
3889 */
3890 if (!(bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_PERSISTENT_BIT) &&
3891 bufferobj_range_mapped(bufObj, offset, length)) {
3892 _mesa_error(ctx, GL_INVALID_OPERATION,
3893 "glInvalidateBufferSubData(intersection with mapped "
3894 "range)");
3895 return;
3896 }
3897
3898 /* We don't actually do anything for this yet. Just return after
3899 * validating the parameters and generating the required errors.
3900 */
3901 return;
3902 }
3903
3904 void GLAPIENTRY
3905 _mesa_InvalidateBufferData(GLuint buffer)
3906 {
3907 GET_CURRENT_CONTEXT(ctx);
3908 struct gl_buffer_object *bufObj;
3909
3910 bufObj = _mesa_lookup_bufferobj(ctx, buffer);
3911 if (!bufObj) {
3912 _mesa_error(ctx, GL_INVALID_VALUE,
3913 "glInvalidateBufferData(name = 0x%x) invalid object",
3914 buffer);
3915 return;
3916 }
3917
3918 /* The OpenGL 4.4 (Core Profile) spec says:
3919 *
3920 * "An INVALID_OPERATION error is generated if buffer is currently
3921 * mapped by MapBuffer or if the invalidate range intersects the range
3922 * currently mapped by MapBufferRange, unless it was mapped
3923 * with MAP_PERSISTENT_BIT set in the MapBufferRange access flags."
3924 */
3925 if (_mesa_check_disallowed_mapping(bufObj)) {
3926 _mesa_error(ctx, GL_INVALID_OPERATION,
3927 "glInvalidateBufferData(intersection with mapped "
3928 "range)");
3929 return;
3930 }
3931
3932 /* We don't actually do anything for this yet. Just return after
3933 * validating the parameters and generating the required errors.
3934 */
3935 return;
3936 }