bufferobj.c revision 848b8605
1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 5848b8605Smrg * Copyright (C) 2009 VMware, Inc. All Rights Reserved. 6848b8605Smrg * 7848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 8848b8605Smrg * copy of this software and associated documentation files (the "Software"), 9848b8605Smrg * to deal in the Software without restriction, including without limitation 10848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 12848b8605Smrg * Software is furnished to do so, subject to the following conditions: 13848b8605Smrg * 14848b8605Smrg * The above copyright notice and this permission notice shall be included 15848b8605Smrg * in all copies or substantial portions of the Software. 16848b8605Smrg * 17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 24848b8605Smrg */ 25848b8605Smrg 26848b8605Smrg 27848b8605Smrg/** 28848b8605Smrg * \file bufferobj.c 29848b8605Smrg * \brief Functions for the GL_ARB_vertex/pixel_buffer_object extensions. 30848b8605Smrg * \author Brian Paul, Ian Romanick 31848b8605Smrg */ 32848b8605Smrg 33848b8605Smrg#include <stdbool.h> 34848b8605Smrg#include <inttypes.h> /* for PRId64 macro */ 35848b8605Smrg#include "glheader.h" 36848b8605Smrg#include "enums.h" 37848b8605Smrg#include "hash.h" 38848b8605Smrg#include "imports.h" 39848b8605Smrg#include "image.h" 40848b8605Smrg#include "context.h" 41848b8605Smrg#include "bufferobj.h" 42848b8605Smrg#include "fbobject.h" 43848b8605Smrg#include "mtypes.h" 44848b8605Smrg#include "texobj.h" 45848b8605Smrg#include "teximage.h" 46848b8605Smrg#include "glformats.h" 47848b8605Smrg#include "texstore.h" 48848b8605Smrg#include "transformfeedback.h" 49848b8605Smrg#include "dispatch.h" 50848b8605Smrg 51848b8605Smrg 52848b8605Smrg/* Debug flags */ 53848b8605Smrg/*#define VBO_DEBUG*/ 54848b8605Smrg/*#define BOUNDS_CHECK*/ 55848b8605Smrg 56848b8605Smrg 57848b8605Smrg/** 58848b8605Smrg * Used as a placeholder for buffer objects between glGenBuffers() and 59848b8605Smrg * glBindBuffer() so that glIsBuffer() can work correctly. 60848b8605Smrg */ 61848b8605Smrgstatic struct gl_buffer_object DummyBufferObject; 62848b8605Smrg 63848b8605Smrg 64848b8605Smrg/** 65848b8605Smrg * Return pointer to address of a buffer object target. 66848b8605Smrg * \param ctx the GL context 67848b8605Smrg * \param target the buffer object target to be retrieved. 68848b8605Smrg * \return pointer to pointer to the buffer object bound to \c target in the 69848b8605Smrg * specified context or \c NULL if \c target is invalid. 70848b8605Smrg */ 71848b8605Smrgstatic inline struct gl_buffer_object ** 72848b8605Smrgget_buffer_target(struct gl_context *ctx, GLenum target) 73848b8605Smrg{ 74848b8605Smrg /* Other targets are only supported in desktop OpenGL and OpenGL ES 3.0. 75848b8605Smrg */ 76848b8605Smrg if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx) 77848b8605Smrg && target != GL_ARRAY_BUFFER && target != GL_ELEMENT_ARRAY_BUFFER) 78848b8605Smrg return NULL; 79848b8605Smrg 80848b8605Smrg switch (target) { 81848b8605Smrg case GL_ARRAY_BUFFER_ARB: 82848b8605Smrg return &ctx->Array.ArrayBufferObj; 83848b8605Smrg case GL_ELEMENT_ARRAY_BUFFER_ARB: 84848b8605Smrg return &ctx->Array.VAO->IndexBufferObj; 85848b8605Smrg case GL_PIXEL_PACK_BUFFER_EXT: 86848b8605Smrg return &ctx->Pack.BufferObj; 87848b8605Smrg case GL_PIXEL_UNPACK_BUFFER_EXT: 88848b8605Smrg return &ctx->Unpack.BufferObj; 89848b8605Smrg case GL_COPY_READ_BUFFER: 90848b8605Smrg return &ctx->CopyReadBuffer; 91848b8605Smrg case GL_COPY_WRITE_BUFFER: 92848b8605Smrg return &ctx->CopyWriteBuffer; 93848b8605Smrg case GL_DRAW_INDIRECT_BUFFER: 94848b8605Smrg if (ctx->API == API_OPENGL_CORE && 95848b8605Smrg ctx->Extensions.ARB_draw_indirect) { 96848b8605Smrg return &ctx->DrawIndirectBuffer; 97848b8605Smrg } 98848b8605Smrg break; 99848b8605Smrg case GL_TRANSFORM_FEEDBACK_BUFFER: 100848b8605Smrg if (ctx->Extensions.EXT_transform_feedback) { 101848b8605Smrg return &ctx->TransformFeedback.CurrentBuffer; 102848b8605Smrg } 103848b8605Smrg break; 104848b8605Smrg case GL_TEXTURE_BUFFER: 105848b8605Smrg if (ctx->API == API_OPENGL_CORE && 106848b8605Smrg ctx->Extensions.ARB_texture_buffer_object) { 107848b8605Smrg return &ctx->Texture.BufferObject; 108848b8605Smrg } 109848b8605Smrg break; 110848b8605Smrg case GL_UNIFORM_BUFFER: 111848b8605Smrg if (ctx->Extensions.ARB_uniform_buffer_object) { 112848b8605Smrg return &ctx->UniformBuffer; 113848b8605Smrg } 114848b8605Smrg break; 115848b8605Smrg case GL_ATOMIC_COUNTER_BUFFER: 116848b8605Smrg if (ctx->Extensions.ARB_shader_atomic_counters) { 117848b8605Smrg return &ctx->AtomicBuffer; 118848b8605Smrg } 119848b8605Smrg break; 120848b8605Smrg default: 121848b8605Smrg return NULL; 122848b8605Smrg } 123848b8605Smrg return NULL; 124848b8605Smrg} 125848b8605Smrg 126848b8605Smrg 127848b8605Smrg/** 128848b8605Smrg * Get the buffer object bound to the specified target in a GL context. 129848b8605Smrg * \param ctx the GL context 130848b8605Smrg * \param target the buffer object target to be retrieved. 131848b8605Smrg * \param error the GL error to record if target is illegal. 132848b8605Smrg * \return pointer to the buffer object bound to \c target in the 133848b8605Smrg * specified context or \c NULL if \c target is invalid. 134848b8605Smrg */ 135848b8605Smrgstatic inline struct gl_buffer_object * 136848b8605Smrgget_buffer(struct gl_context *ctx, const char *func, GLenum target, 137848b8605Smrg GLenum error) 138848b8605Smrg{ 139848b8605Smrg struct gl_buffer_object **bufObj = get_buffer_target(ctx, target); 140848b8605Smrg 141848b8605Smrg if (!bufObj) { 142848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func); 143848b8605Smrg return NULL; 144848b8605Smrg } 145848b8605Smrg 146848b8605Smrg if (!_mesa_is_bufferobj(*bufObj)) { 147848b8605Smrg _mesa_error(ctx, error, "%s(no buffer bound)", func); 148848b8605Smrg return NULL; 149848b8605Smrg } 150848b8605Smrg 151848b8605Smrg return *bufObj; 152848b8605Smrg} 153848b8605Smrg 154848b8605Smrg 155848b8605Smrg/** 156848b8605Smrg * Convert a GLbitfield describing the mapped buffer access flags 157848b8605Smrg * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY. 158848b8605Smrg */ 159848b8605Smrgstatic GLenum 160848b8605Smrgsimplified_access_mode(struct gl_context *ctx, GLbitfield access) 161848b8605Smrg{ 162848b8605Smrg const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; 163848b8605Smrg if ((access & rwFlags) == rwFlags) 164848b8605Smrg return GL_READ_WRITE; 165848b8605Smrg if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT) 166848b8605Smrg return GL_READ_ONLY; 167848b8605Smrg if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT) 168848b8605Smrg return GL_WRITE_ONLY; 169848b8605Smrg 170848b8605Smrg /* Otherwise, AccessFlags is zero (the default state). 171848b8605Smrg * 172848b8605Smrg * Table 2.6 on page 31 (page 44 of the PDF) of the OpenGL 1.5 spec says: 173848b8605Smrg * 174848b8605Smrg * Name Type Initial Value Legal Values 175848b8605Smrg * ... ... ... ... 176848b8605Smrg * BUFFER_ACCESS enum READ_WRITE READ_ONLY, WRITE_ONLY 177848b8605Smrg * READ_WRITE 178848b8605Smrg * 179848b8605Smrg * However, table 6.8 in the GL_OES_mapbuffer extension says: 180848b8605Smrg * 181848b8605Smrg * Get Value Type Get Command Value Description 182848b8605Smrg * --------- ---- ----------- ----- ----------- 183848b8605Smrg * BUFFER_ACCESS_OES Z1 GetBufferParameteriv WRITE_ONLY_OES buffer map flag 184848b8605Smrg * 185848b8605Smrg * The difference is because GL_OES_mapbuffer only supports mapping buffers 186848b8605Smrg * write-only. 187848b8605Smrg */ 188848b8605Smrg assert(access == 0); 189848b8605Smrg 190848b8605Smrg return _mesa_is_gles(ctx) ? GL_WRITE_ONLY : GL_READ_WRITE; 191848b8605Smrg} 192848b8605Smrg 193848b8605Smrg 194848b8605Smrg/** 195848b8605Smrg * Test if the buffer is mapped, and if so, if the mapped range overlaps the 196848b8605Smrg * given range. 197848b8605Smrg * The regions do not overlap if and only if the end of the given 198848b8605Smrg * region is before the mapped region or the start of the given region 199848b8605Smrg * is after the mapped region. 200848b8605Smrg * 201848b8605Smrg * \param obj Buffer object target on which to operate. 202848b8605Smrg * \param offset Offset of the first byte of the subdata range. 203848b8605Smrg * \param size Size, in bytes, of the subdata range. 204848b8605Smrg * \return true if ranges overlap, false otherwise 205848b8605Smrg * 206848b8605Smrg */ 207848b8605Smrgstatic bool 208848b8605Smrgbufferobj_range_mapped(const struct gl_buffer_object *obj, 209848b8605Smrg GLintptr offset, GLsizeiptr size) 210848b8605Smrg{ 211848b8605Smrg if (_mesa_bufferobj_mapped(obj, MAP_USER)) { 212848b8605Smrg const GLintptr end = offset + size; 213848b8605Smrg const GLintptr mapEnd = obj->Mappings[MAP_USER].Offset + 214848b8605Smrg obj->Mappings[MAP_USER].Length; 215848b8605Smrg 216848b8605Smrg if (!(end <= obj->Mappings[MAP_USER].Offset || offset >= mapEnd)) { 217848b8605Smrg return true; 218848b8605Smrg } 219848b8605Smrg } 220848b8605Smrg return false; 221848b8605Smrg} 222848b8605Smrg 223848b8605Smrg 224848b8605Smrg/** 225848b8605Smrg * Tests the subdata range parameters and sets the GL error code for 226848b8605Smrg * \c glBufferSubDataARB, \c glGetBufferSubDataARB and 227848b8605Smrg * \c glClearBufferSubData. 228848b8605Smrg * 229848b8605Smrg * \param ctx GL context. 230848b8605Smrg * \param target Buffer object target on which to operate. 231848b8605Smrg * \param offset Offset of the first byte of the subdata range. 232848b8605Smrg * \param size Size, in bytes, of the subdata range. 233848b8605Smrg * \param mappedRange If true, checks if an overlapping range is mapped. 234848b8605Smrg * If false, checks if buffer is mapped. 235848b8605Smrg * \param errorNoBuffer Error code if no buffer is bound to target. 236848b8605Smrg * \param caller Name of calling function for recording errors. 237848b8605Smrg * \return A pointer to the buffer object bound to \c target in the 238848b8605Smrg * specified context or \c NULL if any of the parameter or state 239848b8605Smrg * conditions are invalid. 240848b8605Smrg * 241848b8605Smrg * \sa glBufferSubDataARB, glGetBufferSubDataARB, glClearBufferSubData 242848b8605Smrg */ 243848b8605Smrgstatic struct gl_buffer_object * 244848b8605Smrgbuffer_object_subdata_range_good(struct gl_context * ctx, GLenum target, 245848b8605Smrg GLintptrARB offset, GLsizeiptrARB size, 246848b8605Smrg bool mappedRange, GLenum errorNoBuffer, 247848b8605Smrg const char *caller) 248848b8605Smrg{ 249848b8605Smrg struct gl_buffer_object *bufObj; 250848b8605Smrg 251848b8605Smrg if (size < 0) { 252848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller); 253848b8605Smrg return NULL; 254848b8605Smrg } 255848b8605Smrg 256848b8605Smrg if (offset < 0) { 257848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller); 258848b8605Smrg return NULL; 259848b8605Smrg } 260848b8605Smrg 261848b8605Smrg bufObj = get_buffer(ctx, caller, target, errorNoBuffer); 262848b8605Smrg if (!bufObj) 263848b8605Smrg return NULL; 264848b8605Smrg 265848b8605Smrg if (offset + size > bufObj->Size) { 266848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 267848b8605Smrg "%s(offset %lu + size %lu > buffer size %lu)", caller, 268848b8605Smrg (unsigned long) offset, 269848b8605Smrg (unsigned long) size, 270848b8605Smrg (unsigned long) bufObj->Size); 271848b8605Smrg return NULL; 272848b8605Smrg } 273848b8605Smrg 274848b8605Smrg if (bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_PERSISTENT_BIT) 275848b8605Smrg return bufObj; 276848b8605Smrg 277848b8605Smrg if (mappedRange) { 278848b8605Smrg if (bufferobj_range_mapped(bufObj, offset, size)) { 279848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); 280848b8605Smrg return NULL; 281848b8605Smrg } 282848b8605Smrg } 283848b8605Smrg else { 284848b8605Smrg if (_mesa_bufferobj_mapped(bufObj, MAP_USER)) { 285848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); 286848b8605Smrg return NULL; 287848b8605Smrg } 288848b8605Smrg } 289848b8605Smrg 290848b8605Smrg return bufObj; 291848b8605Smrg} 292848b8605Smrg 293848b8605Smrg 294848b8605Smrg/** 295848b8605Smrg * Test the format and type parameters and set the GL error code for 296848b8605Smrg * \c glClearBufferData and \c glClearBufferSubData. 297848b8605Smrg * 298848b8605Smrg * \param ctx GL context. 299848b8605Smrg * \param internalformat Format to which the data is to be converted. 300848b8605Smrg * \param format Format of the supplied data. 301848b8605Smrg * \param type Type of the supplied data. 302848b8605Smrg * \param caller Name of calling function for recording errors. 303848b8605Smrg * \return If internalformat, format and type are legal the mesa_format 304848b8605Smrg * corresponding to internalformat, otherwise MESA_FORMAT_NONE. 305848b8605Smrg * 306848b8605Smrg * \sa glClearBufferData and glClearBufferSubData 307848b8605Smrg */ 308848b8605Smrgstatic mesa_format 309848b8605Smrgvalidate_clear_buffer_format(struct gl_context *ctx, 310848b8605Smrg GLenum internalformat, 311848b8605Smrg GLenum format, GLenum type, 312848b8605Smrg const char *caller) 313848b8605Smrg{ 314848b8605Smrg mesa_format mesaFormat; 315848b8605Smrg GLenum errorFormatType; 316848b8605Smrg 317848b8605Smrg mesaFormat = _mesa_validate_texbuffer_format(ctx, internalformat); 318848b8605Smrg if (mesaFormat == MESA_FORMAT_NONE) { 319848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, 320848b8605Smrg "%s(invalid internalformat)", caller); 321848b8605Smrg return MESA_FORMAT_NONE; 322848b8605Smrg } 323848b8605Smrg 324848b8605Smrg /* NOTE: not mentioned in ARB_clear_buffer_object but according to 325848b8605Smrg * EXT_texture_integer there is no conversion between integer and 326848b8605Smrg * non-integer formats 327848b8605Smrg */ 328848b8605Smrg if (_mesa_is_enum_format_signed_int(format) != 329848b8605Smrg _mesa_is_format_integer_color(mesaFormat)) { 330848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 331848b8605Smrg "%s(integer vs non-integer)", caller); 332848b8605Smrg return MESA_FORMAT_NONE; 333848b8605Smrg } 334848b8605Smrg 335848b8605Smrg if (!_mesa_is_color_format(format)) { 336848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, 337848b8605Smrg "%s(format is not a color format)", caller); 338848b8605Smrg return MESA_FORMAT_NONE; 339848b8605Smrg } 340848b8605Smrg 341848b8605Smrg errorFormatType = _mesa_error_check_format_and_type(ctx, format, type); 342848b8605Smrg if (errorFormatType != GL_NO_ERROR) { 343848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, 344848b8605Smrg "%s(invalid format or type)", caller); 345848b8605Smrg return MESA_FORMAT_NONE; 346848b8605Smrg } 347848b8605Smrg 348848b8605Smrg return mesaFormat; 349848b8605Smrg} 350848b8605Smrg 351848b8605Smrg 352848b8605Smrg/** 353848b8605Smrg * Convert user-specified clear value to the specified internal format. 354848b8605Smrg * 355848b8605Smrg * \param ctx GL context. 356848b8605Smrg * \param internalformat Format to which the data is converted. 357848b8605Smrg * \param clearValue Points to the converted clear value. 358848b8605Smrg * \param format Format of the supplied data. 359848b8605Smrg * \param type Type of the supplied data. 360848b8605Smrg * \param data Data which is to be converted to internalformat. 361848b8605Smrg * \param caller Name of calling function for recording errors. 362848b8605Smrg * \return true if data could be converted, false otherwise. 363848b8605Smrg * 364848b8605Smrg * \sa glClearBufferData, glClearBufferSubData 365848b8605Smrg */ 366848b8605Smrgstatic bool 367848b8605Smrgconvert_clear_buffer_data(struct gl_context *ctx, 368848b8605Smrg mesa_format internalformat, 369848b8605Smrg GLubyte *clearValue, GLenum format, GLenum type, 370848b8605Smrg const GLvoid *data, const char *caller) 371848b8605Smrg{ 372848b8605Smrg GLenum internalformatBase = _mesa_get_format_base_format(internalformat); 373848b8605Smrg 374848b8605Smrg if (_mesa_texstore(ctx, 1, internalformatBase, internalformat, 375848b8605Smrg 0, &clearValue, 1, 1, 1, 376848b8605Smrg format, type, data, &ctx->Unpack)) { 377848b8605Smrg return true; 378848b8605Smrg } 379848b8605Smrg else { 380848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller); 381848b8605Smrg return false; 382848b8605Smrg } 383848b8605Smrg} 384848b8605Smrg 385848b8605Smrg 386848b8605Smrg/** 387848b8605Smrg * Allocate and initialize a new buffer object. 388848b8605Smrg * 389848b8605Smrg * Default callback for the \c dd_function_table::NewBufferObject() hook. 390848b8605Smrg */ 391848b8605Smrgstatic struct gl_buffer_object * 392848b8605Smrg_mesa_new_buffer_object( struct gl_context *ctx, GLuint name, GLenum target ) 393848b8605Smrg{ 394848b8605Smrg struct gl_buffer_object *obj; 395848b8605Smrg 396848b8605Smrg (void) ctx; 397848b8605Smrg 398848b8605Smrg obj = MALLOC_STRUCT(gl_buffer_object); 399848b8605Smrg _mesa_initialize_buffer_object(ctx, obj, name, target); 400848b8605Smrg return obj; 401848b8605Smrg} 402848b8605Smrg 403848b8605Smrg 404848b8605Smrg/** 405848b8605Smrg * Delete a buffer object. 406848b8605Smrg * 407848b8605Smrg * Default callback for the \c dd_function_table::DeleteBuffer() hook. 408848b8605Smrg */ 409848b8605Smrgstatic void 410848b8605Smrg_mesa_delete_buffer_object(struct gl_context *ctx, 411848b8605Smrg struct gl_buffer_object *bufObj) 412848b8605Smrg{ 413848b8605Smrg (void) ctx; 414848b8605Smrg 415848b8605Smrg _mesa_align_free(bufObj->Data); 416848b8605Smrg 417848b8605Smrg /* assign strange values here to help w/ debugging */ 418848b8605Smrg bufObj->RefCount = -1000; 419848b8605Smrg bufObj->Name = ~0; 420848b8605Smrg 421848b8605Smrg mtx_destroy(&bufObj->Mutex); 422848b8605Smrg free(bufObj->Label); 423848b8605Smrg free(bufObj); 424848b8605Smrg} 425848b8605Smrg 426848b8605Smrg 427848b8605Smrg 428848b8605Smrg/** 429848b8605Smrg * Set ptr to bufObj w/ reference counting. 430848b8605Smrg * This is normally only called from the _mesa_reference_buffer_object() macro 431848b8605Smrg * when there's a real pointer change. 432848b8605Smrg */ 433848b8605Smrgvoid 434848b8605Smrg_mesa_reference_buffer_object_(struct gl_context *ctx, 435848b8605Smrg struct gl_buffer_object **ptr, 436848b8605Smrg struct gl_buffer_object *bufObj) 437848b8605Smrg{ 438848b8605Smrg if (*ptr) { 439848b8605Smrg /* Unreference the old buffer */ 440848b8605Smrg GLboolean deleteFlag = GL_FALSE; 441848b8605Smrg struct gl_buffer_object *oldObj = *ptr; 442848b8605Smrg 443848b8605Smrg mtx_lock(&oldObj->Mutex); 444848b8605Smrg ASSERT(oldObj->RefCount > 0); 445848b8605Smrg oldObj->RefCount--; 446848b8605Smrg#if 0 447848b8605Smrg printf("BufferObj %p %d DECR to %d\n", 448848b8605Smrg (void *) oldObj, oldObj->Name, oldObj->RefCount); 449848b8605Smrg#endif 450848b8605Smrg deleteFlag = (oldObj->RefCount == 0); 451848b8605Smrg mtx_unlock(&oldObj->Mutex); 452848b8605Smrg 453848b8605Smrg if (deleteFlag) { 454848b8605Smrg 455848b8605Smrg /* some sanity checking: don't delete a buffer still in use */ 456848b8605Smrg#if 0 457848b8605Smrg /* unfortunately, these tests are invalid during context tear-down */ 458848b8605Smrg ASSERT(ctx->Array.ArrayBufferObj != bufObj); 459848b8605Smrg ASSERT(ctx->Array.VAO->IndexBufferObj != bufObj); 460848b8605Smrg ASSERT(ctx->Array.VAO->Vertex.BufferObj != bufObj); 461848b8605Smrg#endif 462848b8605Smrg 463848b8605Smrg ASSERT(ctx->Driver.DeleteBuffer); 464848b8605Smrg ctx->Driver.DeleteBuffer(ctx, oldObj); 465848b8605Smrg } 466848b8605Smrg 467848b8605Smrg *ptr = NULL; 468848b8605Smrg } 469848b8605Smrg ASSERT(!*ptr); 470848b8605Smrg 471848b8605Smrg if (bufObj) { 472848b8605Smrg /* reference new buffer */ 473848b8605Smrg mtx_lock(&bufObj->Mutex); 474848b8605Smrg if (bufObj->RefCount == 0) { 475848b8605Smrg /* this buffer's being deleted (look just above) */ 476848b8605Smrg /* Not sure this can every really happen. Warn if it does. */ 477848b8605Smrg _mesa_problem(NULL, "referencing deleted buffer object"); 478848b8605Smrg *ptr = NULL; 479848b8605Smrg } 480848b8605Smrg else { 481848b8605Smrg bufObj->RefCount++; 482848b8605Smrg#if 0 483848b8605Smrg printf("BufferObj %p %d INCR to %d\n", 484848b8605Smrg (void *) bufObj, bufObj->Name, bufObj->RefCount); 485848b8605Smrg#endif 486848b8605Smrg *ptr = bufObj; 487848b8605Smrg } 488848b8605Smrg mtx_unlock(&bufObj->Mutex); 489848b8605Smrg } 490848b8605Smrg} 491848b8605Smrg 492848b8605Smrg 493848b8605Smrg/** 494848b8605Smrg * Initialize a buffer object to default values. 495848b8605Smrg */ 496848b8605Smrgvoid 497848b8605Smrg_mesa_initialize_buffer_object( struct gl_context *ctx, 498848b8605Smrg struct gl_buffer_object *obj, 499848b8605Smrg GLuint name, GLenum target ) 500848b8605Smrg{ 501848b8605Smrg (void) target; 502848b8605Smrg 503848b8605Smrg memset(obj, 0, sizeof(struct gl_buffer_object)); 504848b8605Smrg mtx_init(&obj->Mutex, mtx_plain); 505848b8605Smrg obj->RefCount = 1; 506848b8605Smrg obj->Name = name; 507848b8605Smrg obj->Usage = GL_STATIC_DRAW_ARB; 508848b8605Smrg} 509848b8605Smrg 510848b8605Smrg 511848b8605Smrg 512848b8605Smrg/** 513848b8605Smrg * Callback called from _mesa_HashWalk() 514848b8605Smrg */ 515848b8605Smrgstatic void 516848b8605Smrgcount_buffer_size(GLuint key, void *data, void *userData) 517848b8605Smrg{ 518848b8605Smrg const struct gl_buffer_object *bufObj = 519848b8605Smrg (const struct gl_buffer_object *) data; 520848b8605Smrg GLuint *total = (GLuint *) userData; 521848b8605Smrg 522848b8605Smrg *total = *total + bufObj->Size; 523848b8605Smrg} 524848b8605Smrg 525848b8605Smrg 526848b8605Smrg/** 527848b8605Smrg * Compute total size (in bytes) of all buffer objects for the given context. 528848b8605Smrg * For debugging purposes. 529848b8605Smrg */ 530848b8605SmrgGLuint 531848b8605Smrg_mesa_total_buffer_object_memory(struct gl_context *ctx) 532848b8605Smrg{ 533848b8605Smrg GLuint total = 0; 534848b8605Smrg 535848b8605Smrg _mesa_HashWalk(ctx->Shared->BufferObjects, count_buffer_size, &total); 536848b8605Smrg 537848b8605Smrg return total; 538848b8605Smrg} 539848b8605Smrg 540848b8605Smrg 541848b8605Smrg/** 542848b8605Smrg * Allocate space for and store data in a buffer object. Any data that was 543848b8605Smrg * previously stored in the buffer object is lost. If \c data is \c NULL, 544848b8605Smrg * memory will be allocated, but no copy will occur. 545848b8605Smrg * 546848b8605Smrg * This is the default callback for \c dd_function_table::BufferData() 547848b8605Smrg * Note that all GL error checking will have been done already. 548848b8605Smrg * 549848b8605Smrg * \param ctx GL context. 550848b8605Smrg * \param target Buffer object target on which to operate. 551848b8605Smrg * \param size Size, in bytes, of the new data store. 552848b8605Smrg * \param data Pointer to the data to store in the buffer object. This 553848b8605Smrg * pointer may be \c NULL. 554848b8605Smrg * \param usage Hints about how the data will be used. 555848b8605Smrg * \param bufObj Object to be used. 556848b8605Smrg * 557848b8605Smrg * \return GL_TRUE for success, GL_FALSE for failure 558848b8605Smrg * \sa glBufferDataARB, dd_function_table::BufferData. 559848b8605Smrg */ 560848b8605Smrgstatic GLboolean 561848b8605Smrg_mesa_buffer_data( struct gl_context *ctx, GLenum target, GLsizeiptrARB size, 562848b8605Smrg const GLvoid * data, GLenum usage, GLenum storageFlags, 563848b8605Smrg struct gl_buffer_object * bufObj ) 564848b8605Smrg{ 565848b8605Smrg void * new_data; 566848b8605Smrg 567848b8605Smrg (void) target; 568848b8605Smrg 569848b8605Smrg _mesa_align_free( bufObj->Data ); 570848b8605Smrg 571848b8605Smrg new_data = _mesa_align_malloc( size, ctx->Const.MinMapBufferAlignment ); 572848b8605Smrg if (new_data) { 573848b8605Smrg bufObj->Data = (GLubyte *) new_data; 574848b8605Smrg bufObj->Size = size; 575848b8605Smrg bufObj->Usage = usage; 576848b8605Smrg bufObj->StorageFlags = storageFlags; 577848b8605Smrg 578848b8605Smrg if (data) { 579848b8605Smrg memcpy( bufObj->Data, data, size ); 580848b8605Smrg } 581848b8605Smrg 582848b8605Smrg return GL_TRUE; 583848b8605Smrg } 584848b8605Smrg else { 585848b8605Smrg return GL_FALSE; 586848b8605Smrg } 587848b8605Smrg} 588848b8605Smrg 589848b8605Smrg 590848b8605Smrg/** 591848b8605Smrg * Replace data in a subrange of buffer object. If the data range 592848b8605Smrg * specified by \c size + \c offset extends beyond the end of the buffer or 593848b8605Smrg * if \c data is \c NULL, no copy is performed. 594848b8605Smrg * 595848b8605Smrg * This is the default callback for \c dd_function_table::BufferSubData() 596848b8605Smrg * Note that all GL error checking will have been done already. 597848b8605Smrg * 598848b8605Smrg * \param ctx GL context. 599848b8605Smrg * \param offset Offset of the first byte to be modified. 600848b8605Smrg * \param size Size, in bytes, of the data range. 601848b8605Smrg * \param data Pointer to the data to store in the buffer object. 602848b8605Smrg * \param bufObj Object to be used. 603848b8605Smrg * 604848b8605Smrg * \sa glBufferSubDataARB, dd_function_table::BufferSubData. 605848b8605Smrg */ 606848b8605Smrgstatic void 607848b8605Smrg_mesa_buffer_subdata( struct gl_context *ctx, GLintptrARB offset, 608848b8605Smrg GLsizeiptrARB size, const GLvoid * data, 609848b8605Smrg struct gl_buffer_object * bufObj ) 610848b8605Smrg{ 611848b8605Smrg (void) ctx; 612848b8605Smrg 613848b8605Smrg /* this should have been caught in _mesa_BufferSubData() */ 614848b8605Smrg ASSERT(size + offset <= bufObj->Size); 615848b8605Smrg 616848b8605Smrg if (bufObj->Data) { 617848b8605Smrg memcpy( (GLubyte *) bufObj->Data + offset, data, size ); 618848b8605Smrg } 619848b8605Smrg} 620848b8605Smrg 621848b8605Smrg 622848b8605Smrg/** 623848b8605Smrg * Retrieve data from a subrange of buffer object. If the data range 624848b8605Smrg * specified by \c size + \c offset extends beyond the end of the buffer or 625848b8605Smrg * if \c data is \c NULL, no copy is performed. 626848b8605Smrg * 627848b8605Smrg * This is the default callback for \c dd_function_table::GetBufferSubData() 628848b8605Smrg * Note that all GL error checking will have been done already. 629848b8605Smrg * 630848b8605Smrg * \param ctx GL context. 631848b8605Smrg * \param target Buffer object target on which to operate. 632848b8605Smrg * \param offset Offset of the first byte to be fetched. 633848b8605Smrg * \param size Size, in bytes, of the data range. 634848b8605Smrg * \param data Destination for data 635848b8605Smrg * \param bufObj Object to be used. 636848b8605Smrg * 637848b8605Smrg * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData. 638848b8605Smrg */ 639848b8605Smrgstatic void 640848b8605Smrg_mesa_buffer_get_subdata( struct gl_context *ctx, GLintptrARB offset, 641848b8605Smrg GLsizeiptrARB size, GLvoid * data, 642848b8605Smrg struct gl_buffer_object * bufObj ) 643848b8605Smrg{ 644848b8605Smrg (void) ctx; 645848b8605Smrg 646848b8605Smrg if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) { 647848b8605Smrg memcpy( data, (GLubyte *) bufObj->Data + offset, size ); 648848b8605Smrg } 649848b8605Smrg} 650848b8605Smrg 651848b8605Smrg 652848b8605Smrg/** 653848b8605Smrg * Clear a subrange of the buffer object with copies of the supplied data. 654848b8605Smrg * If data is NULL the buffer is filled with zeros. 655848b8605Smrg * 656848b8605Smrg * This is the default callback for \c dd_function_table::ClearBufferSubData() 657848b8605Smrg * Note that all GL error checking will have been done already. 658848b8605Smrg * 659848b8605Smrg * \param ctx GL context. 660848b8605Smrg * \param offset Offset of the first byte to be cleared. 661848b8605Smrg * \param size Size, in bytes, of the to be cleared range. 662848b8605Smrg * \param clearValue Source of the data. 663848b8605Smrg * \param clearValueSize Size, in bytes, of the supplied data. 664848b8605Smrg * \param bufObj Object to be cleared. 665848b8605Smrg * 666848b8605Smrg * \sa glClearBufferSubData, glClearBufferData and 667848b8605Smrg * dd_function_table::ClearBufferSubData. 668848b8605Smrg */ 669848b8605Smrgvoid 670848b8605Smrg_mesa_buffer_clear_subdata(struct gl_context *ctx, 671848b8605Smrg GLintptr offset, GLsizeiptr size, 672848b8605Smrg const GLvoid *clearValue, 673848b8605Smrg GLsizeiptr clearValueSize, 674848b8605Smrg struct gl_buffer_object *bufObj) 675848b8605Smrg{ 676848b8605Smrg GLsizeiptr i; 677848b8605Smrg GLubyte *dest; 678848b8605Smrg 679848b8605Smrg ASSERT(ctx->Driver.MapBufferRange); 680848b8605Smrg dest = ctx->Driver.MapBufferRange(ctx, offset, size, 681848b8605Smrg GL_MAP_WRITE_BIT | 682848b8605Smrg GL_MAP_INVALIDATE_RANGE_BIT, 683848b8605Smrg bufObj, MAP_INTERNAL); 684848b8605Smrg 685848b8605Smrg if (!dest) { 686848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClearBuffer[Sub]Data"); 687848b8605Smrg return; 688848b8605Smrg } 689848b8605Smrg 690848b8605Smrg if (clearValue == NULL) { 691848b8605Smrg /* Clear with zeros, per the spec */ 692848b8605Smrg memset(dest, 0, size); 693848b8605Smrg ctx->Driver.UnmapBuffer(ctx, bufObj, MAP_INTERNAL); 694848b8605Smrg return; 695848b8605Smrg } 696848b8605Smrg 697848b8605Smrg for (i = 0; i < size/clearValueSize; ++i) { 698848b8605Smrg memcpy(dest, clearValue, clearValueSize); 699848b8605Smrg dest += clearValueSize; 700848b8605Smrg } 701848b8605Smrg 702848b8605Smrg ctx->Driver.UnmapBuffer(ctx, bufObj, MAP_INTERNAL); 703848b8605Smrg} 704848b8605Smrg 705848b8605Smrg 706848b8605Smrg/** 707848b8605Smrg * Default fallback for \c dd_function_table::MapBufferRange(). 708848b8605Smrg * Called via glMapBufferRange(). 709848b8605Smrg */ 710848b8605Smrgstatic void * 711848b8605Smrg_mesa_buffer_map_range( struct gl_context *ctx, GLintptr offset, 712848b8605Smrg GLsizeiptr length, GLbitfield access, 713848b8605Smrg struct gl_buffer_object *bufObj, 714848b8605Smrg gl_map_buffer_index index) 715848b8605Smrg{ 716848b8605Smrg (void) ctx; 717848b8605Smrg assert(!_mesa_bufferobj_mapped(bufObj, index)); 718848b8605Smrg /* Just return a direct pointer to the data */ 719848b8605Smrg bufObj->Mappings[index].Pointer = bufObj->Data + offset; 720848b8605Smrg bufObj->Mappings[index].Length = length; 721848b8605Smrg bufObj->Mappings[index].Offset = offset; 722848b8605Smrg bufObj->Mappings[index].AccessFlags = access; 723848b8605Smrg return bufObj->Mappings[index].Pointer; 724848b8605Smrg} 725848b8605Smrg 726848b8605Smrg 727848b8605Smrg/** 728848b8605Smrg * Default fallback for \c dd_function_table::FlushMappedBufferRange(). 729848b8605Smrg * Called via glFlushMappedBufferRange(). 730848b8605Smrg */ 731848b8605Smrgstatic void 732848b8605Smrg_mesa_buffer_flush_mapped_range( struct gl_context *ctx, 733848b8605Smrg GLintptr offset, GLsizeiptr length, 734848b8605Smrg struct gl_buffer_object *obj, 735848b8605Smrg gl_map_buffer_index index) 736848b8605Smrg{ 737848b8605Smrg (void) ctx; 738848b8605Smrg (void) offset; 739848b8605Smrg (void) length; 740848b8605Smrg (void) obj; 741848b8605Smrg /* no-op */ 742848b8605Smrg} 743848b8605Smrg 744848b8605Smrg 745848b8605Smrg/** 746848b8605Smrg * Default callback for \c dd_function_table::MapBuffer(). 747848b8605Smrg * 748848b8605Smrg * The input parameters will have been already tested for errors. 749848b8605Smrg * 750848b8605Smrg * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer 751848b8605Smrg */ 752848b8605Smrgstatic GLboolean 753848b8605Smrg_mesa_buffer_unmap(struct gl_context *ctx, struct gl_buffer_object *bufObj, 754848b8605Smrg gl_map_buffer_index index) 755848b8605Smrg{ 756848b8605Smrg (void) ctx; 757848b8605Smrg /* XXX we might assert here that bufObj->Pointer is non-null */ 758848b8605Smrg bufObj->Mappings[index].Pointer = NULL; 759848b8605Smrg bufObj->Mappings[index].Length = 0; 760848b8605Smrg bufObj->Mappings[index].Offset = 0; 761848b8605Smrg bufObj->Mappings[index].AccessFlags = 0x0; 762848b8605Smrg return GL_TRUE; 763848b8605Smrg} 764848b8605Smrg 765848b8605Smrg 766848b8605Smrg/** 767848b8605Smrg * Default fallback for \c dd_function_table::CopyBufferSubData(). 768848b8605Smrg * Called via glCopyBufferSubData(). 769848b8605Smrg */ 770848b8605Smrgstatic void 771848b8605Smrg_mesa_copy_buffer_subdata(struct gl_context *ctx, 772848b8605Smrg struct gl_buffer_object *src, 773848b8605Smrg struct gl_buffer_object *dst, 774848b8605Smrg GLintptr readOffset, GLintptr writeOffset, 775848b8605Smrg GLsizeiptr size) 776848b8605Smrg{ 777848b8605Smrg GLubyte *srcPtr, *dstPtr; 778848b8605Smrg 779848b8605Smrg if (src == dst) { 780848b8605Smrg srcPtr = dstPtr = ctx->Driver.MapBufferRange(ctx, 0, src->Size, 781848b8605Smrg GL_MAP_READ_BIT | 782848b8605Smrg GL_MAP_WRITE_BIT, src, 783848b8605Smrg MAP_INTERNAL); 784848b8605Smrg 785848b8605Smrg if (!srcPtr) 786848b8605Smrg return; 787848b8605Smrg 788848b8605Smrg srcPtr += readOffset; 789848b8605Smrg dstPtr += writeOffset; 790848b8605Smrg } else { 791848b8605Smrg srcPtr = ctx->Driver.MapBufferRange(ctx, readOffset, size, 792848b8605Smrg GL_MAP_READ_BIT, src, 793848b8605Smrg MAP_INTERNAL); 794848b8605Smrg dstPtr = ctx->Driver.MapBufferRange(ctx, writeOffset, size, 795848b8605Smrg (GL_MAP_WRITE_BIT | 796848b8605Smrg GL_MAP_INVALIDATE_RANGE_BIT), dst, 797848b8605Smrg MAP_INTERNAL); 798848b8605Smrg } 799848b8605Smrg 800848b8605Smrg /* Note: the src and dst regions will never overlap. Trying to do so 801848b8605Smrg * would generate GL_INVALID_VALUE earlier. 802848b8605Smrg */ 803848b8605Smrg if (srcPtr && dstPtr) 804848b8605Smrg memcpy(dstPtr, srcPtr, size); 805848b8605Smrg 806848b8605Smrg ctx->Driver.UnmapBuffer(ctx, src, MAP_INTERNAL); 807848b8605Smrg if (dst != src) 808848b8605Smrg ctx->Driver.UnmapBuffer(ctx, dst, MAP_INTERNAL); 809848b8605Smrg} 810848b8605Smrg 811848b8605Smrg 812848b8605Smrg 813848b8605Smrg/** 814848b8605Smrg * Initialize the state associated with buffer objects 815848b8605Smrg */ 816848b8605Smrgvoid 817848b8605Smrg_mesa_init_buffer_objects( struct gl_context *ctx ) 818848b8605Smrg{ 819848b8605Smrg GLuint i; 820848b8605Smrg 821848b8605Smrg memset(&DummyBufferObject, 0, sizeof(DummyBufferObject)); 822848b8605Smrg mtx_init(&DummyBufferObject.Mutex, mtx_plain); 823848b8605Smrg DummyBufferObject.RefCount = 1000*1000*1000; /* never delete */ 824848b8605Smrg 825848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, 826848b8605Smrg ctx->Shared->NullBufferObj); 827848b8605Smrg 828848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, 829848b8605Smrg ctx->Shared->NullBufferObj); 830848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, 831848b8605Smrg ctx->Shared->NullBufferObj); 832848b8605Smrg 833848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, 834848b8605Smrg ctx->Shared->NullBufferObj); 835848b8605Smrg 836848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, 837848b8605Smrg ctx->Shared->NullBufferObj); 838848b8605Smrg 839848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->DrawIndirectBuffer, 840848b8605Smrg ctx->Shared->NullBufferObj); 841848b8605Smrg 842848b8605Smrg for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) { 843848b8605Smrg _mesa_reference_buffer_object(ctx, 844848b8605Smrg &ctx->UniformBufferBindings[i].BufferObject, 845848b8605Smrg ctx->Shared->NullBufferObj); 846848b8605Smrg ctx->UniformBufferBindings[i].Offset = -1; 847848b8605Smrg ctx->UniformBufferBindings[i].Size = -1; 848848b8605Smrg } 849848b8605Smrg 850848b8605Smrg for (i = 0; i < MAX_COMBINED_ATOMIC_BUFFERS; i++) { 851848b8605Smrg _mesa_reference_buffer_object(ctx, 852848b8605Smrg &ctx->AtomicBufferBindings[i].BufferObject, 853848b8605Smrg ctx->Shared->NullBufferObj); 854848b8605Smrg ctx->AtomicBufferBindings[i].Offset = -1; 855848b8605Smrg ctx->AtomicBufferBindings[i].Size = -1; 856848b8605Smrg } 857848b8605Smrg} 858848b8605Smrg 859848b8605Smrg 860848b8605Smrgvoid 861848b8605Smrg_mesa_free_buffer_objects( struct gl_context *ctx ) 862848b8605Smrg{ 863848b8605Smrg GLuint i; 864848b8605Smrg 865848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL); 866848b8605Smrg 867848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, NULL); 868848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, NULL); 869848b8605Smrg 870848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, NULL); 871848b8605Smrg 872848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, NULL); 873848b8605Smrg 874848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->DrawIndirectBuffer, NULL); 875848b8605Smrg 876848b8605Smrg for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) { 877848b8605Smrg _mesa_reference_buffer_object(ctx, 878848b8605Smrg &ctx->UniformBufferBindings[i].BufferObject, 879848b8605Smrg NULL); 880848b8605Smrg } 881848b8605Smrg 882848b8605Smrg for (i = 0; i < MAX_COMBINED_ATOMIC_BUFFERS; i++) { 883848b8605Smrg _mesa_reference_buffer_object(ctx, 884848b8605Smrg &ctx->AtomicBufferBindings[i].BufferObject, 885848b8605Smrg NULL); 886848b8605Smrg } 887848b8605Smrg 888848b8605Smrg} 889848b8605Smrg 890848b8605Smrgbool 891848b8605Smrg_mesa_handle_bind_buffer_gen(struct gl_context *ctx, 892848b8605Smrg GLenum target, 893848b8605Smrg GLuint buffer, 894848b8605Smrg struct gl_buffer_object **buf_handle, 895848b8605Smrg const char *caller) 896848b8605Smrg{ 897848b8605Smrg struct gl_buffer_object *buf = *buf_handle; 898848b8605Smrg 899848b8605Smrg if (!buf && ctx->API == API_OPENGL_CORE) { 900848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", caller); 901848b8605Smrg return false; 902848b8605Smrg } 903848b8605Smrg 904848b8605Smrg if (!buf || buf == &DummyBufferObject) { 905848b8605Smrg /* If this is a new buffer object id, or one which was generated but 906848b8605Smrg * never used before, allocate a buffer object now. 907848b8605Smrg */ 908848b8605Smrg ASSERT(ctx->Driver.NewBufferObject); 909848b8605Smrg buf = ctx->Driver.NewBufferObject(ctx, buffer, target); 910848b8605Smrg if (!buf) { 911848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller); 912848b8605Smrg return false; 913848b8605Smrg } 914848b8605Smrg _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, buf); 915848b8605Smrg *buf_handle = buf; 916848b8605Smrg } 917848b8605Smrg 918848b8605Smrg return true; 919848b8605Smrg} 920848b8605Smrg 921848b8605Smrg/** 922848b8605Smrg * Bind the specified target to buffer for the specified context. 923848b8605Smrg * Called by glBindBuffer() and other functions. 924848b8605Smrg */ 925848b8605Smrgstatic void 926848b8605Smrgbind_buffer_object(struct gl_context *ctx, GLenum target, GLuint buffer) 927848b8605Smrg{ 928848b8605Smrg struct gl_buffer_object *oldBufObj; 929848b8605Smrg struct gl_buffer_object *newBufObj = NULL; 930848b8605Smrg struct gl_buffer_object **bindTarget = NULL; 931848b8605Smrg 932848b8605Smrg bindTarget = get_buffer_target(ctx, target); 933848b8605Smrg if (!bindTarget) { 934848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)", target); 935848b8605Smrg return; 936848b8605Smrg } 937848b8605Smrg 938848b8605Smrg /* Get pointer to old buffer object (to be unbound) */ 939848b8605Smrg oldBufObj = *bindTarget; 940848b8605Smrg if (oldBufObj && oldBufObj->Name == buffer && !oldBufObj->DeletePending) 941848b8605Smrg return; /* rebinding the same buffer object- no change */ 942848b8605Smrg 943848b8605Smrg /* 944848b8605Smrg * Get pointer to new buffer object (newBufObj) 945848b8605Smrg */ 946848b8605Smrg if (buffer == 0) { 947848b8605Smrg /* The spec says there's not a buffer object named 0, but we use 948848b8605Smrg * one internally because it simplifies things. 949848b8605Smrg */ 950848b8605Smrg newBufObj = ctx->Shared->NullBufferObj; 951848b8605Smrg } 952848b8605Smrg else { 953848b8605Smrg /* non-default buffer object */ 954848b8605Smrg newBufObj = _mesa_lookup_bufferobj(ctx, buffer); 955848b8605Smrg if (!_mesa_handle_bind_buffer_gen(ctx, target, buffer, 956848b8605Smrg &newBufObj, "glBindBuffer")) 957848b8605Smrg return; 958848b8605Smrg } 959848b8605Smrg 960848b8605Smrg /* bind new buffer */ 961848b8605Smrg _mesa_reference_buffer_object(ctx, bindTarget, newBufObj); 962848b8605Smrg} 963848b8605Smrg 964848b8605Smrg 965848b8605Smrg/** 966848b8605Smrg * Update the default buffer objects in the given context to reference those 967848b8605Smrg * specified in the shared state and release those referencing the old 968848b8605Smrg * shared state. 969848b8605Smrg */ 970848b8605Smrgvoid 971848b8605Smrg_mesa_update_default_objects_buffer_objects(struct gl_context *ctx) 972848b8605Smrg{ 973848b8605Smrg /* Bind the NullBufferObj to remove references to those 974848b8605Smrg * in the shared context hash table. 975848b8605Smrg */ 976848b8605Smrg bind_buffer_object( ctx, GL_ARRAY_BUFFER_ARB, 0); 977848b8605Smrg bind_buffer_object( ctx, GL_ELEMENT_ARRAY_BUFFER_ARB, 0); 978848b8605Smrg bind_buffer_object( ctx, GL_PIXEL_PACK_BUFFER_ARB, 0); 979848b8605Smrg bind_buffer_object( ctx, GL_PIXEL_UNPACK_BUFFER_ARB, 0); 980848b8605Smrg} 981848b8605Smrg 982848b8605Smrg 983848b8605Smrg 984848b8605Smrg/** 985848b8605Smrg * Return the gl_buffer_object for the given ID. 986848b8605Smrg * Always return NULL for ID 0. 987848b8605Smrg */ 988848b8605Smrgstruct gl_buffer_object * 989848b8605Smrg_mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer) 990848b8605Smrg{ 991848b8605Smrg if (buffer == 0) 992848b8605Smrg return NULL; 993848b8605Smrg else 994848b8605Smrg return (struct gl_buffer_object *) 995848b8605Smrg _mesa_HashLookup(ctx->Shared->BufferObjects, buffer); 996848b8605Smrg} 997848b8605Smrg 998848b8605Smrg 999848b8605Smrgstruct gl_buffer_object * 1000848b8605Smrg_mesa_lookup_bufferobj_locked(struct gl_context *ctx, GLuint buffer) 1001848b8605Smrg{ 1002848b8605Smrg return (struct gl_buffer_object *) 1003848b8605Smrg _mesa_HashLookupLocked(ctx->Shared->BufferObjects, buffer); 1004848b8605Smrg} 1005848b8605Smrg 1006848b8605Smrg 1007848b8605Smrgvoid 1008848b8605Smrg_mesa_begin_bufferobj_lookups(struct gl_context *ctx) 1009848b8605Smrg{ 1010848b8605Smrg _mesa_HashLockMutex(ctx->Shared->BufferObjects); 1011848b8605Smrg} 1012848b8605Smrg 1013848b8605Smrg 1014848b8605Smrgvoid 1015848b8605Smrg_mesa_end_bufferobj_lookups(struct gl_context *ctx) 1016848b8605Smrg{ 1017848b8605Smrg _mesa_HashUnlockMutex(ctx->Shared->BufferObjects); 1018848b8605Smrg} 1019848b8605Smrg 1020848b8605Smrg 1021848b8605Smrg/** 1022848b8605Smrg * Look up a buffer object for a multi-bind function. 1023848b8605Smrg * 1024848b8605Smrg * Unlike _mesa_lookup_bufferobj(), this function also takes care 1025848b8605Smrg * of generating an error if the buffer ID is not zero or the name 1026848b8605Smrg * of an existing buffer object. 1027848b8605Smrg * 1028848b8605Smrg * If the buffer ID refers to an existing buffer object, a pointer 1029848b8605Smrg * to the buffer object is returned. If the ID is zero, a pointer 1030848b8605Smrg * to the shared NullBufferObj is returned. If the ID is not zero 1031848b8605Smrg * and does not refer to a valid buffer object, this function 1032848b8605Smrg * returns NULL. 1033848b8605Smrg * 1034848b8605Smrg * This function assumes that the caller has already locked the 1035848b8605Smrg * hash table mutex by calling _mesa_begin_bufferobj_lookups(). 1036848b8605Smrg */ 1037848b8605Smrgstruct gl_buffer_object * 1038848b8605Smrg_mesa_multi_bind_lookup_bufferobj(struct gl_context *ctx, 1039848b8605Smrg const GLuint *buffers, 1040848b8605Smrg GLuint index, const char *caller) 1041848b8605Smrg{ 1042848b8605Smrg struct gl_buffer_object *bufObj; 1043848b8605Smrg 1044848b8605Smrg if (buffers[index] != 0) { 1045848b8605Smrg bufObj = _mesa_lookup_bufferobj_locked(ctx, buffers[index]); 1046848b8605Smrg 1047848b8605Smrg /* The multi-bind functions don't create the buffer objects 1048848b8605Smrg when they don't exist. */ 1049848b8605Smrg if (bufObj == &DummyBufferObject) 1050848b8605Smrg bufObj = NULL; 1051848b8605Smrg } else 1052848b8605Smrg bufObj = ctx->Shared->NullBufferObj; 1053848b8605Smrg 1054848b8605Smrg if (!bufObj) { 1055848b8605Smrg /* The ARB_multi_bind spec says: 1056848b8605Smrg * 1057848b8605Smrg * "An INVALID_OPERATION error is generated if any value 1058848b8605Smrg * in <buffers> is not zero or the name of an existing 1059848b8605Smrg * buffer object (per binding)." 1060848b8605Smrg */ 1061848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1062848b8605Smrg "%s(buffers[%u]=%u is not zero or the name " 1063848b8605Smrg "of an existing buffer object)", 1064848b8605Smrg caller, index, buffers[index]); 1065848b8605Smrg } 1066848b8605Smrg 1067848b8605Smrg return bufObj; 1068848b8605Smrg} 1069848b8605Smrg 1070848b8605Smrg 1071848b8605Smrg/** 1072848b8605Smrg * If *ptr points to obj, set ptr = the Null/default buffer object. 1073848b8605Smrg * This is a helper for buffer object deletion. 1074848b8605Smrg * The GL spec says that deleting a buffer object causes it to get 1075848b8605Smrg * unbound from all arrays in the current context. 1076848b8605Smrg */ 1077848b8605Smrgstatic void 1078848b8605Smrgunbind(struct gl_context *ctx, 1079848b8605Smrg struct gl_buffer_object **ptr, 1080848b8605Smrg struct gl_buffer_object *obj) 1081848b8605Smrg{ 1082848b8605Smrg if (*ptr == obj) { 1083848b8605Smrg _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj); 1084848b8605Smrg } 1085848b8605Smrg} 1086848b8605Smrg 1087848b8605Smrg 1088848b8605Smrg/** 1089848b8605Smrg * Plug default/fallback buffer object functions into the device 1090848b8605Smrg * driver hooks. 1091848b8605Smrg */ 1092848b8605Smrgvoid 1093848b8605Smrg_mesa_init_buffer_object_functions(struct dd_function_table *driver) 1094848b8605Smrg{ 1095848b8605Smrg /* GL_ARB_vertex/pixel_buffer_object */ 1096848b8605Smrg driver->NewBufferObject = _mesa_new_buffer_object; 1097848b8605Smrg driver->DeleteBuffer = _mesa_delete_buffer_object; 1098848b8605Smrg driver->BufferData = _mesa_buffer_data; 1099848b8605Smrg driver->BufferSubData = _mesa_buffer_subdata; 1100848b8605Smrg driver->GetBufferSubData = _mesa_buffer_get_subdata; 1101848b8605Smrg driver->UnmapBuffer = _mesa_buffer_unmap; 1102848b8605Smrg 1103848b8605Smrg /* GL_ARB_clear_buffer_object */ 1104848b8605Smrg driver->ClearBufferSubData = _mesa_buffer_clear_subdata; 1105848b8605Smrg 1106848b8605Smrg /* GL_ARB_map_buffer_range */ 1107848b8605Smrg driver->MapBufferRange = _mesa_buffer_map_range; 1108848b8605Smrg driver->FlushMappedBufferRange = _mesa_buffer_flush_mapped_range; 1109848b8605Smrg 1110848b8605Smrg /* GL_ARB_copy_buffer */ 1111848b8605Smrg driver->CopyBufferSubData = _mesa_copy_buffer_subdata; 1112848b8605Smrg} 1113848b8605Smrg 1114848b8605Smrg 1115848b8605Smrgvoid 1116848b8605Smrg_mesa_buffer_unmap_all_mappings(struct gl_context *ctx, 1117848b8605Smrg struct gl_buffer_object *bufObj) 1118848b8605Smrg{ 1119848b8605Smrg int i; 1120848b8605Smrg 1121848b8605Smrg for (i = 0; i < MAP_COUNT; i++) { 1122848b8605Smrg if (_mesa_bufferobj_mapped(bufObj, i)) { 1123848b8605Smrg ctx->Driver.UnmapBuffer(ctx, bufObj, i); 1124848b8605Smrg ASSERT(bufObj->Mappings[i].Pointer == NULL); 1125848b8605Smrg bufObj->Mappings[i].AccessFlags = 0; 1126848b8605Smrg } 1127848b8605Smrg } 1128848b8605Smrg} 1129848b8605Smrg 1130848b8605Smrg 1131848b8605Smrg/**********************************************************************/ 1132848b8605Smrg/* API Functions */ 1133848b8605Smrg/**********************************************************************/ 1134848b8605Smrg 1135848b8605Smrgvoid GLAPIENTRY 1136848b8605Smrg_mesa_BindBuffer(GLenum target, GLuint buffer) 1137848b8605Smrg{ 1138848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1139848b8605Smrg 1140848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 1141848b8605Smrg _mesa_debug(ctx, "glBindBuffer(%s, %u)\n", 1142848b8605Smrg _mesa_lookup_enum_by_nr(target), buffer); 1143848b8605Smrg 1144848b8605Smrg bind_buffer_object(ctx, target, buffer); 1145848b8605Smrg} 1146848b8605Smrg 1147848b8605Smrg 1148848b8605Smrg/** 1149848b8605Smrg * Delete a set of buffer objects. 1150848b8605Smrg * 1151848b8605Smrg * \param n Number of buffer objects to delete. 1152848b8605Smrg * \param ids Array of \c n buffer object IDs. 1153848b8605Smrg */ 1154848b8605Smrgvoid GLAPIENTRY 1155848b8605Smrg_mesa_DeleteBuffers(GLsizei n, const GLuint *ids) 1156848b8605Smrg{ 1157848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1158848b8605Smrg GLsizei i; 1159848b8605Smrg FLUSH_VERTICES(ctx, 0); 1160848b8605Smrg 1161848b8605Smrg if (n < 0) { 1162848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)"); 1163848b8605Smrg return; 1164848b8605Smrg } 1165848b8605Smrg 1166848b8605Smrg mtx_lock(&ctx->Shared->Mutex); 1167848b8605Smrg 1168848b8605Smrg for (i = 0; i < n; i++) { 1169848b8605Smrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]); 1170848b8605Smrg if (bufObj) { 1171848b8605Smrg struct gl_vertex_array_object *vao = ctx->Array.VAO; 1172848b8605Smrg GLuint j; 1173848b8605Smrg 1174848b8605Smrg ASSERT(bufObj->Name == ids[i] || bufObj == &DummyBufferObject); 1175848b8605Smrg 1176848b8605Smrg _mesa_buffer_unmap_all_mappings(ctx, bufObj); 1177848b8605Smrg 1178848b8605Smrg /* unbind any vertex pointers bound to this buffer */ 1179848b8605Smrg for (j = 0; j < Elements(vao->VertexBinding); j++) { 1180848b8605Smrg unbind(ctx, &vao->VertexBinding[j].BufferObj, bufObj); 1181848b8605Smrg } 1182848b8605Smrg 1183848b8605Smrg if (ctx->Array.ArrayBufferObj == bufObj) { 1184848b8605Smrg _mesa_BindBuffer( GL_ARRAY_BUFFER_ARB, 0 ); 1185848b8605Smrg } 1186848b8605Smrg if (vao->IndexBufferObj == bufObj) { 1187848b8605Smrg _mesa_BindBuffer( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 ); 1188848b8605Smrg } 1189848b8605Smrg 1190848b8605Smrg /* unbind ARB_draw_indirect binding point */ 1191848b8605Smrg if (ctx->DrawIndirectBuffer == bufObj) { 1192848b8605Smrg _mesa_BindBuffer( GL_DRAW_INDIRECT_BUFFER, 0 ); 1193848b8605Smrg } 1194848b8605Smrg 1195848b8605Smrg /* unbind ARB_copy_buffer binding points */ 1196848b8605Smrg if (ctx->CopyReadBuffer == bufObj) { 1197848b8605Smrg _mesa_BindBuffer( GL_COPY_READ_BUFFER, 0 ); 1198848b8605Smrg } 1199848b8605Smrg if (ctx->CopyWriteBuffer == bufObj) { 1200848b8605Smrg _mesa_BindBuffer( GL_COPY_WRITE_BUFFER, 0 ); 1201848b8605Smrg } 1202848b8605Smrg 1203848b8605Smrg /* unbind transform feedback binding points */ 1204848b8605Smrg if (ctx->TransformFeedback.CurrentBuffer == bufObj) { 1205848b8605Smrg _mesa_BindBuffer( GL_TRANSFORM_FEEDBACK_BUFFER, 0 ); 1206848b8605Smrg } 1207848b8605Smrg for (j = 0; j < MAX_FEEDBACK_BUFFERS; j++) { 1208848b8605Smrg if (ctx->TransformFeedback.CurrentObject->Buffers[j] == bufObj) { 1209848b8605Smrg _mesa_BindBufferBase( GL_TRANSFORM_FEEDBACK_BUFFER, j, 0 ); 1210848b8605Smrg } 1211848b8605Smrg } 1212848b8605Smrg 1213848b8605Smrg /* unbind UBO binding points */ 1214848b8605Smrg for (j = 0; j < ctx->Const.MaxUniformBufferBindings; j++) { 1215848b8605Smrg if (ctx->UniformBufferBindings[j].BufferObject == bufObj) { 1216848b8605Smrg _mesa_BindBufferBase( GL_UNIFORM_BUFFER, j, 0 ); 1217848b8605Smrg } 1218848b8605Smrg } 1219848b8605Smrg 1220848b8605Smrg if (ctx->UniformBuffer == bufObj) { 1221848b8605Smrg _mesa_BindBuffer( GL_UNIFORM_BUFFER, 0 ); 1222848b8605Smrg } 1223848b8605Smrg 1224848b8605Smrg /* unbind Atomci Buffer binding points */ 1225848b8605Smrg for (j = 0; j < ctx->Const.MaxAtomicBufferBindings; j++) { 1226848b8605Smrg if (ctx->AtomicBufferBindings[j].BufferObject == bufObj) { 1227848b8605Smrg _mesa_BindBufferBase( GL_ATOMIC_COUNTER_BUFFER, j, 0 ); 1228848b8605Smrg } 1229848b8605Smrg } 1230848b8605Smrg 1231848b8605Smrg if (ctx->UniformBuffer == bufObj) { 1232848b8605Smrg _mesa_BindBuffer( GL_ATOMIC_COUNTER_BUFFER, 0 ); 1233848b8605Smrg } 1234848b8605Smrg 1235848b8605Smrg /* unbind any pixel pack/unpack pointers bound to this buffer */ 1236848b8605Smrg if (ctx->Pack.BufferObj == bufObj) { 1237848b8605Smrg _mesa_BindBuffer( GL_PIXEL_PACK_BUFFER_EXT, 0 ); 1238848b8605Smrg } 1239848b8605Smrg if (ctx->Unpack.BufferObj == bufObj) { 1240848b8605Smrg _mesa_BindBuffer( GL_PIXEL_UNPACK_BUFFER_EXT, 0 ); 1241848b8605Smrg } 1242848b8605Smrg 1243848b8605Smrg if (ctx->Texture.BufferObject == bufObj) { 1244848b8605Smrg _mesa_BindBuffer( GL_TEXTURE_BUFFER, 0 ); 1245848b8605Smrg } 1246848b8605Smrg 1247848b8605Smrg /* The ID is immediately freed for re-use */ 1248848b8605Smrg _mesa_HashRemove(ctx->Shared->BufferObjects, ids[i]); 1249848b8605Smrg /* Make sure we do not run into the classic ABA problem on bind. 1250848b8605Smrg * We don't want to allow re-binding a buffer object that's been 1251848b8605Smrg * "deleted" by glDeleteBuffers(). 1252848b8605Smrg * 1253848b8605Smrg * The explicit rebinding to the default object in the current context 1254848b8605Smrg * prevents the above in the current context, but another context 1255848b8605Smrg * sharing the same objects might suffer from this problem. 1256848b8605Smrg * The alternative would be to do the hash lookup in any case on bind 1257848b8605Smrg * which would introduce more runtime overhead than this. 1258848b8605Smrg */ 1259848b8605Smrg bufObj->DeletePending = GL_TRUE; 1260848b8605Smrg _mesa_reference_buffer_object(ctx, &bufObj, NULL); 1261848b8605Smrg } 1262848b8605Smrg } 1263848b8605Smrg 1264848b8605Smrg mtx_unlock(&ctx->Shared->Mutex); 1265848b8605Smrg} 1266848b8605Smrg 1267848b8605Smrg 1268848b8605Smrg/** 1269848b8605Smrg * Generate a set of unique buffer object IDs and store them in \c buffer. 1270848b8605Smrg * 1271848b8605Smrg * \param n Number of IDs to generate. 1272848b8605Smrg * \param buffer Array of \c n locations to store the IDs. 1273848b8605Smrg */ 1274848b8605Smrgvoid GLAPIENTRY 1275848b8605Smrg_mesa_GenBuffers(GLsizei n, GLuint *buffer) 1276848b8605Smrg{ 1277848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1278848b8605Smrg GLuint first; 1279848b8605Smrg GLint i; 1280848b8605Smrg 1281848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 1282848b8605Smrg _mesa_debug(ctx, "glGenBuffers(%d)\n", n); 1283848b8605Smrg 1284848b8605Smrg if (n < 0) { 1285848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glGenBuffersARB"); 1286848b8605Smrg return; 1287848b8605Smrg } 1288848b8605Smrg 1289848b8605Smrg if (!buffer) { 1290848b8605Smrg return; 1291848b8605Smrg } 1292848b8605Smrg 1293848b8605Smrg /* 1294848b8605Smrg * This must be atomic (generation and allocation of buffer object IDs) 1295848b8605Smrg */ 1296848b8605Smrg mtx_lock(&ctx->Shared->Mutex); 1297848b8605Smrg 1298848b8605Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n); 1299848b8605Smrg 1300848b8605Smrg /* Insert the ID and pointer to dummy buffer object into hash table */ 1301848b8605Smrg for (i = 0; i < n; i++) { 1302848b8605Smrg _mesa_HashInsert(ctx->Shared->BufferObjects, first + i, 1303848b8605Smrg &DummyBufferObject); 1304848b8605Smrg buffer[i] = first + i; 1305848b8605Smrg } 1306848b8605Smrg 1307848b8605Smrg mtx_unlock(&ctx->Shared->Mutex); 1308848b8605Smrg} 1309848b8605Smrg 1310848b8605Smrg 1311848b8605Smrg/** 1312848b8605Smrg * Determine if ID is the name of a buffer object. 1313848b8605Smrg * 1314848b8605Smrg * \param id ID of the potential buffer object. 1315848b8605Smrg * \return \c GL_TRUE if \c id is the name of a buffer object, 1316848b8605Smrg * \c GL_FALSE otherwise. 1317848b8605Smrg */ 1318848b8605SmrgGLboolean GLAPIENTRY 1319848b8605Smrg_mesa_IsBuffer(GLuint id) 1320848b8605Smrg{ 1321848b8605Smrg struct gl_buffer_object *bufObj; 1322848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1323848b8605Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 1324848b8605Smrg 1325848b8605Smrg mtx_lock(&ctx->Shared->Mutex); 1326848b8605Smrg bufObj = _mesa_lookup_bufferobj(ctx, id); 1327848b8605Smrg mtx_unlock(&ctx->Shared->Mutex); 1328848b8605Smrg 1329848b8605Smrg return bufObj && bufObj != &DummyBufferObject; 1330848b8605Smrg} 1331848b8605Smrg 1332848b8605Smrg 1333848b8605Smrgvoid GLAPIENTRY 1334848b8605Smrg_mesa_BufferStorage(GLenum target, GLsizeiptr size, const GLvoid *data, 1335848b8605Smrg GLbitfield flags) 1336848b8605Smrg{ 1337848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1338848b8605Smrg struct gl_buffer_object *bufObj; 1339848b8605Smrg 1340848b8605Smrg if (size <= 0) { 1341848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glBufferStorage(size <= 0)"); 1342848b8605Smrg return; 1343848b8605Smrg } 1344848b8605Smrg 1345848b8605Smrg if (flags & ~(GL_MAP_READ_BIT | 1346848b8605Smrg GL_MAP_WRITE_BIT | 1347848b8605Smrg GL_MAP_PERSISTENT_BIT | 1348848b8605Smrg GL_MAP_COHERENT_BIT | 1349848b8605Smrg GL_DYNAMIC_STORAGE_BIT | 1350848b8605Smrg GL_CLIENT_STORAGE_BIT)) { 1351848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glBufferStorage(flags)"); 1352848b8605Smrg return; 1353848b8605Smrg } 1354848b8605Smrg 1355848b8605Smrg if (flags & GL_MAP_PERSISTENT_BIT && 1356848b8605Smrg !(flags & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT))) { 1357848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glBufferStorage(flags!=READ/WRITE)"); 1358848b8605Smrg return; 1359848b8605Smrg } 1360848b8605Smrg 1361848b8605Smrg if (flags & GL_MAP_COHERENT_BIT && !(flags & GL_MAP_PERSISTENT_BIT)) { 1362848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glBufferStorage(flags!=PERSISTENT)"); 1363848b8605Smrg return; 1364848b8605Smrg } 1365848b8605Smrg 1366848b8605Smrg bufObj = get_buffer(ctx, "glBufferStorage", target, GL_INVALID_OPERATION); 1367848b8605Smrg if (!bufObj) 1368848b8605Smrg return; 1369848b8605Smrg 1370848b8605Smrg if (bufObj->Immutable) { 1371848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferStorage(immutable)"); 1372848b8605Smrg return; 1373848b8605Smrg } 1374848b8605Smrg 1375848b8605Smrg /* Unmap the existing buffer. We'll replace it now. Not an error. */ 1376848b8605Smrg _mesa_buffer_unmap_all_mappings(ctx, bufObj); 1377848b8605Smrg 1378848b8605Smrg FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT); 1379848b8605Smrg 1380848b8605Smrg bufObj->Written = GL_TRUE; 1381848b8605Smrg bufObj->Immutable = GL_TRUE; 1382848b8605Smrg 1383848b8605Smrg ASSERT(ctx->Driver.BufferData); 1384848b8605Smrg if (!ctx->Driver.BufferData(ctx, target, size, data, GL_DYNAMIC_DRAW, 1385848b8605Smrg flags, bufObj)) { 1386848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferStorage()"); 1387848b8605Smrg } 1388848b8605Smrg} 1389848b8605Smrg 1390848b8605Smrg 1391848b8605Smrgvoid GLAPIENTRY 1392848b8605Smrg_mesa_BufferData(GLenum target, GLsizeiptrARB size, 1393848b8605Smrg const GLvoid * data, GLenum usage) 1394848b8605Smrg{ 1395848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1396848b8605Smrg struct gl_buffer_object *bufObj; 1397848b8605Smrg bool valid_usage; 1398848b8605Smrg 1399848b8605Smrg if (MESA_VERBOSE & VERBOSE_API) 1400848b8605Smrg _mesa_debug(ctx, "glBufferData(%s, %ld, %p, %s)\n", 1401848b8605Smrg _mesa_lookup_enum_by_nr(target), 1402848b8605Smrg (long int) size, data, 1403848b8605Smrg _mesa_lookup_enum_by_nr(usage)); 1404848b8605Smrg 1405848b8605Smrg if (size < 0) { 1406848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glBufferDataARB(size < 0)"); 1407848b8605Smrg return; 1408848b8605Smrg } 1409848b8605Smrg 1410848b8605Smrg switch (usage) { 1411848b8605Smrg case GL_STREAM_DRAW_ARB: 1412848b8605Smrg valid_usage = (ctx->API != API_OPENGLES); 1413848b8605Smrg break; 1414848b8605Smrg 1415848b8605Smrg case GL_STATIC_DRAW_ARB: 1416848b8605Smrg case GL_DYNAMIC_DRAW_ARB: 1417848b8605Smrg valid_usage = true; 1418848b8605Smrg break; 1419848b8605Smrg 1420848b8605Smrg case GL_STREAM_READ_ARB: 1421848b8605Smrg case GL_STREAM_COPY_ARB: 1422848b8605Smrg case GL_STATIC_READ_ARB: 1423848b8605Smrg case GL_STATIC_COPY_ARB: 1424848b8605Smrg case GL_DYNAMIC_READ_ARB: 1425848b8605Smrg case GL_DYNAMIC_COPY_ARB: 1426848b8605Smrg valid_usage = _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx); 1427848b8605Smrg break; 1428848b8605Smrg 1429848b8605Smrg default: 1430848b8605Smrg valid_usage = false; 1431848b8605Smrg break; 1432848b8605Smrg } 1433848b8605Smrg 1434848b8605Smrg if (!valid_usage) { 1435848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBufferData(usage)"); 1436848b8605Smrg return; 1437848b8605Smrg } 1438848b8605Smrg 1439848b8605Smrg bufObj = get_buffer(ctx, "glBufferDataARB", target, GL_INVALID_OPERATION); 1440848b8605Smrg if (!bufObj) 1441848b8605Smrg return; 1442848b8605Smrg 1443848b8605Smrg if (bufObj->Immutable) { 1444848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferData(immutable)"); 1445848b8605Smrg return; 1446848b8605Smrg } 1447848b8605Smrg 1448848b8605Smrg /* Unmap the existing buffer. We'll replace it now. Not an error. */ 1449848b8605Smrg _mesa_buffer_unmap_all_mappings(ctx, bufObj); 1450848b8605Smrg 1451848b8605Smrg FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT); 1452848b8605Smrg 1453848b8605Smrg bufObj->Written = GL_TRUE; 1454848b8605Smrg 1455848b8605Smrg#ifdef VBO_DEBUG 1456848b8605Smrg printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n", 1457848b8605Smrg bufObj->Name, size, data, usage); 1458848b8605Smrg#endif 1459848b8605Smrg 1460848b8605Smrg#ifdef BOUNDS_CHECK 1461848b8605Smrg size += 100; 1462848b8605Smrg#endif 1463848b8605Smrg 1464848b8605Smrg ASSERT(ctx->Driver.BufferData); 1465848b8605Smrg if (!ctx->Driver.BufferData(ctx, target, size, data, usage, 1466848b8605Smrg GL_MAP_READ_BIT | 1467848b8605Smrg GL_MAP_WRITE_BIT | 1468848b8605Smrg GL_DYNAMIC_STORAGE_BIT, 1469848b8605Smrg bufObj)) { 1470848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBufferDataARB()"); 1471848b8605Smrg } 1472848b8605Smrg} 1473848b8605Smrg 1474848b8605Smrg 1475848b8605Smrgvoid GLAPIENTRY 1476848b8605Smrg_mesa_BufferSubData(GLenum target, GLintptrARB offset, 1477848b8605Smrg GLsizeiptrARB size, const GLvoid * data) 1478848b8605Smrg{ 1479848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1480848b8605Smrg struct gl_buffer_object *bufObj; 1481848b8605Smrg 1482848b8605Smrg bufObj = buffer_object_subdata_range_good( ctx, target, offset, size, 1483848b8605Smrg false, GL_INVALID_OPERATION, 1484848b8605Smrg "glBufferSubDataARB" ); 1485848b8605Smrg if (!bufObj) { 1486848b8605Smrg /* error already recorded */ 1487848b8605Smrg return; 1488848b8605Smrg } 1489848b8605Smrg 1490848b8605Smrg if (bufObj->Immutable && 1491848b8605Smrg !(bufObj->StorageFlags & GL_DYNAMIC_STORAGE_BIT)) { 1492848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glBufferSubData"); 1493848b8605Smrg return; 1494848b8605Smrg } 1495848b8605Smrg 1496848b8605Smrg if (size == 0) 1497848b8605Smrg return; 1498848b8605Smrg 1499848b8605Smrg bufObj->Written = GL_TRUE; 1500848b8605Smrg 1501848b8605Smrg ASSERT(ctx->Driver.BufferSubData); 1502848b8605Smrg ctx->Driver.BufferSubData( ctx, offset, size, data, bufObj ); 1503848b8605Smrg} 1504848b8605Smrg 1505848b8605Smrg 1506848b8605Smrgvoid GLAPIENTRY 1507848b8605Smrg_mesa_GetBufferSubData(GLenum target, GLintptrARB offset, 1508848b8605Smrg GLsizeiptrARB size, void * data) 1509848b8605Smrg{ 1510848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1511848b8605Smrg struct gl_buffer_object *bufObj; 1512848b8605Smrg 1513848b8605Smrg bufObj = buffer_object_subdata_range_good(ctx, target, offset, size, 1514848b8605Smrg false, GL_INVALID_OPERATION, 1515848b8605Smrg "glGetBufferSubDataARB"); 1516848b8605Smrg if (!bufObj) { 1517848b8605Smrg /* error already recorded */ 1518848b8605Smrg return; 1519848b8605Smrg } 1520848b8605Smrg 1521848b8605Smrg ASSERT(ctx->Driver.GetBufferSubData); 1522848b8605Smrg ctx->Driver.GetBufferSubData( ctx, offset, size, data, bufObj ); 1523848b8605Smrg} 1524848b8605Smrg 1525848b8605Smrg 1526848b8605Smrgvoid GLAPIENTRY 1527848b8605Smrg_mesa_ClearBufferData(GLenum target, GLenum internalformat, GLenum format, 1528848b8605Smrg GLenum type, const GLvoid* data) 1529848b8605Smrg{ 1530848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1531848b8605Smrg struct gl_buffer_object* bufObj; 1532848b8605Smrg mesa_format mesaFormat; 1533848b8605Smrg GLubyte clearValue[MAX_PIXEL_BYTES]; 1534848b8605Smrg GLsizeiptr clearValueSize; 1535848b8605Smrg 1536848b8605Smrg bufObj = get_buffer(ctx, "glClearBufferData", target, GL_INVALID_VALUE); 1537848b8605Smrg if (!bufObj) { 1538848b8605Smrg return; 1539848b8605Smrg } 1540848b8605Smrg 1541848b8605Smrg if (_mesa_check_disallowed_mapping(bufObj)) { 1542848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1543848b8605Smrg "glClearBufferData(buffer currently mapped)"); 1544848b8605Smrg return; 1545848b8605Smrg } 1546848b8605Smrg 1547848b8605Smrg mesaFormat = validate_clear_buffer_format(ctx, internalformat, 1548848b8605Smrg format, type, 1549848b8605Smrg "glClearBufferData"); 1550848b8605Smrg if (mesaFormat == MESA_FORMAT_NONE) { 1551848b8605Smrg return; 1552848b8605Smrg } 1553848b8605Smrg 1554848b8605Smrg clearValueSize = _mesa_get_format_bytes(mesaFormat); 1555848b8605Smrg if (bufObj->Size % clearValueSize != 0) { 1556848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 1557848b8605Smrg "glClearBufferData(size is not a multiple of " 1558848b8605Smrg "internalformat size)"); 1559848b8605Smrg return; 1560848b8605Smrg } 1561848b8605Smrg 1562848b8605Smrg if (data == NULL) { 1563848b8605Smrg /* clear to zeros, per the spec */ 1564848b8605Smrg ctx->Driver.ClearBufferSubData(ctx, 0, bufObj->Size, 1565848b8605Smrg NULL, clearValueSize, bufObj); 1566848b8605Smrg return; 1567848b8605Smrg } 1568848b8605Smrg 1569848b8605Smrg if (!convert_clear_buffer_data(ctx, mesaFormat, clearValue, 1570848b8605Smrg format, type, data, "glClearBufferData")) { 1571848b8605Smrg return; 1572848b8605Smrg } 1573848b8605Smrg 1574848b8605Smrg ctx->Driver.ClearBufferSubData(ctx, 0, bufObj->Size, 1575848b8605Smrg clearValue, clearValueSize, bufObj); 1576848b8605Smrg} 1577848b8605Smrg 1578848b8605Smrg 1579848b8605Smrgvoid GLAPIENTRY 1580848b8605Smrg_mesa_ClearBufferSubData(GLenum target, GLenum internalformat, 1581848b8605Smrg GLintptr offset, GLsizeiptr size, 1582848b8605Smrg GLenum format, GLenum type, 1583848b8605Smrg const GLvoid* data) 1584848b8605Smrg{ 1585848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1586848b8605Smrg struct gl_buffer_object* bufObj; 1587848b8605Smrg mesa_format mesaFormat; 1588848b8605Smrg GLubyte clearValue[MAX_PIXEL_BYTES]; 1589848b8605Smrg GLsizeiptr clearValueSize; 1590848b8605Smrg 1591848b8605Smrg bufObj = buffer_object_subdata_range_good(ctx, target, offset, size, 1592848b8605Smrg true, GL_INVALID_VALUE, 1593848b8605Smrg "glClearBufferSubData"); 1594848b8605Smrg if (!bufObj) { 1595848b8605Smrg return; 1596848b8605Smrg } 1597848b8605Smrg 1598848b8605Smrg mesaFormat = validate_clear_buffer_format(ctx, internalformat, 1599848b8605Smrg format, type, 1600848b8605Smrg "glClearBufferSubData"); 1601848b8605Smrg if (mesaFormat == MESA_FORMAT_NONE) { 1602848b8605Smrg return; 1603848b8605Smrg } 1604848b8605Smrg 1605848b8605Smrg clearValueSize = _mesa_get_format_bytes(mesaFormat); 1606848b8605Smrg if (offset % clearValueSize != 0 || size % clearValueSize != 0) { 1607848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 1608848b8605Smrg "glClearBufferSubData(offset or size is not a multiple of " 1609848b8605Smrg "internalformat size)"); 1610848b8605Smrg return; 1611848b8605Smrg } 1612848b8605Smrg 1613848b8605Smrg if (data == NULL) { 1614848b8605Smrg /* clear to zeros, per the spec */ 1615848b8605Smrg if (size > 0) { 1616848b8605Smrg ctx->Driver.ClearBufferSubData(ctx, offset, size, 1617848b8605Smrg NULL, clearValueSize, bufObj); 1618848b8605Smrg } 1619848b8605Smrg return; 1620848b8605Smrg } 1621848b8605Smrg 1622848b8605Smrg if (!convert_clear_buffer_data(ctx, mesaFormat, clearValue, 1623848b8605Smrg format, type, data, 1624848b8605Smrg "glClearBufferSubData")) { 1625848b8605Smrg return; 1626848b8605Smrg } 1627848b8605Smrg 1628848b8605Smrg if (size > 0) { 1629848b8605Smrg ctx->Driver.ClearBufferSubData(ctx, offset, size, 1630848b8605Smrg clearValue, clearValueSize, bufObj); 1631848b8605Smrg } 1632848b8605Smrg} 1633848b8605Smrg 1634848b8605Smrg 1635848b8605Smrgvoid * GLAPIENTRY 1636848b8605Smrg_mesa_MapBuffer(GLenum target, GLenum access) 1637848b8605Smrg{ 1638848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1639848b8605Smrg struct gl_buffer_object * bufObj; 1640848b8605Smrg GLbitfield accessFlags; 1641848b8605Smrg void *map; 1642848b8605Smrg bool valid_access; 1643848b8605Smrg 1644848b8605Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); 1645848b8605Smrg 1646848b8605Smrg switch (access) { 1647848b8605Smrg case GL_READ_ONLY_ARB: 1648848b8605Smrg accessFlags = GL_MAP_READ_BIT; 1649848b8605Smrg valid_access = _mesa_is_desktop_gl(ctx); 1650848b8605Smrg break; 1651848b8605Smrg case GL_WRITE_ONLY_ARB: 1652848b8605Smrg accessFlags = GL_MAP_WRITE_BIT; 1653848b8605Smrg valid_access = true; 1654848b8605Smrg break; 1655848b8605Smrg case GL_READ_WRITE_ARB: 1656848b8605Smrg accessFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; 1657848b8605Smrg valid_access = _mesa_is_desktop_gl(ctx); 1658848b8605Smrg break; 1659848b8605Smrg default: 1660848b8605Smrg valid_access = false; 1661848b8605Smrg break; 1662848b8605Smrg } 1663848b8605Smrg 1664848b8605Smrg if (!valid_access) { 1665848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glMapBufferARB(access)"); 1666848b8605Smrg return NULL; 1667848b8605Smrg } 1668848b8605Smrg 1669848b8605Smrg bufObj = get_buffer(ctx, "glMapBufferARB", target, GL_INVALID_OPERATION); 1670848b8605Smrg if (!bufObj) 1671848b8605Smrg return NULL; 1672848b8605Smrg 1673848b8605Smrg if (accessFlags & GL_MAP_READ_BIT && 1674848b8605Smrg !(bufObj->StorageFlags & GL_MAP_READ_BIT)) { 1675848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1676848b8605Smrg "glMapBuffer(invalid read flag)"); 1677848b8605Smrg return NULL; 1678848b8605Smrg } 1679848b8605Smrg 1680848b8605Smrg if (accessFlags & GL_MAP_WRITE_BIT && 1681848b8605Smrg !(bufObj->StorageFlags & GL_MAP_WRITE_BIT)) { 1682848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1683848b8605Smrg "glMapBuffer(invalid write flag)"); 1684848b8605Smrg return NULL; 1685848b8605Smrg } 1686848b8605Smrg 1687848b8605Smrg if (_mesa_bufferobj_mapped(bufObj, MAP_USER)) { 1688848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glMapBufferARB(already mapped)"); 1689848b8605Smrg return NULL; 1690848b8605Smrg } 1691848b8605Smrg 1692848b8605Smrg if (!bufObj->Size) { 1693848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, 1694848b8605Smrg "glMapBuffer(buffer size = 0)"); 1695848b8605Smrg return NULL; 1696848b8605Smrg } 1697848b8605Smrg 1698848b8605Smrg ASSERT(ctx->Driver.MapBufferRange); 1699848b8605Smrg map = ctx->Driver.MapBufferRange(ctx, 0, bufObj->Size, accessFlags, bufObj, 1700848b8605Smrg MAP_USER); 1701848b8605Smrg if (!map) { 1702848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); 1703848b8605Smrg return NULL; 1704848b8605Smrg } 1705848b8605Smrg else { 1706848b8605Smrg /* The driver callback should have set these fields. 1707848b8605Smrg * This is important because other modules (like VBO) might call 1708848b8605Smrg * the driver function directly. 1709848b8605Smrg */ 1710848b8605Smrg ASSERT(bufObj->Mappings[MAP_USER].Pointer == map); 1711848b8605Smrg ASSERT(bufObj->Mappings[MAP_USER].Length == bufObj->Size); 1712848b8605Smrg ASSERT(bufObj->Mappings[MAP_USER].Offset == 0); 1713848b8605Smrg bufObj->Mappings[MAP_USER].AccessFlags = accessFlags; 1714848b8605Smrg } 1715848b8605Smrg 1716848b8605Smrg if (access == GL_WRITE_ONLY_ARB || access == GL_READ_WRITE_ARB) 1717848b8605Smrg bufObj->Written = GL_TRUE; 1718848b8605Smrg 1719848b8605Smrg#ifdef VBO_DEBUG 1720848b8605Smrg printf("glMapBufferARB(%u, sz %ld, access 0x%x)\n", 1721848b8605Smrg bufObj->Name, bufObj->Size, access); 1722848b8605Smrg if (access == GL_WRITE_ONLY_ARB) { 1723848b8605Smrg GLuint i; 1724848b8605Smrg GLubyte *b = (GLubyte *) bufObj->Pointer; 1725848b8605Smrg for (i = 0; i < bufObj->Size; i++) 1726848b8605Smrg b[i] = i & 0xff; 1727848b8605Smrg } 1728848b8605Smrg#endif 1729848b8605Smrg 1730848b8605Smrg#ifdef BOUNDS_CHECK 1731848b8605Smrg { 1732848b8605Smrg GLubyte *buf = (GLubyte *) bufObj->Pointer; 1733848b8605Smrg GLuint i; 1734848b8605Smrg /* buffer is 100 bytes larger than requested, fill with magic value */ 1735848b8605Smrg for (i = 0; i < 100; i++) { 1736848b8605Smrg buf[bufObj->Size - i - 1] = 123; 1737848b8605Smrg } 1738848b8605Smrg } 1739848b8605Smrg#endif 1740848b8605Smrg 1741848b8605Smrg return bufObj->Mappings[MAP_USER].Pointer; 1742848b8605Smrg} 1743848b8605Smrg 1744848b8605Smrg 1745848b8605SmrgGLboolean GLAPIENTRY 1746848b8605Smrg_mesa_UnmapBuffer(GLenum target) 1747848b8605Smrg{ 1748848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1749848b8605Smrg struct gl_buffer_object *bufObj; 1750848b8605Smrg GLboolean status = GL_TRUE; 1751848b8605Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 1752848b8605Smrg 1753848b8605Smrg bufObj = get_buffer(ctx, "glUnmapBufferARB", target, GL_INVALID_OPERATION); 1754848b8605Smrg if (!bufObj) 1755848b8605Smrg return GL_FALSE; 1756848b8605Smrg 1757848b8605Smrg if (!_mesa_bufferobj_mapped(bufObj, MAP_USER)) { 1758848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glUnmapBufferARB"); 1759848b8605Smrg return GL_FALSE; 1760848b8605Smrg } 1761848b8605Smrg 1762848b8605Smrg#ifdef BOUNDS_CHECK 1763848b8605Smrg if (bufObj->Access != GL_READ_ONLY_ARB) { 1764848b8605Smrg GLubyte *buf = (GLubyte *) bufObj->Pointer; 1765848b8605Smrg GLuint i; 1766848b8605Smrg /* check that last 100 bytes are still = magic value */ 1767848b8605Smrg for (i = 0; i < 100; i++) { 1768848b8605Smrg GLuint pos = bufObj->Size - i - 1; 1769848b8605Smrg if (buf[pos] != 123) { 1770848b8605Smrg _mesa_warning(ctx, "Out of bounds buffer object write detected" 1771848b8605Smrg " at position %d (value = %u)\n", 1772848b8605Smrg pos, buf[pos]); 1773848b8605Smrg } 1774848b8605Smrg } 1775848b8605Smrg } 1776848b8605Smrg#endif 1777848b8605Smrg 1778848b8605Smrg#ifdef VBO_DEBUG 1779848b8605Smrg if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) { 1780848b8605Smrg GLuint i, unchanged = 0; 1781848b8605Smrg GLubyte *b = (GLubyte *) bufObj->Pointer; 1782848b8605Smrg GLint pos = -1; 1783848b8605Smrg /* check which bytes changed */ 1784848b8605Smrg for (i = 0; i < bufObj->Size - 1; i++) { 1785848b8605Smrg if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) { 1786848b8605Smrg unchanged++; 1787848b8605Smrg if (pos == -1) 1788848b8605Smrg pos = i; 1789848b8605Smrg } 1790848b8605Smrg } 1791848b8605Smrg if (unchanged) { 1792848b8605Smrg printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n", 1793848b8605Smrg bufObj->Name, unchanged, bufObj->Size, pos); 1794848b8605Smrg } 1795848b8605Smrg } 1796848b8605Smrg#endif 1797848b8605Smrg 1798848b8605Smrg status = ctx->Driver.UnmapBuffer(ctx, bufObj, MAP_USER); 1799848b8605Smrg bufObj->Mappings[MAP_USER].AccessFlags = 0; 1800848b8605Smrg ASSERT(bufObj->Mappings[MAP_USER].Pointer == NULL); 1801848b8605Smrg ASSERT(bufObj->Mappings[MAP_USER].Offset == 0); 1802848b8605Smrg ASSERT(bufObj->Mappings[MAP_USER].Length == 0); 1803848b8605Smrg 1804848b8605Smrg return status; 1805848b8605Smrg} 1806848b8605Smrg 1807848b8605Smrg 1808848b8605Smrgvoid GLAPIENTRY 1809848b8605Smrg_mesa_GetBufferParameteriv(GLenum target, GLenum pname, GLint *params) 1810848b8605Smrg{ 1811848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1812848b8605Smrg struct gl_buffer_object *bufObj; 1813848b8605Smrg 1814848b8605Smrg bufObj = get_buffer(ctx, "glGetBufferParameterivARB", target, 1815848b8605Smrg GL_INVALID_OPERATION); 1816848b8605Smrg if (!bufObj) 1817848b8605Smrg return; 1818848b8605Smrg 1819848b8605Smrg switch (pname) { 1820848b8605Smrg case GL_BUFFER_SIZE_ARB: 1821848b8605Smrg *params = (GLint) bufObj->Size; 1822848b8605Smrg return; 1823848b8605Smrg case GL_BUFFER_USAGE_ARB: 1824848b8605Smrg *params = bufObj->Usage; 1825848b8605Smrg return; 1826848b8605Smrg case GL_BUFFER_ACCESS_ARB: 1827848b8605Smrg *params = simplified_access_mode(ctx, 1828848b8605Smrg bufObj->Mappings[MAP_USER].AccessFlags); 1829848b8605Smrg return; 1830848b8605Smrg case GL_BUFFER_MAPPED_ARB: 1831848b8605Smrg *params = _mesa_bufferobj_mapped(bufObj, MAP_USER); 1832848b8605Smrg return; 1833848b8605Smrg case GL_BUFFER_ACCESS_FLAGS: 1834848b8605Smrg if (!ctx->Extensions.ARB_map_buffer_range) 1835848b8605Smrg goto invalid_pname; 1836848b8605Smrg *params = bufObj->Mappings[MAP_USER].AccessFlags; 1837848b8605Smrg return; 1838848b8605Smrg case GL_BUFFER_MAP_OFFSET: 1839848b8605Smrg if (!ctx->Extensions.ARB_map_buffer_range) 1840848b8605Smrg goto invalid_pname; 1841848b8605Smrg *params = (GLint) bufObj->Mappings[MAP_USER].Offset; 1842848b8605Smrg return; 1843848b8605Smrg case GL_BUFFER_MAP_LENGTH: 1844848b8605Smrg if (!ctx->Extensions.ARB_map_buffer_range) 1845848b8605Smrg goto invalid_pname; 1846848b8605Smrg *params = (GLint) bufObj->Mappings[MAP_USER].Length; 1847848b8605Smrg return; 1848848b8605Smrg case GL_BUFFER_IMMUTABLE_STORAGE: 1849848b8605Smrg if (!ctx->Extensions.ARB_buffer_storage) 1850848b8605Smrg goto invalid_pname; 1851848b8605Smrg *params = bufObj->Immutable; 1852848b8605Smrg return; 1853848b8605Smrg case GL_BUFFER_STORAGE_FLAGS: 1854848b8605Smrg if (!ctx->Extensions.ARB_buffer_storage) 1855848b8605Smrg goto invalid_pname; 1856848b8605Smrg *params = bufObj->StorageFlags; 1857848b8605Smrg return; 1858848b8605Smrg default: 1859848b8605Smrg ; /* fall-through */ 1860848b8605Smrg } 1861848b8605Smrg 1862848b8605Smrginvalid_pname: 1863848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameterivARB(pname=%s)", 1864848b8605Smrg _mesa_lookup_enum_by_nr(pname)); 1865848b8605Smrg} 1866848b8605Smrg 1867848b8605Smrg 1868848b8605Smrg/** 1869848b8605Smrg * New in GL 3.2 1870848b8605Smrg * This is pretty much a duplicate of GetBufferParameteriv() but the 1871848b8605Smrg * GL_BUFFER_SIZE_ARB attribute will be 64-bits on a 64-bit system. 1872848b8605Smrg */ 1873848b8605Smrgvoid GLAPIENTRY 1874848b8605Smrg_mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params) 1875848b8605Smrg{ 1876848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1877848b8605Smrg struct gl_buffer_object *bufObj; 1878848b8605Smrg 1879848b8605Smrg bufObj = get_buffer(ctx, "glGetBufferParameteri64v", target, 1880848b8605Smrg GL_INVALID_OPERATION); 1881848b8605Smrg if (!bufObj) 1882848b8605Smrg return; 1883848b8605Smrg 1884848b8605Smrg switch (pname) { 1885848b8605Smrg case GL_BUFFER_SIZE_ARB: 1886848b8605Smrg *params = bufObj->Size; 1887848b8605Smrg return; 1888848b8605Smrg case GL_BUFFER_USAGE_ARB: 1889848b8605Smrg *params = bufObj->Usage; 1890848b8605Smrg return; 1891848b8605Smrg case GL_BUFFER_ACCESS_ARB: 1892848b8605Smrg *params = simplified_access_mode(ctx, 1893848b8605Smrg bufObj->Mappings[MAP_USER].AccessFlags); 1894848b8605Smrg return; 1895848b8605Smrg case GL_BUFFER_ACCESS_FLAGS: 1896848b8605Smrg if (!ctx->Extensions.ARB_map_buffer_range) 1897848b8605Smrg goto invalid_pname; 1898848b8605Smrg *params = bufObj->Mappings[MAP_USER].AccessFlags; 1899848b8605Smrg return; 1900848b8605Smrg case GL_BUFFER_MAPPED_ARB: 1901848b8605Smrg *params = _mesa_bufferobj_mapped(bufObj, MAP_USER); 1902848b8605Smrg return; 1903848b8605Smrg case GL_BUFFER_MAP_OFFSET: 1904848b8605Smrg if (!ctx->Extensions.ARB_map_buffer_range) 1905848b8605Smrg goto invalid_pname; 1906848b8605Smrg *params = bufObj->Mappings[MAP_USER].Offset; 1907848b8605Smrg return; 1908848b8605Smrg case GL_BUFFER_MAP_LENGTH: 1909848b8605Smrg if (!ctx->Extensions.ARB_map_buffer_range) 1910848b8605Smrg goto invalid_pname; 1911848b8605Smrg *params = bufObj->Mappings[MAP_USER].Length; 1912848b8605Smrg return; 1913848b8605Smrg case GL_BUFFER_IMMUTABLE_STORAGE: 1914848b8605Smrg if (!ctx->Extensions.ARB_buffer_storage) 1915848b8605Smrg goto invalid_pname; 1916848b8605Smrg *params = bufObj->Immutable; 1917848b8605Smrg return; 1918848b8605Smrg case GL_BUFFER_STORAGE_FLAGS: 1919848b8605Smrg if (!ctx->Extensions.ARB_buffer_storage) 1920848b8605Smrg goto invalid_pname; 1921848b8605Smrg *params = bufObj->StorageFlags; 1922848b8605Smrg return; 1923848b8605Smrg default: 1924848b8605Smrg ; /* fall-through */ 1925848b8605Smrg } 1926848b8605Smrg 1927848b8605Smrginvalid_pname: 1928848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferParameteri64v(pname=%s)", 1929848b8605Smrg _mesa_lookup_enum_by_nr(pname)); 1930848b8605Smrg} 1931848b8605Smrg 1932848b8605Smrg 1933848b8605Smrgvoid GLAPIENTRY 1934848b8605Smrg_mesa_GetBufferPointerv(GLenum target, GLenum pname, GLvoid **params) 1935848b8605Smrg{ 1936848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1937848b8605Smrg struct gl_buffer_object * bufObj; 1938848b8605Smrg 1939848b8605Smrg if (pname != GL_BUFFER_MAP_POINTER_ARB) { 1940848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointervARB(pname)"); 1941848b8605Smrg return; 1942848b8605Smrg } 1943848b8605Smrg 1944848b8605Smrg bufObj = get_buffer(ctx, "glGetBufferPointervARB", target, 1945848b8605Smrg GL_INVALID_OPERATION); 1946848b8605Smrg if (!bufObj) 1947848b8605Smrg return; 1948848b8605Smrg 1949848b8605Smrg *params = bufObj->Mappings[MAP_USER].Pointer; 1950848b8605Smrg} 1951848b8605Smrg 1952848b8605Smrg 1953848b8605Smrgvoid GLAPIENTRY 1954848b8605Smrg_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, 1955848b8605Smrg GLintptr readOffset, GLintptr writeOffset, 1956848b8605Smrg GLsizeiptr size) 1957848b8605Smrg{ 1958848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1959848b8605Smrg struct gl_buffer_object *src, *dst; 1960848b8605Smrg 1961848b8605Smrg src = get_buffer(ctx, "glCopyBufferSubData", readTarget, 1962848b8605Smrg GL_INVALID_OPERATION); 1963848b8605Smrg if (!src) 1964848b8605Smrg return; 1965848b8605Smrg 1966848b8605Smrg dst = get_buffer(ctx, "glCopyBufferSubData", writeTarget, 1967848b8605Smrg GL_INVALID_OPERATION); 1968848b8605Smrg if (!dst) 1969848b8605Smrg return; 1970848b8605Smrg 1971848b8605Smrg if (_mesa_check_disallowed_mapping(src)) { 1972848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1973848b8605Smrg "glCopyBufferSubData(readBuffer is mapped)"); 1974848b8605Smrg return; 1975848b8605Smrg } 1976848b8605Smrg 1977848b8605Smrg if (_mesa_check_disallowed_mapping(dst)) { 1978848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1979848b8605Smrg "glCopyBufferSubData(writeBuffer is mapped)"); 1980848b8605Smrg return; 1981848b8605Smrg } 1982848b8605Smrg 1983848b8605Smrg if (readOffset < 0) { 1984848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 1985848b8605Smrg "glCopyBufferSubData(readOffset = %d)", (int) readOffset); 1986848b8605Smrg return; 1987848b8605Smrg } 1988848b8605Smrg 1989848b8605Smrg if (writeOffset < 0) { 1990848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 1991848b8605Smrg "glCopyBufferSubData(writeOffset = %d)", (int) writeOffset); 1992848b8605Smrg return; 1993848b8605Smrg } 1994848b8605Smrg 1995848b8605Smrg if (size < 0) { 1996848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 1997848b8605Smrg "glCopyBufferSubData(writeOffset = %d)", (int) size); 1998848b8605Smrg return; 1999848b8605Smrg } 2000848b8605Smrg 2001848b8605Smrg if (readOffset + size > src->Size) { 2002848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2003848b8605Smrg "glCopyBufferSubData(readOffset + size = %d)", 2004848b8605Smrg (int) (readOffset + size)); 2005848b8605Smrg return; 2006848b8605Smrg } 2007848b8605Smrg 2008848b8605Smrg if (writeOffset + size > dst->Size) { 2009848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2010848b8605Smrg "glCopyBufferSubData(writeOffset + size = %d)", 2011848b8605Smrg (int) (writeOffset + size)); 2012848b8605Smrg return; 2013848b8605Smrg } 2014848b8605Smrg 2015848b8605Smrg if (src == dst) { 2016848b8605Smrg if (readOffset + size <= writeOffset) { 2017848b8605Smrg /* OK */ 2018848b8605Smrg } 2019848b8605Smrg else if (writeOffset + size <= readOffset) { 2020848b8605Smrg /* OK */ 2021848b8605Smrg } 2022848b8605Smrg else { 2023848b8605Smrg /* overlapping src/dst is illegal */ 2024848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2025848b8605Smrg "glCopyBufferSubData(overlapping src/dst)"); 2026848b8605Smrg return; 2027848b8605Smrg } 2028848b8605Smrg } 2029848b8605Smrg 2030848b8605Smrg ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size); 2031848b8605Smrg} 2032848b8605Smrg 2033848b8605Smrg 2034848b8605Smrg/** 2035848b8605Smrg * See GL_ARB_map_buffer_range spec 2036848b8605Smrg */ 2037848b8605Smrgvoid * GLAPIENTRY 2038848b8605Smrg_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, 2039848b8605Smrg GLbitfield access) 2040848b8605Smrg{ 2041848b8605Smrg GET_CURRENT_CONTEXT(ctx); 2042848b8605Smrg struct gl_buffer_object *bufObj; 2043848b8605Smrg void *map; 2044848b8605Smrg GLbitfield allowed_access; 2045848b8605Smrg 2046848b8605Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, NULL); 2047848b8605Smrg 2048848b8605Smrg if (!ctx->Extensions.ARB_map_buffer_range) { 2049848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2050848b8605Smrg "glMapBufferRange(extension not supported)"); 2051848b8605Smrg return NULL; 2052848b8605Smrg } 2053848b8605Smrg 2054848b8605Smrg if (offset < 0) { 2055848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2056848b8605Smrg "glMapBufferRange(offset = %ld)", (long)offset); 2057848b8605Smrg return NULL; 2058848b8605Smrg } 2059848b8605Smrg 2060848b8605Smrg if (length < 0) { 2061848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2062848b8605Smrg "glMapBufferRange(length = %ld)", (long)length); 2063848b8605Smrg return NULL; 2064848b8605Smrg } 2065848b8605Smrg 2066848b8605Smrg /* Page 38 of the PDF of the OpenGL ES 3.0 spec says: 2067848b8605Smrg * 2068848b8605Smrg * "An INVALID_OPERATION error is generated for any of the following 2069848b8605Smrg * conditions: 2070848b8605Smrg * 2071848b8605Smrg * * <length> is zero." 2072848b8605Smrg */ 2073848b8605Smrg if (_mesa_is_gles(ctx) && length == 0) { 2074848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2075848b8605Smrg "glMapBufferRange(length = 0)"); 2076848b8605Smrg return NULL; 2077848b8605Smrg } 2078848b8605Smrg 2079848b8605Smrg allowed_access = GL_MAP_READ_BIT | 2080848b8605Smrg GL_MAP_WRITE_BIT | 2081848b8605Smrg GL_MAP_INVALIDATE_RANGE_BIT | 2082848b8605Smrg GL_MAP_INVALIDATE_BUFFER_BIT | 2083848b8605Smrg GL_MAP_FLUSH_EXPLICIT_BIT | 2084848b8605Smrg GL_MAP_UNSYNCHRONIZED_BIT; 2085848b8605Smrg 2086848b8605Smrg if (ctx->Extensions.ARB_buffer_storage) { 2087848b8605Smrg allowed_access |= GL_MAP_PERSISTENT_BIT | 2088848b8605Smrg GL_MAP_COHERENT_BIT; 2089848b8605Smrg } 2090848b8605Smrg 2091848b8605Smrg if (access & ~allowed_access) { 2092848b8605Smrg /* generate an error if any other than allowed bit is set */ 2093848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glMapBufferRange(access)"); 2094848b8605Smrg return NULL; 2095848b8605Smrg } 2096848b8605Smrg 2097848b8605Smrg if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) { 2098848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2099848b8605Smrg "glMapBufferRange(access indicates neither read or write)"); 2100848b8605Smrg return NULL; 2101848b8605Smrg } 2102848b8605Smrg 2103848b8605Smrg if ((access & GL_MAP_READ_BIT) && 2104848b8605Smrg (access & (GL_MAP_INVALIDATE_RANGE_BIT | 2105848b8605Smrg GL_MAP_INVALIDATE_BUFFER_BIT | 2106848b8605Smrg GL_MAP_UNSYNCHRONIZED_BIT))) { 2107848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2108848b8605Smrg "glMapBufferRange(invalid access flags)"); 2109848b8605Smrg return NULL; 2110848b8605Smrg } 2111848b8605Smrg 2112848b8605Smrg if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) && 2113848b8605Smrg ((access & GL_MAP_WRITE_BIT) == 0)) { 2114848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2115848b8605Smrg "glMapBufferRange(invalid access flags)"); 2116848b8605Smrg return NULL; 2117848b8605Smrg } 2118848b8605Smrg 2119848b8605Smrg bufObj = get_buffer(ctx, "glMapBufferRange", target, GL_INVALID_OPERATION); 2120848b8605Smrg if (!bufObj) 2121848b8605Smrg return NULL; 2122848b8605Smrg 2123848b8605Smrg if (access & GL_MAP_READ_BIT && 2124848b8605Smrg !(bufObj->StorageFlags & GL_MAP_READ_BIT)) { 2125848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2126848b8605Smrg "glMapBufferRange(invalid read flag)"); 2127848b8605Smrg return NULL; 2128848b8605Smrg } 2129848b8605Smrg 2130848b8605Smrg if (access & GL_MAP_WRITE_BIT && 2131848b8605Smrg !(bufObj->StorageFlags & GL_MAP_WRITE_BIT)) { 2132848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2133848b8605Smrg "glMapBufferRange(invalid write flag)"); 2134848b8605Smrg return NULL; 2135848b8605Smrg } 2136848b8605Smrg 2137848b8605Smrg if (access & GL_MAP_COHERENT_BIT && 2138848b8605Smrg !(bufObj->StorageFlags & GL_MAP_COHERENT_BIT)) { 2139848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2140848b8605Smrg "glMapBufferRange(invalid coherent flag)"); 2141848b8605Smrg return NULL; 2142848b8605Smrg } 2143848b8605Smrg 2144848b8605Smrg if (access & GL_MAP_PERSISTENT_BIT && 2145848b8605Smrg !(bufObj->StorageFlags & GL_MAP_PERSISTENT_BIT)) { 2146848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2147848b8605Smrg "glMapBufferRange(invalid persistent flag)"); 2148848b8605Smrg return NULL; 2149848b8605Smrg } 2150848b8605Smrg 2151848b8605Smrg if (offset + length > bufObj->Size) { 2152848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2153848b8605Smrg "glMapBufferRange(offset + length > size)"); 2154848b8605Smrg return NULL; 2155848b8605Smrg } 2156848b8605Smrg 2157848b8605Smrg if (_mesa_bufferobj_mapped(bufObj, MAP_USER)) { 2158848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2159848b8605Smrg "glMapBufferRange(buffer already mapped)"); 2160848b8605Smrg return NULL; 2161848b8605Smrg } 2162848b8605Smrg 2163848b8605Smrg if (!bufObj->Size) { 2164848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, 2165848b8605Smrg "glMapBufferRange(buffer size = 0)"); 2166848b8605Smrg return NULL; 2167848b8605Smrg } 2168848b8605Smrg 2169848b8605Smrg /* Mapping zero bytes should return a non-null pointer. */ 2170848b8605Smrg if (!length) { 2171848b8605Smrg static long dummy = 0; 2172848b8605Smrg bufObj->Mappings[MAP_USER].Pointer = &dummy; 2173848b8605Smrg bufObj->Mappings[MAP_USER].Length = length; 2174848b8605Smrg bufObj->Mappings[MAP_USER].Offset = offset; 2175848b8605Smrg bufObj->Mappings[MAP_USER].AccessFlags = access; 2176848b8605Smrg return bufObj->Mappings[MAP_USER].Pointer; 2177848b8605Smrg } 2178848b8605Smrg 2179848b8605Smrg ASSERT(ctx->Driver.MapBufferRange); 2180848b8605Smrg map = ctx->Driver.MapBufferRange(ctx, offset, length, access, bufObj, 2181848b8605Smrg MAP_USER); 2182848b8605Smrg if (!map) { 2183848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glMapBufferARB(map failed)"); 2184848b8605Smrg } 2185848b8605Smrg else { 2186848b8605Smrg /* The driver callback should have set all these fields. 2187848b8605Smrg * This is important because other modules (like VBO) might call 2188848b8605Smrg * the driver function directly. 2189848b8605Smrg */ 2190848b8605Smrg ASSERT(bufObj->Mappings[MAP_USER].Pointer == map); 2191848b8605Smrg ASSERT(bufObj->Mappings[MAP_USER].Length == length); 2192848b8605Smrg ASSERT(bufObj->Mappings[MAP_USER].Offset == offset); 2193848b8605Smrg ASSERT(bufObj->Mappings[MAP_USER].AccessFlags == access); 2194848b8605Smrg } 2195848b8605Smrg 2196848b8605Smrg return map; 2197848b8605Smrg} 2198848b8605Smrg 2199848b8605Smrg 2200848b8605Smrg/** 2201848b8605Smrg * See GL_ARB_map_buffer_range spec 2202848b8605Smrg */ 2203848b8605Smrgvoid GLAPIENTRY 2204848b8605Smrg_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length) 2205848b8605Smrg{ 2206848b8605Smrg GET_CURRENT_CONTEXT(ctx); 2207848b8605Smrg struct gl_buffer_object *bufObj; 2208848b8605Smrg 2209848b8605Smrg if (!ctx->Extensions.ARB_map_buffer_range) { 2210848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2211848b8605Smrg "glFlushMappedBufferRange(extension not supported)"); 2212848b8605Smrg return; 2213848b8605Smrg } 2214848b8605Smrg 2215848b8605Smrg if (offset < 0) { 2216848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2217848b8605Smrg "glFlushMappedBufferRange(offset = %ld)", (long)offset); 2218848b8605Smrg return; 2219848b8605Smrg } 2220848b8605Smrg 2221848b8605Smrg if (length < 0) { 2222848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2223848b8605Smrg "glFlushMappedBufferRange(length = %ld)", (long)length); 2224848b8605Smrg return; 2225848b8605Smrg } 2226848b8605Smrg 2227848b8605Smrg bufObj = get_buffer(ctx, "glFlushMappedBufferRange", target, 2228848b8605Smrg GL_INVALID_OPERATION); 2229848b8605Smrg if (!bufObj) 2230848b8605Smrg return; 2231848b8605Smrg 2232848b8605Smrg if (!_mesa_bufferobj_mapped(bufObj, MAP_USER)) { 2233848b8605Smrg /* buffer is not mapped */ 2234848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2235848b8605Smrg "glFlushMappedBufferRange(buffer is not mapped)"); 2236848b8605Smrg return; 2237848b8605Smrg } 2238848b8605Smrg 2239848b8605Smrg if ((bufObj->Mappings[MAP_USER].AccessFlags & 2240848b8605Smrg GL_MAP_FLUSH_EXPLICIT_BIT) == 0) { 2241848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2242848b8605Smrg "glFlushMappedBufferRange(GL_MAP_FLUSH_EXPLICIT_BIT not set)"); 2243848b8605Smrg return; 2244848b8605Smrg } 2245848b8605Smrg 2246848b8605Smrg if (offset + length > bufObj->Mappings[MAP_USER].Length) { 2247848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2248848b8605Smrg "glFlushMappedBufferRange(offset %ld + length %ld > mapped length %ld)", 2249848b8605Smrg (long)offset, (long)length, 2250848b8605Smrg (long)bufObj->Mappings[MAP_USER].Length); 2251848b8605Smrg return; 2252848b8605Smrg } 2253848b8605Smrg 2254848b8605Smrg ASSERT(bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_WRITE_BIT); 2255848b8605Smrg 2256848b8605Smrg if (ctx->Driver.FlushMappedBufferRange) 2257848b8605Smrg ctx->Driver.FlushMappedBufferRange(ctx, offset, length, bufObj, 2258848b8605Smrg MAP_USER); 2259848b8605Smrg} 2260848b8605Smrg 2261848b8605Smrg 2262848b8605Smrgstatic GLenum 2263848b8605Smrgbuffer_object_purgeable(struct gl_context *ctx, GLuint name, GLenum option) 2264848b8605Smrg{ 2265848b8605Smrg struct gl_buffer_object *bufObj; 2266848b8605Smrg GLenum retval; 2267848b8605Smrg 2268848b8605Smrg bufObj = _mesa_lookup_bufferobj(ctx, name); 2269848b8605Smrg if (!bufObj) { 2270848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2271848b8605Smrg "glObjectPurgeable(name = 0x%x)", name); 2272848b8605Smrg return 0; 2273848b8605Smrg } 2274848b8605Smrg if (!_mesa_is_bufferobj(bufObj)) { 2275848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glObjectPurgeable(buffer 0)" ); 2276848b8605Smrg return 0; 2277848b8605Smrg } 2278848b8605Smrg 2279848b8605Smrg if (bufObj->Purgeable) { 2280848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2281848b8605Smrg "glObjectPurgeable(name = 0x%x) is already purgeable", name); 2282848b8605Smrg return GL_VOLATILE_APPLE; 2283848b8605Smrg } 2284848b8605Smrg 2285848b8605Smrg bufObj->Purgeable = GL_TRUE; 2286848b8605Smrg 2287848b8605Smrg retval = GL_VOLATILE_APPLE; 2288848b8605Smrg if (ctx->Driver.BufferObjectPurgeable) 2289848b8605Smrg retval = ctx->Driver.BufferObjectPurgeable(ctx, bufObj, option); 2290848b8605Smrg 2291848b8605Smrg return retval; 2292848b8605Smrg} 2293848b8605Smrg 2294848b8605Smrg 2295848b8605Smrgstatic GLenum 2296848b8605Smrgrenderbuffer_purgeable(struct gl_context *ctx, GLuint name, GLenum option) 2297848b8605Smrg{ 2298848b8605Smrg struct gl_renderbuffer *bufObj; 2299848b8605Smrg GLenum retval; 2300848b8605Smrg 2301848b8605Smrg bufObj = _mesa_lookup_renderbuffer(ctx, name); 2302848b8605Smrg if (!bufObj) { 2303848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2304848b8605Smrg "glObjectUnpurgeable(name = 0x%x)", name); 2305848b8605Smrg return 0; 2306848b8605Smrg } 2307848b8605Smrg 2308848b8605Smrg if (bufObj->Purgeable) { 2309848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2310848b8605Smrg "glObjectPurgeable(name = 0x%x) is already purgeable", name); 2311848b8605Smrg return GL_VOLATILE_APPLE; 2312848b8605Smrg } 2313848b8605Smrg 2314848b8605Smrg bufObj->Purgeable = GL_TRUE; 2315848b8605Smrg 2316848b8605Smrg retval = GL_VOLATILE_APPLE; 2317848b8605Smrg if (ctx->Driver.RenderObjectPurgeable) 2318848b8605Smrg retval = ctx->Driver.RenderObjectPurgeable(ctx, bufObj, option); 2319848b8605Smrg 2320848b8605Smrg return retval; 2321848b8605Smrg} 2322848b8605Smrg 2323848b8605Smrg 2324848b8605Smrgstatic GLenum 2325848b8605Smrgtexture_object_purgeable(struct gl_context *ctx, GLuint name, GLenum option) 2326848b8605Smrg{ 2327848b8605Smrg struct gl_texture_object *bufObj; 2328848b8605Smrg GLenum retval; 2329848b8605Smrg 2330848b8605Smrg bufObj = _mesa_lookup_texture(ctx, name); 2331848b8605Smrg if (!bufObj) { 2332848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2333848b8605Smrg "glObjectPurgeable(name = 0x%x)", name); 2334848b8605Smrg return 0; 2335848b8605Smrg } 2336848b8605Smrg 2337848b8605Smrg if (bufObj->Purgeable) { 2338848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2339848b8605Smrg "glObjectPurgeable(name = 0x%x) is already purgeable", name); 2340848b8605Smrg return GL_VOLATILE_APPLE; 2341848b8605Smrg } 2342848b8605Smrg 2343848b8605Smrg bufObj->Purgeable = GL_TRUE; 2344848b8605Smrg 2345848b8605Smrg retval = GL_VOLATILE_APPLE; 2346848b8605Smrg if (ctx->Driver.TextureObjectPurgeable) 2347848b8605Smrg retval = ctx->Driver.TextureObjectPurgeable(ctx, bufObj, option); 2348848b8605Smrg 2349848b8605Smrg return retval; 2350848b8605Smrg} 2351848b8605Smrg 2352848b8605Smrg 2353848b8605SmrgGLenum GLAPIENTRY 2354848b8605Smrg_mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option) 2355848b8605Smrg{ 2356848b8605Smrg GLenum retval; 2357848b8605Smrg 2358848b8605Smrg GET_CURRENT_CONTEXT(ctx); 2359848b8605Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 2360848b8605Smrg 2361848b8605Smrg if (name == 0) { 2362848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2363848b8605Smrg "glObjectPurgeable(name = 0x%x)", name); 2364848b8605Smrg return 0; 2365848b8605Smrg } 2366848b8605Smrg 2367848b8605Smrg switch (option) { 2368848b8605Smrg case GL_VOLATILE_APPLE: 2369848b8605Smrg case GL_RELEASED_APPLE: 2370848b8605Smrg /* legal */ 2371848b8605Smrg break; 2372848b8605Smrg default: 2373848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, 2374848b8605Smrg "glObjectPurgeable(name = 0x%x) invalid option: %d", 2375848b8605Smrg name, option); 2376848b8605Smrg return 0; 2377848b8605Smrg } 2378848b8605Smrg 2379848b8605Smrg switch (objectType) { 2380848b8605Smrg case GL_TEXTURE: 2381848b8605Smrg retval = texture_object_purgeable(ctx, name, option); 2382848b8605Smrg break; 2383848b8605Smrg case GL_RENDERBUFFER_EXT: 2384848b8605Smrg retval = renderbuffer_purgeable(ctx, name, option); 2385848b8605Smrg break; 2386848b8605Smrg case GL_BUFFER_OBJECT_APPLE: 2387848b8605Smrg retval = buffer_object_purgeable(ctx, name, option); 2388848b8605Smrg break; 2389848b8605Smrg default: 2390848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, 2391848b8605Smrg "glObjectPurgeable(name = 0x%x) invalid type: %d", 2392848b8605Smrg name, objectType); 2393848b8605Smrg return 0; 2394848b8605Smrg } 2395848b8605Smrg 2396848b8605Smrg /* In strict conformance to the spec, we must only return VOLATILE when 2397848b8605Smrg * when passed the VOLATILE option. Madness. 2398848b8605Smrg * 2399848b8605Smrg * XXX First fix the spec, then fix me. 2400848b8605Smrg */ 2401848b8605Smrg return option == GL_VOLATILE_APPLE ? GL_VOLATILE_APPLE : retval; 2402848b8605Smrg} 2403848b8605Smrg 2404848b8605Smrg 2405848b8605Smrgstatic GLenum 2406848b8605Smrgbuffer_object_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option) 2407848b8605Smrg{ 2408848b8605Smrg struct gl_buffer_object *bufObj; 2409848b8605Smrg GLenum retval; 2410848b8605Smrg 2411848b8605Smrg bufObj = _mesa_lookup_bufferobj(ctx, name); 2412848b8605Smrg if (!bufObj) { 2413848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2414848b8605Smrg "glObjectUnpurgeable(name = 0x%x)", name); 2415848b8605Smrg return 0; 2416848b8605Smrg } 2417848b8605Smrg 2418848b8605Smrg if (! bufObj->Purgeable) { 2419848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2420848b8605Smrg "glObjectUnpurgeable(name = 0x%x) object is " 2421848b8605Smrg " already \"unpurged\"", name); 2422848b8605Smrg return 0; 2423848b8605Smrg } 2424848b8605Smrg 2425848b8605Smrg bufObj->Purgeable = GL_FALSE; 2426848b8605Smrg 2427848b8605Smrg retval = option; 2428848b8605Smrg if (ctx->Driver.BufferObjectUnpurgeable) 2429848b8605Smrg retval = ctx->Driver.BufferObjectUnpurgeable(ctx, bufObj, option); 2430848b8605Smrg 2431848b8605Smrg return retval; 2432848b8605Smrg} 2433848b8605Smrg 2434848b8605Smrg 2435848b8605Smrgstatic GLenum 2436848b8605Smrgrenderbuffer_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option) 2437848b8605Smrg{ 2438848b8605Smrg struct gl_renderbuffer *bufObj; 2439848b8605Smrg GLenum retval; 2440848b8605Smrg 2441848b8605Smrg bufObj = _mesa_lookup_renderbuffer(ctx, name); 2442848b8605Smrg if (!bufObj) { 2443848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2444848b8605Smrg "glObjectUnpurgeable(name = 0x%x)", name); 2445848b8605Smrg return 0; 2446848b8605Smrg } 2447848b8605Smrg 2448848b8605Smrg if (! bufObj->Purgeable) { 2449848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2450848b8605Smrg "glObjectUnpurgeable(name = 0x%x) object is " 2451848b8605Smrg " already \"unpurged\"", name); 2452848b8605Smrg return 0; 2453848b8605Smrg } 2454848b8605Smrg 2455848b8605Smrg bufObj->Purgeable = GL_FALSE; 2456848b8605Smrg 2457848b8605Smrg retval = option; 2458848b8605Smrg if (ctx->Driver.RenderObjectUnpurgeable) 2459848b8605Smrg retval = ctx->Driver.RenderObjectUnpurgeable(ctx, bufObj, option); 2460848b8605Smrg 2461848b8605Smrg return retval; 2462848b8605Smrg} 2463848b8605Smrg 2464848b8605Smrg 2465848b8605Smrgstatic GLenum 2466848b8605Smrgtexture_object_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option) 2467848b8605Smrg{ 2468848b8605Smrg struct gl_texture_object *bufObj; 2469848b8605Smrg GLenum retval; 2470848b8605Smrg 2471848b8605Smrg bufObj = _mesa_lookup_texture(ctx, name); 2472848b8605Smrg if (!bufObj) { 2473848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2474848b8605Smrg "glObjectUnpurgeable(name = 0x%x)", name); 2475848b8605Smrg return 0; 2476848b8605Smrg } 2477848b8605Smrg 2478848b8605Smrg if (! bufObj->Purgeable) { 2479848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2480848b8605Smrg "glObjectUnpurgeable(name = 0x%x) object is" 2481848b8605Smrg " already \"unpurged\"", name); 2482848b8605Smrg return 0; 2483848b8605Smrg } 2484848b8605Smrg 2485848b8605Smrg bufObj->Purgeable = GL_FALSE; 2486848b8605Smrg 2487848b8605Smrg retval = option; 2488848b8605Smrg if (ctx->Driver.TextureObjectUnpurgeable) 2489848b8605Smrg retval = ctx->Driver.TextureObjectUnpurgeable(ctx, bufObj, option); 2490848b8605Smrg 2491848b8605Smrg return retval; 2492848b8605Smrg} 2493848b8605Smrg 2494848b8605Smrg 2495848b8605SmrgGLenum GLAPIENTRY 2496848b8605Smrg_mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option) 2497848b8605Smrg{ 2498848b8605Smrg GET_CURRENT_CONTEXT(ctx); 2499848b8605Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); 2500848b8605Smrg 2501848b8605Smrg if (name == 0) { 2502848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2503848b8605Smrg "glObjectUnpurgeable(name = 0x%x)", name); 2504848b8605Smrg return 0; 2505848b8605Smrg } 2506848b8605Smrg 2507848b8605Smrg switch (option) { 2508848b8605Smrg case GL_RETAINED_APPLE: 2509848b8605Smrg case GL_UNDEFINED_APPLE: 2510848b8605Smrg /* legal */ 2511848b8605Smrg break; 2512848b8605Smrg default: 2513848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, 2514848b8605Smrg "glObjectUnpurgeable(name = 0x%x) invalid option: %d", 2515848b8605Smrg name, option); 2516848b8605Smrg return 0; 2517848b8605Smrg } 2518848b8605Smrg 2519848b8605Smrg switch (objectType) { 2520848b8605Smrg case GL_BUFFER_OBJECT_APPLE: 2521848b8605Smrg return buffer_object_unpurgeable(ctx, name, option); 2522848b8605Smrg case GL_TEXTURE: 2523848b8605Smrg return texture_object_unpurgeable(ctx, name, option); 2524848b8605Smrg case GL_RENDERBUFFER_EXT: 2525848b8605Smrg return renderbuffer_unpurgeable(ctx, name, option); 2526848b8605Smrg default: 2527848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, 2528848b8605Smrg "glObjectUnpurgeable(name = 0x%x) invalid type: %d", 2529848b8605Smrg name, objectType); 2530848b8605Smrg return 0; 2531848b8605Smrg } 2532848b8605Smrg} 2533848b8605Smrg 2534848b8605Smrg 2535848b8605Smrgstatic void 2536848b8605Smrgget_buffer_object_parameteriv(struct gl_context *ctx, GLuint name, 2537848b8605Smrg GLenum pname, GLint *params) 2538848b8605Smrg{ 2539848b8605Smrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, name); 2540848b8605Smrg if (!bufObj) { 2541848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2542848b8605Smrg "glGetObjectParameteriv(name = 0x%x) invalid object", name); 2543848b8605Smrg return; 2544848b8605Smrg } 2545848b8605Smrg 2546848b8605Smrg switch (pname) { 2547848b8605Smrg case GL_PURGEABLE_APPLE: 2548848b8605Smrg *params = bufObj->Purgeable; 2549848b8605Smrg break; 2550848b8605Smrg default: 2551848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, 2552848b8605Smrg "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", 2553848b8605Smrg name, pname); 2554848b8605Smrg break; 2555848b8605Smrg } 2556848b8605Smrg} 2557848b8605Smrg 2558848b8605Smrg 2559848b8605Smrgstatic void 2560848b8605Smrgget_renderbuffer_parameteriv(struct gl_context *ctx, GLuint name, 2561848b8605Smrg GLenum pname, GLint *params) 2562848b8605Smrg{ 2563848b8605Smrg struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name); 2564848b8605Smrg if (!rb) { 2565848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2566848b8605Smrg "glObjectUnpurgeable(name = 0x%x)", name); 2567848b8605Smrg return; 2568848b8605Smrg } 2569848b8605Smrg 2570848b8605Smrg switch (pname) { 2571848b8605Smrg case GL_PURGEABLE_APPLE: 2572848b8605Smrg *params = rb->Purgeable; 2573848b8605Smrg break; 2574848b8605Smrg default: 2575848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, 2576848b8605Smrg "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", 2577848b8605Smrg name, pname); 2578848b8605Smrg break; 2579848b8605Smrg } 2580848b8605Smrg} 2581848b8605Smrg 2582848b8605Smrg 2583848b8605Smrgstatic void 2584848b8605Smrgget_texture_object_parameteriv(struct gl_context *ctx, GLuint name, 2585848b8605Smrg GLenum pname, GLint *params) 2586848b8605Smrg{ 2587848b8605Smrg struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name); 2588848b8605Smrg if (!texObj) { 2589848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2590848b8605Smrg "glObjectUnpurgeable(name = 0x%x)", name); 2591848b8605Smrg return; 2592848b8605Smrg } 2593848b8605Smrg 2594848b8605Smrg switch (pname) { 2595848b8605Smrg case GL_PURGEABLE_APPLE: 2596848b8605Smrg *params = texObj->Purgeable; 2597848b8605Smrg break; 2598848b8605Smrg default: 2599848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, 2600848b8605Smrg "glGetObjectParameteriv(name = 0x%x) invalid enum: %d", 2601848b8605Smrg name, pname); 2602848b8605Smrg break; 2603848b8605Smrg } 2604848b8605Smrg} 2605848b8605Smrg 2606848b8605Smrg 2607848b8605Smrgvoid GLAPIENTRY 2608848b8605Smrg_mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname, 2609848b8605Smrg GLint *params) 2610848b8605Smrg{ 2611848b8605Smrg GET_CURRENT_CONTEXT(ctx); 2612848b8605Smrg 2613848b8605Smrg if (name == 0) { 2614848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2615848b8605Smrg "glGetObjectParameteriv(name = 0x%x)", name); 2616848b8605Smrg return; 2617848b8605Smrg } 2618848b8605Smrg 2619848b8605Smrg switch (objectType) { 2620848b8605Smrg case GL_TEXTURE: 2621848b8605Smrg get_texture_object_parameteriv(ctx, name, pname, params); 2622848b8605Smrg break; 2623848b8605Smrg case GL_BUFFER_OBJECT_APPLE: 2624848b8605Smrg get_buffer_object_parameteriv(ctx, name, pname, params); 2625848b8605Smrg break; 2626848b8605Smrg case GL_RENDERBUFFER_EXT: 2627848b8605Smrg get_renderbuffer_parameteriv(ctx, name, pname, params); 2628848b8605Smrg break; 2629848b8605Smrg default: 2630848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, 2631848b8605Smrg "glGetObjectParameteriv(name = 0x%x) invalid type: %d", 2632848b8605Smrg name, objectType); 2633848b8605Smrg } 2634848b8605Smrg} 2635848b8605Smrg 2636848b8605Smrg/** 2637848b8605Smrg * Binds a buffer object to a uniform buffer binding point. 2638848b8605Smrg * 2639848b8605Smrg * The caller is responsible for flushing vertices and updating 2640848b8605Smrg * NewDriverState. 2641848b8605Smrg */ 2642848b8605Smrgstatic void 2643848b8605Smrgset_ubo_binding(struct gl_context *ctx, 2644848b8605Smrg struct gl_uniform_buffer_binding *binding, 2645848b8605Smrg struct gl_buffer_object *bufObj, 2646848b8605Smrg GLintptr offset, 2647848b8605Smrg GLsizeiptr size, 2648848b8605Smrg GLboolean autoSize) 2649848b8605Smrg{ 2650848b8605Smrg _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj); 2651848b8605Smrg 2652848b8605Smrg binding->Offset = offset; 2653848b8605Smrg binding->Size = size; 2654848b8605Smrg binding->AutomaticSize = autoSize; 2655848b8605Smrg} 2656848b8605Smrg 2657848b8605Smrg/** 2658848b8605Smrg * Binds a buffer object to a uniform buffer binding point. 2659848b8605Smrg * 2660848b8605Smrg * Unlike set_ubo_binding(), this function also flushes vertices 2661848b8605Smrg * and updates NewDriverState. It also checks if the binding 2662848b8605Smrg * has actually changed before updating it. 2663848b8605Smrg */ 2664848b8605Smrgstatic void 2665848b8605Smrgbind_uniform_buffer(struct gl_context *ctx, 2666848b8605Smrg GLuint index, 2667848b8605Smrg struct gl_buffer_object *bufObj, 2668848b8605Smrg GLintptr offset, 2669848b8605Smrg GLsizeiptr size, 2670848b8605Smrg GLboolean autoSize) 2671848b8605Smrg{ 2672848b8605Smrg struct gl_uniform_buffer_binding *binding = 2673848b8605Smrg &ctx->UniformBufferBindings[index]; 2674848b8605Smrg 2675848b8605Smrg if (binding->BufferObject == bufObj && 2676848b8605Smrg binding->Offset == offset && 2677848b8605Smrg binding->Size == size && 2678848b8605Smrg binding->AutomaticSize == autoSize) { 2679848b8605Smrg return; 2680848b8605Smrg } 2681848b8605Smrg 2682848b8605Smrg FLUSH_VERTICES(ctx, 0); 2683848b8605Smrg ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer; 2684848b8605Smrg 2685848b8605Smrg set_ubo_binding(ctx, binding, bufObj, offset, size, autoSize); 2686848b8605Smrg} 2687848b8605Smrg 2688848b8605Smrg/** 2689848b8605Smrg * Bind a region of a buffer object to a uniform block binding point. 2690848b8605Smrg * \param index the uniform buffer binding point index 2691848b8605Smrg * \param bufObj the buffer object 2692848b8605Smrg * \param offset offset to the start of buffer object region 2693848b8605Smrg * \param size size of the buffer object region 2694848b8605Smrg */ 2695848b8605Smrgstatic void 2696848b8605Smrgbind_buffer_range_uniform_buffer(struct gl_context *ctx, 2697848b8605Smrg GLuint index, 2698848b8605Smrg struct gl_buffer_object *bufObj, 2699848b8605Smrg GLintptr offset, 2700848b8605Smrg GLsizeiptr size) 2701848b8605Smrg{ 2702848b8605Smrg if (index >= ctx->Const.MaxUniformBufferBindings) { 2703848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index); 2704848b8605Smrg return; 2705848b8605Smrg } 2706848b8605Smrg 2707848b8605Smrg if (offset & (ctx->Const.UniformBufferOffsetAlignment - 1)) { 2708848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2709848b8605Smrg "glBindBufferRange(offset misalgned %d/%d)", (int) offset, 2710848b8605Smrg ctx->Const.UniformBufferOffsetAlignment); 2711848b8605Smrg return; 2712848b8605Smrg } 2713848b8605Smrg 2714848b8605Smrg if (bufObj == ctx->Shared->NullBufferObj) { 2715848b8605Smrg offset = -1; 2716848b8605Smrg size = -1; 2717848b8605Smrg } 2718848b8605Smrg 2719848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj); 2720848b8605Smrg bind_uniform_buffer(ctx, index, bufObj, offset, size, GL_FALSE); 2721848b8605Smrg} 2722848b8605Smrg 2723848b8605Smrg 2724848b8605Smrg/** 2725848b8605Smrg * Bind a buffer object to a uniform block binding point. 2726848b8605Smrg * As above, but offset = 0. 2727848b8605Smrg */ 2728848b8605Smrgstatic void 2729848b8605Smrgbind_buffer_base_uniform_buffer(struct gl_context *ctx, 2730848b8605Smrg GLuint index, 2731848b8605Smrg struct gl_buffer_object *bufObj) 2732848b8605Smrg{ 2733848b8605Smrg if (index >= ctx->Const.MaxUniformBufferBindings) { 2734848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index); 2735848b8605Smrg return; 2736848b8605Smrg } 2737848b8605Smrg 2738848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj); 2739848b8605Smrg 2740848b8605Smrg if (bufObj == ctx->Shared->NullBufferObj) 2741848b8605Smrg bind_uniform_buffer(ctx, index, bufObj, -1, -1, GL_TRUE); 2742848b8605Smrg else 2743848b8605Smrg bind_uniform_buffer(ctx, index, bufObj, 0, 0, GL_TRUE); 2744848b8605Smrg} 2745848b8605Smrg 2746848b8605Smrg/** 2747848b8605Smrg * Binds a buffer object to an atomic buffer binding point. 2748848b8605Smrg * 2749848b8605Smrg * The caller is responsible for validating the offset, 2750848b8605Smrg * flushing the vertices and updating NewDriverState. 2751848b8605Smrg */ 2752848b8605Smrgstatic void 2753848b8605Smrgset_atomic_buffer_binding(struct gl_context *ctx, 2754848b8605Smrg struct gl_atomic_buffer_binding *binding, 2755848b8605Smrg struct gl_buffer_object *bufObj, 2756848b8605Smrg GLintptr offset, 2757848b8605Smrg GLsizeiptr size) 2758848b8605Smrg{ 2759848b8605Smrg _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj); 2760848b8605Smrg 2761848b8605Smrg if (bufObj == ctx->Shared->NullBufferObj) { 2762848b8605Smrg binding->Offset = -1; 2763848b8605Smrg binding->Size = -1; 2764848b8605Smrg } else { 2765848b8605Smrg binding->Offset = offset; 2766848b8605Smrg binding->Size = size; 2767848b8605Smrg } 2768848b8605Smrg} 2769848b8605Smrg 2770848b8605Smrg/** 2771848b8605Smrg * Binds a buffer object to an atomic buffer binding point. 2772848b8605Smrg * 2773848b8605Smrg * Unlike set_atomic_buffer_binding(), this function also validates the 2774848b8605Smrg * index and offset, flushes vertices, and updates NewDriverState. 2775848b8605Smrg * It also checks if the binding has actually changing before 2776848b8605Smrg * updating it. 2777848b8605Smrg */ 2778848b8605Smrgstatic void 2779848b8605Smrgbind_atomic_buffer(struct gl_context *ctx, 2780848b8605Smrg unsigned index, 2781848b8605Smrg struct gl_buffer_object *bufObj, 2782848b8605Smrg GLintptr offset, 2783848b8605Smrg GLsizeiptr size, 2784848b8605Smrg const char *name) 2785848b8605Smrg{ 2786848b8605Smrg struct gl_atomic_buffer_binding *binding; 2787848b8605Smrg 2788848b8605Smrg if (index >= ctx->Const.MaxAtomicBufferBindings) { 2789848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%d)", name, index); 2790848b8605Smrg return; 2791848b8605Smrg } 2792848b8605Smrg 2793848b8605Smrg if (offset & (ATOMIC_COUNTER_SIZE - 1)) { 2794848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2795848b8605Smrg "%s(offset misalgned %d/%d)", name, (int) offset, 2796848b8605Smrg ATOMIC_COUNTER_SIZE); 2797848b8605Smrg return; 2798848b8605Smrg } 2799848b8605Smrg 2800848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, bufObj); 2801848b8605Smrg 2802848b8605Smrg binding = &ctx->AtomicBufferBindings[index]; 2803848b8605Smrg if (binding->BufferObject == bufObj && 2804848b8605Smrg binding->Offset == offset && 2805848b8605Smrg binding->Size == size) { 2806848b8605Smrg return; 2807848b8605Smrg } 2808848b8605Smrg 2809848b8605Smrg FLUSH_VERTICES(ctx, 0); 2810848b8605Smrg ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer; 2811848b8605Smrg 2812848b8605Smrg set_atomic_buffer_binding(ctx, binding, bufObj, offset, size); 2813848b8605Smrg} 2814848b8605Smrg 2815848b8605Smrgstatic inline bool 2816848b8605Smrgbind_buffers_check_offset_and_size(struct gl_context *ctx, 2817848b8605Smrg GLuint index, 2818848b8605Smrg const GLintptr *offsets, 2819848b8605Smrg const GLsizeiptr *sizes) 2820848b8605Smrg{ 2821848b8605Smrg if (offsets[index] < 0) { 2822848b8605Smrg /* The ARB_multi_bind spec says: 2823848b8605Smrg * 2824848b8605Smrg * "An INVALID_VALUE error is generated by BindBuffersRange if any 2825848b8605Smrg * value in <offsets> is less than zero (per binding)." 2826848b8605Smrg */ 2827848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2828848b8605Smrg "glBindBuffersRange(offsets[%u]=%" PRId64 " < 0)", 2829848b8605Smrg index, (int64_t) offsets[index]); 2830848b8605Smrg return false; 2831848b8605Smrg } 2832848b8605Smrg 2833848b8605Smrg if (sizes[index] <= 0) { 2834848b8605Smrg /* The ARB_multi_bind spec says: 2835848b8605Smrg * 2836848b8605Smrg * "An INVALID_VALUE error is generated by BindBuffersRange if any 2837848b8605Smrg * value in <sizes> is less than or equal to zero (per binding)." 2838848b8605Smrg */ 2839848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2840848b8605Smrg "glBindBuffersRange(sizes[%u]=%" PRId64 " <= 0)", 2841848b8605Smrg index, (int64_t) sizes[index]); 2842848b8605Smrg return false; 2843848b8605Smrg } 2844848b8605Smrg 2845848b8605Smrg return true; 2846848b8605Smrg} 2847848b8605Smrg 2848848b8605Smrgstatic bool 2849848b8605Smrgerror_check_bind_uniform_buffers(struct gl_context *ctx, 2850848b8605Smrg GLuint first, GLsizei count, 2851848b8605Smrg const char *caller) 2852848b8605Smrg{ 2853848b8605Smrg if (!ctx->Extensions.ARB_uniform_buffer_object) { 2854848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, 2855848b8605Smrg "%s(target=GL_UNIFORM_BUFFER)", caller); 2856848b8605Smrg return false; 2857848b8605Smrg } 2858848b8605Smrg 2859848b8605Smrg /* The ARB_multi_bind_spec says: 2860848b8605Smrg * 2861848b8605Smrg * "An INVALID_OPERATION error is generated if <first> + <count> is 2862848b8605Smrg * greater than the number of target-specific indexed binding points, 2863848b8605Smrg * as described in section 6.7.1." 2864848b8605Smrg */ 2865848b8605Smrg if (first + count > ctx->Const.MaxUniformBufferBindings) { 2866848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2867848b8605Smrg "%s(first=%u + count=%d > the value of " 2868848b8605Smrg "GL_MAX_UNIFORM_BUFFER_BINDINGS=%u)", 2869848b8605Smrg caller, first, count, 2870848b8605Smrg ctx->Const.MaxUniformBufferBindings); 2871848b8605Smrg return false; 2872848b8605Smrg } 2873848b8605Smrg 2874848b8605Smrg return true; 2875848b8605Smrg} 2876848b8605Smrg 2877848b8605Smrg/** 2878848b8605Smrg * Unbind all uniform buffers in the range 2879848b8605Smrg * <first> through <first>+<count>-1 2880848b8605Smrg */ 2881848b8605Smrgstatic void 2882848b8605Smrgunbind_uniform_buffers(struct gl_context *ctx, GLuint first, GLsizei count) 2883848b8605Smrg{ 2884848b8605Smrg struct gl_buffer_object *bufObj = ctx->Shared->NullBufferObj; 2885848b8605Smrg GLuint i; 2886848b8605Smrg 2887848b8605Smrg for (i = 0; i < count; i++) 2888848b8605Smrg set_ubo_binding(ctx, &ctx->UniformBufferBindings[first + i], 2889848b8605Smrg bufObj, -1, -1, GL_TRUE); 2890848b8605Smrg} 2891848b8605Smrg 2892848b8605Smrgstatic void 2893848b8605Smrgbind_uniform_buffers_base(struct gl_context *ctx, GLuint first, GLsizei count, 2894848b8605Smrg const GLuint *buffers) 2895848b8605Smrg{ 2896848b8605Smrg GLuint i; 2897848b8605Smrg 2898848b8605Smrg if (!error_check_bind_uniform_buffers(ctx, first, count, "glBindBuffersBase")) 2899848b8605Smrg return; 2900848b8605Smrg 2901848b8605Smrg /* Assume that at least one binding will be changed */ 2902848b8605Smrg FLUSH_VERTICES(ctx, 0); 2903848b8605Smrg ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer; 2904848b8605Smrg 2905848b8605Smrg if (!buffers) { 2906848b8605Smrg /* The ARB_multi_bind spec says: 2907848b8605Smrg * 2908848b8605Smrg * "If <buffers> is NULL, all bindings from <first> through 2909848b8605Smrg * <first>+<count>-1 are reset to their unbound (zero) state." 2910848b8605Smrg */ 2911848b8605Smrg unbind_uniform_buffers(ctx, first, count); 2912848b8605Smrg return; 2913848b8605Smrg } 2914848b8605Smrg 2915848b8605Smrg /* Note that the error semantics for multi-bind commands differ from 2916848b8605Smrg * those of other GL commands. 2917848b8605Smrg * 2918848b8605Smrg * The Issues section in the ARB_multi_bind spec says: 2919848b8605Smrg * 2920848b8605Smrg * "(11) Typically, OpenGL specifies that if an error is generated by a 2921848b8605Smrg * command, that command has no effect. This is somewhat 2922848b8605Smrg * unfortunate for multi-bind commands, because it would require a 2923848b8605Smrg * first pass to scan the entire list of bound objects for errors 2924848b8605Smrg * and then a second pass to actually perform the bindings. 2925848b8605Smrg * Should we have different error semantics? 2926848b8605Smrg * 2927848b8605Smrg * RESOLVED: Yes. In this specification, when the parameters for 2928848b8605Smrg * one of the <count> binding points are invalid, that binding point 2929848b8605Smrg * is not updated and an error will be generated. However, other 2930848b8605Smrg * binding points in the same command will be updated if their 2931848b8605Smrg * parameters are valid and no other error occurs." 2932848b8605Smrg */ 2933848b8605Smrg 2934848b8605Smrg _mesa_begin_bufferobj_lookups(ctx); 2935848b8605Smrg 2936848b8605Smrg for (i = 0; i < count; i++) { 2937848b8605Smrg struct gl_uniform_buffer_binding *binding = 2938848b8605Smrg &ctx->UniformBufferBindings[first + i]; 2939848b8605Smrg struct gl_buffer_object *bufObj; 2940848b8605Smrg 2941848b8605Smrg if (binding->BufferObject && binding->BufferObject->Name == buffers[i]) 2942848b8605Smrg bufObj = binding->BufferObject; 2943848b8605Smrg else 2944848b8605Smrg bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, 2945848b8605Smrg "glBindBuffersBase"); 2946848b8605Smrg 2947848b8605Smrg if (bufObj) { 2948848b8605Smrg if (bufObj == ctx->Shared->NullBufferObj) 2949848b8605Smrg set_ubo_binding(ctx, binding, bufObj, -1, -1, GL_TRUE); 2950848b8605Smrg else 2951848b8605Smrg set_ubo_binding(ctx, binding, bufObj, 0, 0, GL_TRUE); 2952848b8605Smrg } 2953848b8605Smrg } 2954848b8605Smrg 2955848b8605Smrg _mesa_end_bufferobj_lookups(ctx); 2956848b8605Smrg} 2957848b8605Smrg 2958848b8605Smrgstatic void 2959848b8605Smrgbind_uniform_buffers_range(struct gl_context *ctx, GLuint first, GLsizei count, 2960848b8605Smrg const GLuint *buffers, 2961848b8605Smrg const GLintptr *offsets, const GLsizeiptr *sizes) 2962848b8605Smrg{ 2963848b8605Smrg GLuint i; 2964848b8605Smrg 2965848b8605Smrg if (!error_check_bind_uniform_buffers(ctx, first, count, 2966848b8605Smrg "glBindBuffersRange")) 2967848b8605Smrg return; 2968848b8605Smrg 2969848b8605Smrg /* Assume that at least one binding will be changed */ 2970848b8605Smrg FLUSH_VERTICES(ctx, 0); 2971848b8605Smrg ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer; 2972848b8605Smrg 2973848b8605Smrg if (!buffers) { 2974848b8605Smrg /* The ARB_multi_bind spec says: 2975848b8605Smrg * 2976848b8605Smrg * "If <buffers> is NULL, all bindings from <first> through 2977848b8605Smrg * <first>+<count>-1 are reset to their unbound (zero) state. 2978848b8605Smrg * In this case, the offsets and sizes associated with the 2979848b8605Smrg * binding points are set to default values, ignoring 2980848b8605Smrg * <offsets> and <sizes>." 2981848b8605Smrg */ 2982848b8605Smrg unbind_uniform_buffers(ctx, first, count); 2983848b8605Smrg return; 2984848b8605Smrg } 2985848b8605Smrg 2986848b8605Smrg /* Note that the error semantics for multi-bind commands differ from 2987848b8605Smrg * those of other GL commands. 2988848b8605Smrg * 2989848b8605Smrg * The Issues section in the ARB_multi_bind spec says: 2990848b8605Smrg * 2991848b8605Smrg * "(11) Typically, OpenGL specifies that if an error is generated by a 2992848b8605Smrg * command, that command has no effect. This is somewhat 2993848b8605Smrg * unfortunate for multi-bind commands, because it would require a 2994848b8605Smrg * first pass to scan the entire list of bound objects for errors 2995848b8605Smrg * and then a second pass to actually perform the bindings. 2996848b8605Smrg * Should we have different error semantics? 2997848b8605Smrg * 2998848b8605Smrg * RESOLVED: Yes. In this specification, when the parameters for 2999848b8605Smrg * one of the <count> binding points are invalid, that binding point 3000848b8605Smrg * is not updated and an error will be generated. However, other 3001848b8605Smrg * binding points in the same command will be updated if their 3002848b8605Smrg * parameters are valid and no other error occurs." 3003848b8605Smrg */ 3004848b8605Smrg 3005848b8605Smrg _mesa_begin_bufferobj_lookups(ctx); 3006848b8605Smrg 3007848b8605Smrg for (i = 0; i < count; i++) { 3008848b8605Smrg struct gl_uniform_buffer_binding *binding = 3009848b8605Smrg &ctx->UniformBufferBindings[first + i]; 3010848b8605Smrg struct gl_buffer_object *bufObj; 3011848b8605Smrg 3012848b8605Smrg if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes)) 3013848b8605Smrg continue; 3014848b8605Smrg 3015848b8605Smrg /* The ARB_multi_bind spec says: 3016848b8605Smrg * 3017848b8605Smrg * "An INVALID_VALUE error is generated by BindBuffersRange if any 3018848b8605Smrg * pair of values in <offsets> and <sizes> does not respectively 3019848b8605Smrg * satisfy the constraints described for those parameters for the 3020848b8605Smrg * specified target, as described in section 6.7.1 (per binding)." 3021848b8605Smrg * 3022848b8605Smrg * Section 6.7.1 refers to table 6.5, which says: 3023848b8605Smrg * 3024848b8605Smrg * "┌───────────────────────────────────────────────────────────────┐ 3025848b8605Smrg * │ Uniform buffer array bindings (see sec. 7.6) │ 3026848b8605Smrg * ├─────────────────────┬─────────────────────────────────────────┤ 3027848b8605Smrg * │ ... │ ... │ 3028848b8605Smrg * │ offset restriction │ multiple of value of UNIFORM_BUFFER_- │ 3029848b8605Smrg * │ │ OFFSET_ALIGNMENT │ 3030848b8605Smrg * │ ... │ ... │ 3031848b8605Smrg * │ size restriction │ none │ 3032848b8605Smrg * └─────────────────────┴─────────────────────────────────────────┘" 3033848b8605Smrg */ 3034848b8605Smrg if (offsets[i] & (ctx->Const.UniformBufferOffsetAlignment - 1)) { 3035848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3036848b8605Smrg "glBindBuffersRange(offsets[%u]=%" PRId64 3037848b8605Smrg " is misaligned; it must be a multiple of the value of " 3038848b8605Smrg "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT=%u when " 3039848b8605Smrg "target=GL_UNIFORM_BUFFER)", 3040848b8605Smrg i, (int64_t) offsets[i], 3041848b8605Smrg ctx->Const.UniformBufferOffsetAlignment); 3042848b8605Smrg continue; 3043848b8605Smrg } 3044848b8605Smrg 3045848b8605Smrg if (binding->BufferObject && binding->BufferObject->Name == buffers[i]) 3046848b8605Smrg bufObj = binding->BufferObject; 3047848b8605Smrg else 3048848b8605Smrg bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, 3049848b8605Smrg "glBindBuffersRange"); 3050848b8605Smrg 3051848b8605Smrg if (bufObj) { 3052848b8605Smrg if (bufObj == ctx->Shared->NullBufferObj) 3053848b8605Smrg set_ubo_binding(ctx, binding, bufObj, -1, -1, GL_FALSE); 3054848b8605Smrg else 3055848b8605Smrg set_ubo_binding(ctx, binding, bufObj, 3056848b8605Smrg offsets[i], sizes[i], GL_FALSE); 3057848b8605Smrg } 3058848b8605Smrg } 3059848b8605Smrg 3060848b8605Smrg _mesa_end_bufferobj_lookups(ctx); 3061848b8605Smrg} 3062848b8605Smrg 3063848b8605Smrgstatic bool 3064848b8605Smrgerror_check_bind_xfb_buffers(struct gl_context *ctx, 3065848b8605Smrg struct gl_transform_feedback_object *tfObj, 3066848b8605Smrg GLuint first, GLsizei count, const char *caller) 3067848b8605Smrg{ 3068848b8605Smrg if (!ctx->Extensions.EXT_transform_feedback) { 3069848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, 3070848b8605Smrg "%s(target=GL_TRANSFORM_FEEDBACK_BUFFER)", caller); 3071848b8605Smrg return false; 3072848b8605Smrg } 3073848b8605Smrg 3074848b8605Smrg /* Page 398 of the PDF of the OpenGL 4.4 (Core Profile) spec says: 3075848b8605Smrg * 3076848b8605Smrg * "An INVALID_OPERATION error is generated : 3077848b8605Smrg * 3078848b8605Smrg * ... 3079848b8605Smrg * • by BindBufferRange or BindBufferBase if target is TRANSFORM_- 3080848b8605Smrg * FEEDBACK_BUFFER and transform feedback is currently active." 3081848b8605Smrg * 3082848b8605Smrg * We assume that this is also meant to apply to BindBuffersRange 3083848b8605Smrg * and BindBuffersBase. 3084848b8605Smrg */ 3085848b8605Smrg if (tfObj->Active) { 3086848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3087848b8605Smrg "%s(Changing transform feedback buffers while " 3088848b8605Smrg "transform feedback is active)", caller); 3089848b8605Smrg return false; 3090848b8605Smrg } 3091848b8605Smrg 3092848b8605Smrg /* The ARB_multi_bind_spec says: 3093848b8605Smrg * 3094848b8605Smrg * "An INVALID_OPERATION error is generated if <first> + <count> is 3095848b8605Smrg * greater than the number of target-specific indexed binding points, 3096848b8605Smrg * as described in section 6.7.1." 3097848b8605Smrg */ 3098848b8605Smrg if (first + count > ctx->Const.MaxTransformFeedbackBuffers) { 3099848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3100848b8605Smrg "%s(first=%u + count=%d > the value of " 3101848b8605Smrg "GL_MAX_TRANSFORM_FEEDBACK_BUFFERS=%u)", 3102848b8605Smrg caller, first, count, 3103848b8605Smrg ctx->Const.MaxTransformFeedbackBuffers); 3104848b8605Smrg return false; 3105848b8605Smrg } 3106848b8605Smrg 3107848b8605Smrg return true; 3108848b8605Smrg} 3109848b8605Smrg 3110848b8605Smrg/** 3111848b8605Smrg * Unbind all transform feedback buffers in the range 3112848b8605Smrg * <first> through <first>+<count>-1 3113848b8605Smrg */ 3114848b8605Smrgstatic void 3115848b8605Smrgunbind_xfb_buffers(struct gl_context *ctx, 3116848b8605Smrg struct gl_transform_feedback_object *tfObj, 3117848b8605Smrg GLuint first, GLsizei count) 3118848b8605Smrg{ 3119848b8605Smrg struct gl_buffer_object * const bufObj = ctx->Shared->NullBufferObj; 3120848b8605Smrg GLuint i; 3121848b8605Smrg 3122848b8605Smrg for (i = 0; i < count; i++) 3123848b8605Smrg _mesa_set_transform_feedback_binding(ctx, tfObj, first + i, 3124848b8605Smrg bufObj, 0, 0); 3125848b8605Smrg} 3126848b8605Smrg 3127848b8605Smrgstatic void 3128848b8605Smrgbind_xfb_buffers_base(struct gl_context *ctx, 3129848b8605Smrg GLuint first, GLsizei count, 3130848b8605Smrg const GLuint *buffers) 3131848b8605Smrg{ 3132848b8605Smrg struct gl_transform_feedback_object *tfObj = 3133848b8605Smrg ctx->TransformFeedback.CurrentObject; 3134848b8605Smrg GLuint i; 3135848b8605Smrg 3136848b8605Smrg if (!error_check_bind_xfb_buffers(ctx, tfObj, first, count, 3137848b8605Smrg "glBindBuffersBase")) 3138848b8605Smrg return; 3139848b8605Smrg 3140848b8605Smrg /* Assume that at least one binding will be changed */ 3141848b8605Smrg FLUSH_VERTICES(ctx, 0); 3142848b8605Smrg ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback; 3143848b8605Smrg 3144848b8605Smrg if (!buffers) { 3145848b8605Smrg /* The ARB_multi_bind spec says: 3146848b8605Smrg * 3147848b8605Smrg * "If <buffers> is NULL, all bindings from <first> through 3148848b8605Smrg * <first>+<count>-1 are reset to their unbound (zero) state." 3149848b8605Smrg */ 3150848b8605Smrg unbind_xfb_buffers(ctx, tfObj, first, count); 3151848b8605Smrg return; 3152848b8605Smrg } 3153848b8605Smrg 3154848b8605Smrg /* Note that the error semantics for multi-bind commands differ from 3155848b8605Smrg * those of other GL commands. 3156848b8605Smrg * 3157848b8605Smrg * The Issues section in the ARB_multi_bind spec says: 3158848b8605Smrg * 3159848b8605Smrg * "(11) Typically, OpenGL specifies that if an error is generated by a 3160848b8605Smrg * command, that command has no effect. This is somewhat 3161848b8605Smrg * unfortunate for multi-bind commands, because it would require a 3162848b8605Smrg * first pass to scan the entire list of bound objects for errors 3163848b8605Smrg * and then a second pass to actually perform the bindings. 3164848b8605Smrg * Should we have different error semantics? 3165848b8605Smrg * 3166848b8605Smrg * RESOLVED: Yes. In this specification, when the parameters for 3167848b8605Smrg * one of the <count> binding points are invalid, that binding point 3168848b8605Smrg * is not updated and an error will be generated. However, other 3169848b8605Smrg * binding points in the same command will be updated if their 3170848b8605Smrg * parameters are valid and no other error occurs." 3171848b8605Smrg */ 3172848b8605Smrg 3173848b8605Smrg _mesa_begin_bufferobj_lookups(ctx); 3174848b8605Smrg 3175848b8605Smrg for (i = 0; i < count; i++) { 3176848b8605Smrg struct gl_buffer_object * const boundBufObj = tfObj->Buffers[first + i]; 3177848b8605Smrg struct gl_buffer_object *bufObj; 3178848b8605Smrg 3179848b8605Smrg if (boundBufObj && boundBufObj->Name == buffers[i]) 3180848b8605Smrg bufObj = boundBufObj; 3181848b8605Smrg else 3182848b8605Smrg bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, 3183848b8605Smrg "glBindBuffersBase"); 3184848b8605Smrg 3185848b8605Smrg if (bufObj) 3186848b8605Smrg _mesa_set_transform_feedback_binding(ctx, tfObj, first + i, 3187848b8605Smrg bufObj, 0, 0); 3188848b8605Smrg } 3189848b8605Smrg 3190848b8605Smrg _mesa_end_bufferobj_lookups(ctx); 3191848b8605Smrg} 3192848b8605Smrg 3193848b8605Smrgstatic void 3194848b8605Smrgbind_xfb_buffers_range(struct gl_context *ctx, 3195848b8605Smrg GLuint first, GLsizei count, 3196848b8605Smrg const GLuint *buffers, 3197848b8605Smrg const GLintptr *offsets, 3198848b8605Smrg const GLsizeiptr *sizes) 3199848b8605Smrg{ 3200848b8605Smrg struct gl_transform_feedback_object *tfObj = 3201848b8605Smrg ctx->TransformFeedback.CurrentObject; 3202848b8605Smrg GLuint i; 3203848b8605Smrg 3204848b8605Smrg if (!error_check_bind_xfb_buffers(ctx, tfObj, first, count, 3205848b8605Smrg "glBindBuffersRange")) 3206848b8605Smrg return; 3207848b8605Smrg 3208848b8605Smrg /* Assume that at least one binding will be changed */ 3209848b8605Smrg FLUSH_VERTICES(ctx, 0); 3210848b8605Smrg ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback; 3211848b8605Smrg 3212848b8605Smrg if (!buffers) { 3213848b8605Smrg /* The ARB_multi_bind spec says: 3214848b8605Smrg * 3215848b8605Smrg * "If <buffers> is NULL, all bindings from <first> through 3216848b8605Smrg * <first>+<count>-1 are reset to their unbound (zero) state. 3217848b8605Smrg * In this case, the offsets and sizes associated with the 3218848b8605Smrg * binding points are set to default values, ignoring 3219848b8605Smrg * <offsets> and <sizes>." 3220848b8605Smrg */ 3221848b8605Smrg unbind_xfb_buffers(ctx, tfObj, first, count); 3222848b8605Smrg return; 3223848b8605Smrg } 3224848b8605Smrg 3225848b8605Smrg /* Note that the error semantics for multi-bind commands differ from 3226848b8605Smrg * those of other GL commands. 3227848b8605Smrg * 3228848b8605Smrg * The Issues section in the ARB_multi_bind spec says: 3229848b8605Smrg * 3230848b8605Smrg * "(11) Typically, OpenGL specifies that if an error is generated by a 3231848b8605Smrg * command, that command has no effect. This is somewhat 3232848b8605Smrg * unfortunate for multi-bind commands, because it would require a 3233848b8605Smrg * first pass to scan the entire list of bound objects for errors 3234848b8605Smrg * and then a second pass to actually perform the bindings. 3235848b8605Smrg * Should we have different error semantics? 3236848b8605Smrg * 3237848b8605Smrg * RESOLVED: Yes. In this specification, when the parameters for 3238848b8605Smrg * one of the <count> binding points are invalid, that binding point 3239848b8605Smrg * is not updated and an error will be generated. However, other 3240848b8605Smrg * binding points in the same command will be updated if their 3241848b8605Smrg * parameters are valid and no other error occurs." 3242848b8605Smrg */ 3243848b8605Smrg 3244848b8605Smrg _mesa_begin_bufferobj_lookups(ctx); 3245848b8605Smrg 3246848b8605Smrg for (i = 0; i < count; i++) { 3247848b8605Smrg const GLuint index = first + i; 3248848b8605Smrg struct gl_buffer_object * const boundBufObj = tfObj->Buffers[index]; 3249848b8605Smrg struct gl_buffer_object *bufObj; 3250848b8605Smrg 3251848b8605Smrg if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes)) 3252848b8605Smrg continue; 3253848b8605Smrg 3254848b8605Smrg /* The ARB_multi_bind spec says: 3255848b8605Smrg * 3256848b8605Smrg * "An INVALID_VALUE error is generated by BindBuffersRange if any 3257848b8605Smrg * pair of values in <offsets> and <sizes> does not respectively 3258848b8605Smrg * satisfy the constraints described for those parameters for the 3259848b8605Smrg * specified target, as described in section 6.7.1 (per binding)." 3260848b8605Smrg * 3261848b8605Smrg * Section 6.7.1 refers to table 6.5, which says: 3262848b8605Smrg * 3263848b8605Smrg * "┌───────────────────────────────────────────────────────────────┐ 3264848b8605Smrg * │ Transform feedback array bindings (see sec. 13.2.2) │ 3265848b8605Smrg * ├───────────────────────┬───────────────────────────────────────┤ 3266848b8605Smrg * │ ... │ ... │ 3267848b8605Smrg * │ offset restriction │ multiple of 4 │ 3268848b8605Smrg * │ ... │ ... │ 3269848b8605Smrg * │ size restriction │ multiple of 4 │ 3270848b8605Smrg * └───────────────────────┴───────────────────────────────────────┘" 3271848b8605Smrg */ 3272848b8605Smrg if (offsets[i] & 0x3) { 3273848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3274848b8605Smrg "glBindBuffersRange(offsets[%u]=%" PRId64 3275848b8605Smrg " is misaligned; it must be a multiple of 4 when " 3276848b8605Smrg "target=GL_TRANSFORM_FEEDBACK_BUFFER)", 3277848b8605Smrg i, (int64_t) offsets[i]); 3278848b8605Smrg continue; 3279848b8605Smrg } 3280848b8605Smrg 3281848b8605Smrg if (sizes[i] & 0x3) { 3282848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3283848b8605Smrg "glBindBuffersRange(sizes[%u]=%" PRId64 3284848b8605Smrg " is misaligned; it must be a multiple of 4 when " 3285848b8605Smrg "target=GL_TRANSFORM_FEEDBACK_BUFFER)", 3286848b8605Smrg i, (int64_t) sizes[i]); 3287848b8605Smrg continue; 3288848b8605Smrg } 3289848b8605Smrg 3290848b8605Smrg if (boundBufObj && boundBufObj->Name == buffers[i]) 3291848b8605Smrg bufObj = boundBufObj; 3292848b8605Smrg else 3293848b8605Smrg bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, 3294848b8605Smrg "glBindBuffersRange"); 3295848b8605Smrg 3296848b8605Smrg if (bufObj) 3297848b8605Smrg _mesa_set_transform_feedback_binding(ctx, tfObj, index, bufObj, 3298848b8605Smrg offsets[i], sizes[i]); 3299848b8605Smrg } 3300848b8605Smrg 3301848b8605Smrg _mesa_end_bufferobj_lookups(ctx); 3302848b8605Smrg} 3303848b8605Smrg 3304848b8605Smrgstatic bool 3305848b8605Smrgerror_check_bind_atomic_buffers(struct gl_context *ctx, 3306848b8605Smrg GLuint first, GLsizei count, 3307848b8605Smrg const char *caller) 3308848b8605Smrg{ 3309848b8605Smrg if (!ctx->Extensions.ARB_shader_atomic_counters) { 3310848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, 3311848b8605Smrg "%s(target=GL_ATOMIC_COUNTER_BUFFER)", caller); 3312848b8605Smrg return false; 3313848b8605Smrg } 3314848b8605Smrg 3315848b8605Smrg /* The ARB_multi_bind_spec says: 3316848b8605Smrg * 3317848b8605Smrg * "An INVALID_OPERATION error is generated if <first> + <count> is 3318848b8605Smrg * greater than the number of target-specific indexed binding points, 3319848b8605Smrg * as described in section 6.7.1." 3320848b8605Smrg */ 3321848b8605Smrg if (first + count > ctx->Const.MaxAtomicBufferBindings) { 3322848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3323848b8605Smrg "%s(first=%u + count=%d > the value of " 3324848b8605Smrg "GL_MAX_ATOMIC_BUFFER_BINDINGS=%u)", 3325848b8605Smrg caller, first, count, ctx->Const.MaxAtomicBufferBindings); 3326848b8605Smrg return false; 3327848b8605Smrg } 3328848b8605Smrg 3329848b8605Smrg return true; 3330848b8605Smrg} 3331848b8605Smrg 3332848b8605Smrg/** 3333848b8605Smrg * Unbind all atomic counter buffers in the range 3334848b8605Smrg * <first> through <first>+<count>-1 3335848b8605Smrg */ 3336848b8605Smrgstatic void 3337848b8605Smrgunbind_atomic_buffers(struct gl_context *ctx, GLuint first, GLsizei count) 3338848b8605Smrg{ 3339848b8605Smrg struct gl_buffer_object * const bufObj = ctx->Shared->NullBufferObj; 3340848b8605Smrg GLuint i; 3341848b8605Smrg 3342848b8605Smrg for (i = 0; i < count; i++) 3343848b8605Smrg set_atomic_buffer_binding(ctx, &ctx->AtomicBufferBindings[first + i], 3344848b8605Smrg bufObj, -1, -1); 3345848b8605Smrg} 3346848b8605Smrg 3347848b8605Smrgstatic void 3348848b8605Smrgbind_atomic_buffers_base(struct gl_context *ctx, 3349848b8605Smrg GLuint first, 3350848b8605Smrg GLsizei count, 3351848b8605Smrg const GLuint *buffers) 3352848b8605Smrg{ 3353848b8605Smrg GLuint i; 3354848b8605Smrg 3355848b8605Smrg if (!error_check_bind_atomic_buffers(ctx, first, count, 3356848b8605Smrg "glBindBuffersBase")) 3357848b8605Smrg return; 3358848b8605Smrg 3359848b8605Smrg /* Assume that at least one binding will be changed */ 3360848b8605Smrg FLUSH_VERTICES(ctx, 0); 3361848b8605Smrg ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer; 3362848b8605Smrg 3363848b8605Smrg if (!buffers) { 3364848b8605Smrg /* The ARB_multi_bind spec says: 3365848b8605Smrg * 3366848b8605Smrg * "If <buffers> is NULL, all bindings from <first> through 3367848b8605Smrg * <first>+<count>-1 are reset to their unbound (zero) state." 3368848b8605Smrg */ 3369848b8605Smrg unbind_atomic_buffers(ctx, first, count); 3370848b8605Smrg return; 3371848b8605Smrg } 3372848b8605Smrg 3373848b8605Smrg /* Note that the error semantics for multi-bind commands differ from 3374848b8605Smrg * those of other GL commands. 3375848b8605Smrg * 3376848b8605Smrg * The Issues section in the ARB_multi_bind spec says: 3377848b8605Smrg * 3378848b8605Smrg * "(11) Typically, OpenGL specifies that if an error is generated by a 3379848b8605Smrg * command, that command has no effect. This is somewhat 3380848b8605Smrg * unfortunate for multi-bind commands, because it would require a 3381848b8605Smrg * first pass to scan the entire list of bound objects for errors 3382848b8605Smrg * and then a second pass to actually perform the bindings. 3383848b8605Smrg * Should we have different error semantics? 3384848b8605Smrg * 3385848b8605Smrg * RESOLVED: Yes. In this specification, when the parameters for 3386848b8605Smrg * one of the <count> binding points are invalid, that binding point 3387848b8605Smrg * is not updated and an error will be generated. However, other 3388848b8605Smrg * binding points in the same command will be updated if their 3389848b8605Smrg * parameters are valid and no other error occurs." 3390848b8605Smrg */ 3391848b8605Smrg 3392848b8605Smrg _mesa_begin_bufferobj_lookups(ctx); 3393848b8605Smrg 3394848b8605Smrg for (i = 0; i < count; i++) { 3395848b8605Smrg struct gl_atomic_buffer_binding *binding = 3396848b8605Smrg &ctx->AtomicBufferBindings[first + i]; 3397848b8605Smrg struct gl_buffer_object *bufObj; 3398848b8605Smrg 3399848b8605Smrg if (binding->BufferObject && binding->BufferObject->Name == buffers[i]) 3400848b8605Smrg bufObj = binding->BufferObject; 3401848b8605Smrg else 3402848b8605Smrg bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, 3403848b8605Smrg "glBindBuffersBase"); 3404848b8605Smrg 3405848b8605Smrg if (bufObj) 3406848b8605Smrg set_atomic_buffer_binding(ctx, binding, bufObj, 0, 0); 3407848b8605Smrg } 3408848b8605Smrg 3409848b8605Smrg _mesa_end_bufferobj_lookups(ctx); 3410848b8605Smrg} 3411848b8605Smrg 3412848b8605Smrgstatic void 3413848b8605Smrgbind_atomic_buffers_range(struct gl_context *ctx, 3414848b8605Smrg GLuint first, 3415848b8605Smrg GLsizei count, 3416848b8605Smrg const GLuint *buffers, 3417848b8605Smrg const GLintptr *offsets, 3418848b8605Smrg const GLsizeiptr *sizes) 3419848b8605Smrg{ 3420848b8605Smrg GLuint i; 3421848b8605Smrg 3422848b8605Smrg if (!error_check_bind_atomic_buffers(ctx, first, count, 3423848b8605Smrg "glBindBuffersRange")) 3424848b8605Smrg return; 3425848b8605Smrg 3426848b8605Smrg /* Assume that at least one binding will be changed */ 3427848b8605Smrg FLUSH_VERTICES(ctx, 0); 3428848b8605Smrg ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer; 3429848b8605Smrg 3430848b8605Smrg if (!buffers) { 3431848b8605Smrg /* The ARB_multi_bind spec says: 3432848b8605Smrg * 3433848b8605Smrg * "If <buffers> is NULL, all bindings from <first> through 3434848b8605Smrg * <first>+<count>-1 are reset to their unbound (zero) state. 3435848b8605Smrg * In this case, the offsets and sizes associated with the 3436848b8605Smrg * binding points are set to default values, ignoring 3437848b8605Smrg * <offsets> and <sizes>." 3438848b8605Smrg */ 3439848b8605Smrg unbind_atomic_buffers(ctx, first, count); 3440848b8605Smrg return; 3441848b8605Smrg } 3442848b8605Smrg 3443848b8605Smrg /* Note that the error semantics for multi-bind commands differ from 3444848b8605Smrg * those of other GL commands. 3445848b8605Smrg * 3446848b8605Smrg * The Issues section in the ARB_multi_bind spec says: 3447848b8605Smrg * 3448848b8605Smrg * "(11) Typically, OpenGL specifies that if an error is generated by a 3449848b8605Smrg * command, that command has no effect. This is somewhat 3450848b8605Smrg * unfortunate for multi-bind commands, because it would require a 3451848b8605Smrg * first pass to scan the entire list of bound objects for errors 3452848b8605Smrg * and then a second pass to actually perform the bindings. 3453848b8605Smrg * Should we have different error semantics? 3454848b8605Smrg * 3455848b8605Smrg * RESOLVED: Yes. In this specification, when the parameters for 3456848b8605Smrg * one of the <count> binding points are invalid, that binding point 3457848b8605Smrg * is not updated and an error will be generated. However, other 3458848b8605Smrg * binding points in the same command will be updated if their 3459848b8605Smrg * parameters are valid and no other error occurs." 3460848b8605Smrg */ 3461848b8605Smrg 3462848b8605Smrg _mesa_begin_bufferobj_lookups(ctx); 3463848b8605Smrg 3464848b8605Smrg for (i = 0; i < count; i++) { 3465848b8605Smrg struct gl_atomic_buffer_binding *binding = 3466848b8605Smrg &ctx->AtomicBufferBindings[first + i]; 3467848b8605Smrg struct gl_buffer_object *bufObj; 3468848b8605Smrg 3469848b8605Smrg if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes)) 3470848b8605Smrg continue; 3471848b8605Smrg 3472848b8605Smrg /* The ARB_multi_bind spec says: 3473848b8605Smrg * 3474848b8605Smrg * "An INVALID_VALUE error is generated by BindBuffersRange if any 3475848b8605Smrg * pair of values in <offsets> and <sizes> does not respectively 3476848b8605Smrg * satisfy the constraints described for those parameters for the 3477848b8605Smrg * specified target, as described in section 6.7.1 (per binding)." 3478848b8605Smrg * 3479848b8605Smrg * Section 6.7.1 refers to table 6.5, which says: 3480848b8605Smrg * 3481848b8605Smrg * "┌───────────────────────────────────────────────────────────────┐ 3482848b8605Smrg * │ Atomic counter array bindings (see sec. 7.7.2) │ 3483848b8605Smrg * ├───────────────────────┬───────────────────────────────────────┤ 3484848b8605Smrg * │ ... │ ... │ 3485848b8605Smrg * │ offset restriction │ multiple of 4 │ 3486848b8605Smrg * │ ... │ ... │ 3487848b8605Smrg * │ size restriction │ none │ 3488848b8605Smrg * └───────────────────────┴───────────────────────────────────────┘" 3489848b8605Smrg */ 3490848b8605Smrg if (offsets[i] & (ATOMIC_COUNTER_SIZE - 1)) { 3491848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3492848b8605Smrg "glBindBuffersRange(offsets[%u]=%" PRId64 3493848b8605Smrg " is misaligned; it must be a multiple of %d when " 3494848b8605Smrg "target=GL_ATOMIC_COUNTER_BUFFER)", 3495848b8605Smrg i, (int64_t) offsets[i], ATOMIC_COUNTER_SIZE); 3496848b8605Smrg continue; 3497848b8605Smrg } 3498848b8605Smrg 3499848b8605Smrg if (binding->BufferObject && binding->BufferObject->Name == buffers[i]) 3500848b8605Smrg bufObj = binding->BufferObject; 3501848b8605Smrg else 3502848b8605Smrg bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, 3503848b8605Smrg "glBindBuffersRange"); 3504848b8605Smrg 3505848b8605Smrg if (bufObj) 3506848b8605Smrg set_atomic_buffer_binding(ctx, binding, bufObj, offsets[i], sizes[i]); 3507848b8605Smrg } 3508848b8605Smrg 3509848b8605Smrg _mesa_end_bufferobj_lookups(ctx); 3510848b8605Smrg} 3511848b8605Smrg 3512848b8605Smrgvoid GLAPIENTRY 3513848b8605Smrg_mesa_BindBufferRange(GLenum target, GLuint index, 3514848b8605Smrg GLuint buffer, GLintptr offset, GLsizeiptr size) 3515848b8605Smrg{ 3516848b8605Smrg GET_CURRENT_CONTEXT(ctx); 3517848b8605Smrg struct gl_buffer_object *bufObj; 3518848b8605Smrg 3519848b8605Smrg if (buffer == 0) { 3520848b8605Smrg bufObj = ctx->Shared->NullBufferObj; 3521848b8605Smrg } else { 3522848b8605Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 3523848b8605Smrg } 3524848b8605Smrg if (!_mesa_handle_bind_buffer_gen(ctx, target, buffer, 3525848b8605Smrg &bufObj, "glBindBufferRange")) 3526848b8605Smrg return; 3527848b8605Smrg 3528848b8605Smrg if (!bufObj) { 3529848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3530848b8605Smrg "glBindBufferRange(invalid buffer=%u)", buffer); 3531848b8605Smrg return; 3532848b8605Smrg } 3533848b8605Smrg 3534848b8605Smrg if (buffer != 0) { 3535848b8605Smrg if (size <= 0) { 3536848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(size=%d)", 3537848b8605Smrg (int) size); 3538848b8605Smrg return; 3539848b8605Smrg } 3540848b8605Smrg } 3541848b8605Smrg 3542848b8605Smrg switch (target) { 3543848b8605Smrg case GL_TRANSFORM_FEEDBACK_BUFFER: 3544848b8605Smrg _mesa_bind_buffer_range_transform_feedback(ctx, index, bufObj, 3545848b8605Smrg offset, size); 3546848b8605Smrg return; 3547848b8605Smrg case GL_UNIFORM_BUFFER: 3548848b8605Smrg bind_buffer_range_uniform_buffer(ctx, index, bufObj, offset, size); 3549848b8605Smrg return; 3550848b8605Smrg case GL_ATOMIC_COUNTER_BUFFER: 3551848b8605Smrg bind_atomic_buffer(ctx, index, bufObj, offset, size, 3552848b8605Smrg "glBindBufferRange"); 3553848b8605Smrg return; 3554848b8605Smrg default: 3555848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferRange(target)"); 3556848b8605Smrg return; 3557848b8605Smrg } 3558848b8605Smrg} 3559848b8605Smrg 3560848b8605Smrgvoid GLAPIENTRY 3561848b8605Smrg_mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer) 3562848b8605Smrg{ 3563848b8605Smrg GET_CURRENT_CONTEXT(ctx); 3564848b8605Smrg struct gl_buffer_object *bufObj; 3565848b8605Smrg 3566848b8605Smrg if (buffer == 0) { 3567848b8605Smrg bufObj = ctx->Shared->NullBufferObj; 3568848b8605Smrg } else { 3569848b8605Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 3570848b8605Smrg } 3571848b8605Smrg if (!_mesa_handle_bind_buffer_gen(ctx, target, buffer, 3572848b8605Smrg &bufObj, "glBindBufferBase")) 3573848b8605Smrg return; 3574848b8605Smrg 3575848b8605Smrg if (!bufObj) { 3576848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3577848b8605Smrg "glBindBufferBase(invalid buffer=%u)", buffer); 3578848b8605Smrg return; 3579848b8605Smrg } 3580848b8605Smrg 3581848b8605Smrg /* Note that there's some oddness in the GL 3.1-GL 3.3 specifications with 3582848b8605Smrg * regards to BindBufferBase. It says (GL 3.1 core spec, page 63): 3583848b8605Smrg * 3584848b8605Smrg * "BindBufferBase is equivalent to calling BindBufferRange with offset 3585848b8605Smrg * zero and size equal to the size of buffer." 3586848b8605Smrg * 3587848b8605Smrg * but it says for glGetIntegeri_v (GL 3.1 core spec, page 230): 3588848b8605Smrg * 3589848b8605Smrg * "If the parameter (starting offset or size) was not specified when the 3590848b8605Smrg * buffer object was bound, zero is returned." 3591848b8605Smrg * 3592848b8605Smrg * What happens if the size of the buffer changes? Does the size of the 3593848b8605Smrg * buffer at the moment glBindBufferBase was called still play a role, like 3594848b8605Smrg * the first quote would imply, or is the size meaningless in the 3595848b8605Smrg * glBindBufferBase case like the second quote would suggest? The GL 4.1 3596848b8605Smrg * core spec page 45 says: 3597848b8605Smrg * 3598848b8605Smrg * "It is equivalent to calling BindBufferRange with offset zero, while 3599848b8605Smrg * size is determined by the size of the bound buffer at the time the 3600848b8605Smrg * binding is used." 3601848b8605Smrg * 3602848b8605Smrg * My interpretation is that the GL 4.1 spec was a clarification of the 3603848b8605Smrg * behavior, not a change. In particular, this choice will only make 3604848b8605Smrg * rendering work in cases where it would have had undefined results. 3605848b8605Smrg */ 3606848b8605Smrg 3607848b8605Smrg switch (target) { 3608848b8605Smrg case GL_TRANSFORM_FEEDBACK_BUFFER: 3609848b8605Smrg _mesa_bind_buffer_base_transform_feedback(ctx, index, bufObj); 3610848b8605Smrg return; 3611848b8605Smrg case GL_UNIFORM_BUFFER: 3612848b8605Smrg bind_buffer_base_uniform_buffer(ctx, index, bufObj); 3613848b8605Smrg return; 3614848b8605Smrg case GL_ATOMIC_COUNTER_BUFFER: 3615848b8605Smrg bind_atomic_buffer(ctx, index, bufObj, 0, 0, 3616848b8605Smrg "glBindBufferBase"); 3617848b8605Smrg return; 3618848b8605Smrg default: 3619848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)"); 3620848b8605Smrg return; 3621848b8605Smrg } 3622848b8605Smrg} 3623848b8605Smrg 3624848b8605Smrgvoid GLAPIENTRY 3625848b8605Smrg_mesa_BindBuffersRange(GLenum target, GLuint first, GLsizei count, 3626848b8605Smrg const GLuint *buffers, 3627848b8605Smrg const GLintptr *offsets, const GLsizeiptr *sizes) 3628848b8605Smrg{ 3629848b8605Smrg GET_CURRENT_CONTEXT(ctx); 3630848b8605Smrg 3631848b8605Smrg switch (target) { 3632848b8605Smrg case GL_TRANSFORM_FEEDBACK_BUFFER: 3633848b8605Smrg bind_xfb_buffers_range(ctx, first, count, buffers, offsets, sizes); 3634848b8605Smrg return; 3635848b8605Smrg case GL_UNIFORM_BUFFER: 3636848b8605Smrg bind_uniform_buffers_range(ctx, first, count, buffers, offsets, sizes); 3637848b8605Smrg return; 3638848b8605Smrg case GL_ATOMIC_COUNTER_BUFFER: 3639848b8605Smrg bind_atomic_buffers_range(ctx, first, count, buffers, 3640848b8605Smrg offsets, sizes); 3641848b8605Smrg return; 3642848b8605Smrg default: 3643848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindBuffersRange(target=%s)", 3644848b8605Smrg _mesa_lookup_enum_by_nr(target)); 3645848b8605Smrg break; 3646848b8605Smrg } 3647848b8605Smrg} 3648848b8605Smrg 3649848b8605Smrgvoid GLAPIENTRY 3650848b8605Smrg_mesa_BindBuffersBase(GLenum target, GLuint first, GLsizei count, 3651848b8605Smrg const GLuint *buffers) 3652848b8605Smrg{ 3653848b8605Smrg GET_CURRENT_CONTEXT(ctx); 3654848b8605Smrg 3655848b8605Smrg switch (target) { 3656848b8605Smrg case GL_TRANSFORM_FEEDBACK_BUFFER: 3657848b8605Smrg bind_xfb_buffers_base(ctx, first, count, buffers); 3658848b8605Smrg return; 3659848b8605Smrg case GL_UNIFORM_BUFFER: 3660848b8605Smrg bind_uniform_buffers_base(ctx, first, count, buffers); 3661848b8605Smrg return; 3662848b8605Smrg case GL_ATOMIC_COUNTER_BUFFER: 3663848b8605Smrg bind_atomic_buffers_base(ctx, first, count, buffers); 3664848b8605Smrg return; 3665848b8605Smrg default: 3666848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindBuffersBase(target=%s)", 3667848b8605Smrg _mesa_lookup_enum_by_nr(target)); 3668848b8605Smrg break; 3669848b8605Smrg } 3670848b8605Smrg} 3671848b8605Smrg 3672848b8605Smrgvoid GLAPIENTRY 3673848b8605Smrg_mesa_InvalidateBufferSubData(GLuint buffer, GLintptr offset, 3674848b8605Smrg GLsizeiptr length) 3675848b8605Smrg{ 3676848b8605Smrg GET_CURRENT_CONTEXT(ctx); 3677848b8605Smrg struct gl_buffer_object *bufObj; 3678848b8605Smrg const GLintptr end = offset + length; 3679848b8605Smrg 3680848b8605Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 3681848b8605Smrg if (!bufObj) { 3682848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3683848b8605Smrg "glInvalidateBufferSubData(name = 0x%x) invalid object", 3684848b8605Smrg buffer); 3685848b8605Smrg return; 3686848b8605Smrg } 3687848b8605Smrg 3688848b8605Smrg /* The GL_ARB_invalidate_subdata spec says: 3689848b8605Smrg * 3690848b8605Smrg * "An INVALID_VALUE error is generated if <offset> or <length> is 3691848b8605Smrg * negative, or if <offset> + <length> is greater than the value of 3692848b8605Smrg * BUFFER_SIZE." 3693848b8605Smrg */ 3694848b8605Smrg if (end < 0 || end > bufObj->Size) { 3695848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3696848b8605Smrg "glInvalidateBufferSubData(invalid offset or length)"); 3697848b8605Smrg return; 3698848b8605Smrg } 3699848b8605Smrg 3700848b8605Smrg /* The OpenGL 4.4 (Core Profile) spec says: 3701848b8605Smrg * 3702848b8605Smrg * "An INVALID_OPERATION error is generated if buffer is currently 3703848b8605Smrg * mapped by MapBuffer or if the invalidate range intersects the range 3704848b8605Smrg * currently mapped by MapBufferRange, unless it was mapped 3705848b8605Smrg * with MAP_PERSISTENT_BIT set in the MapBufferRange access flags." 3706848b8605Smrg */ 3707848b8605Smrg if (!(bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_PERSISTENT_BIT) && 3708848b8605Smrg bufferobj_range_mapped(bufObj, offset, length)) { 3709848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3710848b8605Smrg "glInvalidateBufferSubData(intersection with mapped " 3711848b8605Smrg "range)"); 3712848b8605Smrg return; 3713848b8605Smrg } 3714848b8605Smrg 3715848b8605Smrg /* We don't actually do anything for this yet. Just return after 3716848b8605Smrg * validating the parameters and generating the required errors. 3717848b8605Smrg */ 3718848b8605Smrg return; 3719848b8605Smrg} 3720848b8605Smrg 3721848b8605Smrgvoid GLAPIENTRY 3722848b8605Smrg_mesa_InvalidateBufferData(GLuint buffer) 3723848b8605Smrg{ 3724848b8605Smrg GET_CURRENT_CONTEXT(ctx); 3725848b8605Smrg struct gl_buffer_object *bufObj; 3726848b8605Smrg 3727848b8605Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 3728848b8605Smrg if (!bufObj) { 3729848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3730848b8605Smrg "glInvalidateBufferData(name = 0x%x) invalid object", 3731848b8605Smrg buffer); 3732848b8605Smrg return; 3733848b8605Smrg } 3734848b8605Smrg 3735848b8605Smrg /* The OpenGL 4.4 (Core Profile) spec says: 3736848b8605Smrg * 3737848b8605Smrg * "An INVALID_OPERATION error is generated if buffer is currently 3738848b8605Smrg * mapped by MapBuffer or if the invalidate range intersects the range 3739848b8605Smrg * currently mapped by MapBufferRange, unless it was mapped 3740848b8605Smrg * with MAP_PERSISTENT_BIT set in the MapBufferRange access flags." 3741848b8605Smrg */ 3742848b8605Smrg if (_mesa_check_disallowed_mapping(bufObj)) { 3743848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3744848b8605Smrg "glInvalidateBufferData(intersection with mapped " 3745848b8605Smrg "range)"); 3746848b8605Smrg return; 3747848b8605Smrg } 3748848b8605Smrg 3749848b8605Smrg /* We don't actually do anything for this yet. Just return after 3750848b8605Smrg * validating the parameters and generating the required errors. 3751848b8605Smrg */ 3752848b8605Smrg return; 3753848b8605Smrg} 3754