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 */ 35b8e80941Smrg#include "util/debug.h" 36848b8605Smrg#include "glheader.h" 37848b8605Smrg#include "enums.h" 38848b8605Smrg#include "hash.h" 39848b8605Smrg#include "imports.h" 40848b8605Smrg#include "context.h" 41848b8605Smrg#include "bufferobj.h" 42b8e80941Smrg#include "externalobjects.h" 43848b8605Smrg#include "mtypes.h" 44848b8605Smrg#include "teximage.h" 45848b8605Smrg#include "glformats.h" 46848b8605Smrg#include "texstore.h" 47848b8605Smrg#include "transformfeedback.h" 48b8e80941Smrg#include "varray.h" 49b8e80941Smrg#include "util/u_atomic.h" 50848b8605Smrg 51848b8605Smrg 52848b8605Smrg/* Debug flags */ 53848b8605Smrg/*#define VBO_DEBUG*/ 54848b8605Smrg/*#define BOUNDS_CHECK*/ 55848b8605Smrg 56848b8605Smrg 57b8e80941Smrg/** 58b8e80941Smrg * We count the number of buffer modification calls to check for 59b8e80941Smrg * inefficient buffer use. This is the number of such calls before we 60b8e80941Smrg * issue a warning. 61b8e80941Smrg */ 62b8e80941Smrg#define BUFFER_WARNING_CALL_COUNT 4 63b8e80941Smrg 64b8e80941Smrg 65b8e80941Smrg/** 66b8e80941Smrg * Helper to warn of possible performance issues, such as frequently 67b8e80941Smrg * updating a buffer created with GL_STATIC_DRAW. Called via the macro 68b8e80941Smrg * below. 69b8e80941Smrg */ 70b8e80941Smrgstatic void 71b8e80941Smrgbuffer_usage_warning(struct gl_context *ctx, GLuint *id, const char *fmt, ...) 72b8e80941Smrg{ 73b8e80941Smrg va_list args; 74b8e80941Smrg 75b8e80941Smrg va_start(args, fmt); 76b8e80941Smrg _mesa_gl_vdebugf(ctx, id, 77b8e80941Smrg MESA_DEBUG_SOURCE_API, 78b8e80941Smrg MESA_DEBUG_TYPE_PERFORMANCE, 79b8e80941Smrg MESA_DEBUG_SEVERITY_MEDIUM, 80b8e80941Smrg fmt, args); 81b8e80941Smrg va_end(args); 82b8e80941Smrg} 83b8e80941Smrg 84b8e80941Smrg#define BUFFER_USAGE_WARNING(CTX, FMT, ...) \ 85b8e80941Smrg do { \ 86b8e80941Smrg static GLuint id = 0; \ 87b8e80941Smrg buffer_usage_warning(CTX, &id, FMT, ##__VA_ARGS__); \ 88b8e80941Smrg } while (0) 89b8e80941Smrg 90b8e80941Smrg 91848b8605Smrg/** 92848b8605Smrg * Used as a placeholder for buffer objects between glGenBuffers() and 93848b8605Smrg * glBindBuffer() so that glIsBuffer() can work correctly. 94848b8605Smrg */ 95848b8605Smrgstatic struct gl_buffer_object DummyBufferObject; 96848b8605Smrg 97848b8605Smrg 98848b8605Smrg/** 99848b8605Smrg * Return pointer to address of a buffer object target. 100848b8605Smrg * \param ctx the GL context 101848b8605Smrg * \param target the buffer object target to be retrieved. 102848b8605Smrg * \return pointer to pointer to the buffer object bound to \c target in the 103848b8605Smrg * specified context or \c NULL if \c target is invalid. 104848b8605Smrg */ 105848b8605Smrgstatic inline struct gl_buffer_object ** 106848b8605Smrgget_buffer_target(struct gl_context *ctx, GLenum target) 107848b8605Smrg{ 108848b8605Smrg /* Other targets are only supported in desktop OpenGL and OpenGL ES 3.0. 109848b8605Smrg */ 110848b8605Smrg if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx) 111848b8605Smrg && target != GL_ARRAY_BUFFER && target != GL_ELEMENT_ARRAY_BUFFER) 112848b8605Smrg return NULL; 113848b8605Smrg 114848b8605Smrg switch (target) { 115848b8605Smrg case GL_ARRAY_BUFFER_ARB: 116b8e80941Smrg if (ctx->Array.ArrayBufferObj) 117b8e80941Smrg ctx->Array.ArrayBufferObj->UsageHistory |= USAGE_ARRAY_BUFFER; 118848b8605Smrg return &ctx->Array.ArrayBufferObj; 119848b8605Smrg case GL_ELEMENT_ARRAY_BUFFER_ARB: 120b8e80941Smrg if (ctx->Array.VAO->IndexBufferObj) 121b8e80941Smrg ctx->Array.VAO->IndexBufferObj->UsageHistory 122b8e80941Smrg |= USAGE_ELEMENT_ARRAY_BUFFER; 123848b8605Smrg return &ctx->Array.VAO->IndexBufferObj; 124848b8605Smrg case GL_PIXEL_PACK_BUFFER_EXT: 125848b8605Smrg return &ctx->Pack.BufferObj; 126848b8605Smrg case GL_PIXEL_UNPACK_BUFFER_EXT: 127848b8605Smrg return &ctx->Unpack.BufferObj; 128848b8605Smrg case GL_COPY_READ_BUFFER: 129848b8605Smrg return &ctx->CopyReadBuffer; 130848b8605Smrg case GL_COPY_WRITE_BUFFER: 131848b8605Smrg return &ctx->CopyWriteBuffer; 132b8e80941Smrg case GL_QUERY_BUFFER: 133b8e80941Smrg if (_mesa_has_ARB_query_buffer_object(ctx)) 134b8e80941Smrg return &ctx->QueryBuffer; 135b8e80941Smrg break; 136848b8605Smrg case GL_DRAW_INDIRECT_BUFFER: 137b8e80941Smrg if ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_draw_indirect) || 138b8e80941Smrg _mesa_is_gles31(ctx)) { 139848b8605Smrg return &ctx->DrawIndirectBuffer; 140848b8605Smrg } 141848b8605Smrg break; 142b8e80941Smrg case GL_PARAMETER_BUFFER_ARB: 143b8e80941Smrg if (_mesa_has_ARB_indirect_parameters(ctx)) { 144b8e80941Smrg return &ctx->ParameterBuffer; 145b8e80941Smrg } 146b8e80941Smrg break; 147b8e80941Smrg case GL_DISPATCH_INDIRECT_BUFFER: 148b8e80941Smrg if (_mesa_has_compute_shaders(ctx)) { 149b8e80941Smrg return &ctx->DispatchIndirectBuffer; 150b8e80941Smrg } 151b8e80941Smrg break; 152848b8605Smrg case GL_TRANSFORM_FEEDBACK_BUFFER: 153848b8605Smrg if (ctx->Extensions.EXT_transform_feedback) { 154848b8605Smrg return &ctx->TransformFeedback.CurrentBuffer; 155848b8605Smrg } 156848b8605Smrg break; 157848b8605Smrg case GL_TEXTURE_BUFFER: 158b8e80941Smrg if (_mesa_has_ARB_texture_buffer_object(ctx) || 159b8e80941Smrg _mesa_has_OES_texture_buffer(ctx)) { 160848b8605Smrg return &ctx->Texture.BufferObject; 161848b8605Smrg } 162848b8605Smrg break; 163848b8605Smrg case GL_UNIFORM_BUFFER: 164848b8605Smrg if (ctx->Extensions.ARB_uniform_buffer_object) { 165848b8605Smrg return &ctx->UniformBuffer; 166848b8605Smrg } 167848b8605Smrg break; 168b8e80941Smrg case GL_SHADER_STORAGE_BUFFER: 169b8e80941Smrg if (ctx->Extensions.ARB_shader_storage_buffer_object) { 170b8e80941Smrg return &ctx->ShaderStorageBuffer; 171b8e80941Smrg } 172b8e80941Smrg break; 173848b8605Smrg case GL_ATOMIC_COUNTER_BUFFER: 174848b8605Smrg if (ctx->Extensions.ARB_shader_atomic_counters) { 175848b8605Smrg return &ctx->AtomicBuffer; 176848b8605Smrg } 177848b8605Smrg break; 178b8e80941Smrg case GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD: 179b8e80941Smrg if (ctx->Extensions.AMD_pinned_memory) { 180b8e80941Smrg return &ctx->ExternalVirtualMemoryBuffer; 181b8e80941Smrg } 182b8e80941Smrg break; 183848b8605Smrg default: 184848b8605Smrg return NULL; 185848b8605Smrg } 186848b8605Smrg return NULL; 187848b8605Smrg} 188848b8605Smrg 189848b8605Smrg 190848b8605Smrg/** 191848b8605Smrg * Get the buffer object bound to the specified target in a GL context. 192848b8605Smrg * \param ctx the GL context 193848b8605Smrg * \param target the buffer object target to be retrieved. 194848b8605Smrg * \param error the GL error to record if target is illegal. 195848b8605Smrg * \return pointer to the buffer object bound to \c target in the 196848b8605Smrg * specified context or \c NULL if \c target is invalid. 197848b8605Smrg */ 198848b8605Smrgstatic inline struct gl_buffer_object * 199848b8605Smrgget_buffer(struct gl_context *ctx, const char *func, GLenum target, 200848b8605Smrg GLenum error) 201848b8605Smrg{ 202848b8605Smrg struct gl_buffer_object **bufObj = get_buffer_target(ctx, target); 203848b8605Smrg 204848b8605Smrg if (!bufObj) { 205848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func); 206848b8605Smrg return NULL; 207848b8605Smrg } 208848b8605Smrg 209848b8605Smrg if (!_mesa_is_bufferobj(*bufObj)) { 210848b8605Smrg _mesa_error(ctx, error, "%s(no buffer bound)", func); 211848b8605Smrg return NULL; 212848b8605Smrg } 213848b8605Smrg 214848b8605Smrg return *bufObj; 215848b8605Smrg} 216848b8605Smrg 217848b8605Smrg 218848b8605Smrg/** 219848b8605Smrg * Convert a GLbitfield describing the mapped buffer access flags 220848b8605Smrg * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY. 221848b8605Smrg */ 222848b8605Smrgstatic GLenum 223848b8605Smrgsimplified_access_mode(struct gl_context *ctx, GLbitfield access) 224848b8605Smrg{ 225848b8605Smrg const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; 226848b8605Smrg if ((access & rwFlags) == rwFlags) 227848b8605Smrg return GL_READ_WRITE; 228848b8605Smrg if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT) 229848b8605Smrg return GL_READ_ONLY; 230848b8605Smrg if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT) 231848b8605Smrg return GL_WRITE_ONLY; 232848b8605Smrg 233848b8605Smrg /* Otherwise, AccessFlags is zero (the default state). 234848b8605Smrg * 235848b8605Smrg * Table 2.6 on page 31 (page 44 of the PDF) of the OpenGL 1.5 spec says: 236848b8605Smrg * 237848b8605Smrg * Name Type Initial Value Legal Values 238848b8605Smrg * ... ... ... ... 239848b8605Smrg * BUFFER_ACCESS enum READ_WRITE READ_ONLY, WRITE_ONLY 240848b8605Smrg * READ_WRITE 241848b8605Smrg * 242848b8605Smrg * However, table 6.8 in the GL_OES_mapbuffer extension says: 243848b8605Smrg * 244848b8605Smrg * Get Value Type Get Command Value Description 245848b8605Smrg * --------- ---- ----------- ----- ----------- 246848b8605Smrg * BUFFER_ACCESS_OES Z1 GetBufferParameteriv WRITE_ONLY_OES buffer map flag 247848b8605Smrg * 248848b8605Smrg * The difference is because GL_OES_mapbuffer only supports mapping buffers 249848b8605Smrg * write-only. 250848b8605Smrg */ 251848b8605Smrg assert(access == 0); 252848b8605Smrg 253848b8605Smrg return _mesa_is_gles(ctx) ? GL_WRITE_ONLY : GL_READ_WRITE; 254848b8605Smrg} 255848b8605Smrg 256848b8605Smrg 257848b8605Smrg/** 258848b8605Smrg * Test if the buffer is mapped, and if so, if the mapped range overlaps the 259848b8605Smrg * given range. 260848b8605Smrg * The regions do not overlap if and only if the end of the given 261848b8605Smrg * region is before the mapped region or the start of the given region 262848b8605Smrg * is after the mapped region. 263848b8605Smrg * 264848b8605Smrg * \param obj Buffer object target on which to operate. 265848b8605Smrg * \param offset Offset of the first byte of the subdata range. 266848b8605Smrg * \param size Size, in bytes, of the subdata range. 267848b8605Smrg * \return true if ranges overlap, false otherwise 268848b8605Smrg * 269848b8605Smrg */ 270848b8605Smrgstatic bool 271848b8605Smrgbufferobj_range_mapped(const struct gl_buffer_object *obj, 272848b8605Smrg GLintptr offset, GLsizeiptr size) 273848b8605Smrg{ 274848b8605Smrg if (_mesa_bufferobj_mapped(obj, MAP_USER)) { 275848b8605Smrg const GLintptr end = offset + size; 276848b8605Smrg const GLintptr mapEnd = obj->Mappings[MAP_USER].Offset + 277848b8605Smrg obj->Mappings[MAP_USER].Length; 278848b8605Smrg 279848b8605Smrg if (!(end <= obj->Mappings[MAP_USER].Offset || offset >= mapEnd)) { 280848b8605Smrg return true; 281848b8605Smrg } 282848b8605Smrg } 283848b8605Smrg return false; 284848b8605Smrg} 285848b8605Smrg 286848b8605Smrg 287848b8605Smrg/** 288848b8605Smrg * Tests the subdata range parameters and sets the GL error code for 289848b8605Smrg * \c glBufferSubDataARB, \c glGetBufferSubDataARB and 290848b8605Smrg * \c glClearBufferSubData. 291848b8605Smrg * 292848b8605Smrg * \param ctx GL context. 293b8e80941Smrg * \param bufObj The buffer object. 294848b8605Smrg * \param offset Offset of the first byte of the subdata range. 295848b8605Smrg * \param size Size, in bytes, of the subdata range. 296848b8605Smrg * \param mappedRange If true, checks if an overlapping range is mapped. 297848b8605Smrg * If false, checks if buffer is mapped. 298848b8605Smrg * \param caller Name of calling function for recording errors. 299b8e80941Smrg * \return false if error, true otherwise 300848b8605Smrg * 301848b8605Smrg * \sa glBufferSubDataARB, glGetBufferSubDataARB, glClearBufferSubData 302848b8605Smrg */ 303b8e80941Smrgstatic bool 304b8e80941Smrgbuffer_object_subdata_range_good(struct gl_context *ctx, 305b8e80941Smrg const struct gl_buffer_object *bufObj, 306b8e80941Smrg GLintptr offset, GLsizeiptr size, 307b8e80941Smrg bool mappedRange, const char *caller) 308848b8605Smrg{ 309848b8605Smrg if (size < 0) { 310848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller); 311b8e80941Smrg return false; 312848b8605Smrg } 313848b8605Smrg 314848b8605Smrg if (offset < 0) { 315848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller); 316b8e80941Smrg return false; 317848b8605Smrg } 318848b8605Smrg 319848b8605Smrg if (offset + size > bufObj->Size) { 320848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 321848b8605Smrg "%s(offset %lu + size %lu > buffer size %lu)", caller, 322848b8605Smrg (unsigned long) offset, 323848b8605Smrg (unsigned long) size, 324848b8605Smrg (unsigned long) bufObj->Size); 325b8e80941Smrg return false; 326848b8605Smrg } 327848b8605Smrg 328848b8605Smrg if (bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_PERSISTENT_BIT) 329b8e80941Smrg return true; 330848b8605Smrg 331848b8605Smrg if (mappedRange) { 332848b8605Smrg if (bufferobj_range_mapped(bufObj, offset, size)) { 333b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 334b8e80941Smrg "%s(range is mapped without persistent bit)", 335b8e80941Smrg caller); 336b8e80941Smrg return false; 337848b8605Smrg } 338848b8605Smrg } 339848b8605Smrg else { 340848b8605Smrg if (_mesa_bufferobj_mapped(bufObj, MAP_USER)) { 341b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 342b8e80941Smrg "%s(buffer is mapped without persistent bit)", 343b8e80941Smrg caller); 344b8e80941Smrg return false; 345848b8605Smrg } 346848b8605Smrg } 347848b8605Smrg 348b8e80941Smrg return true; 349848b8605Smrg} 350848b8605Smrg 351848b8605Smrg 352848b8605Smrg/** 353848b8605Smrg * Test the format and type parameters and set the GL error code for 354b8e80941Smrg * \c glClearBufferData, \c glClearNamedBufferData, \c glClearBufferSubData 355b8e80941Smrg * and \c glClearNamedBufferSubData. 356848b8605Smrg * 357848b8605Smrg * \param ctx GL context. 358848b8605Smrg * \param internalformat Format to which the data is to be converted. 359848b8605Smrg * \param format Format of the supplied data. 360848b8605Smrg * \param type Type of the supplied data. 361848b8605Smrg * \param caller Name of calling function for recording errors. 362848b8605Smrg * \return If internalformat, format and type are legal the mesa_format 363848b8605Smrg * corresponding to internalformat, otherwise MESA_FORMAT_NONE. 364848b8605Smrg * 365b8e80941Smrg * \sa glClearBufferData, glClearNamedBufferData, glClearBufferSubData and 366b8e80941Smrg * glClearNamedBufferSubData. 367848b8605Smrg */ 368848b8605Smrgstatic mesa_format 369848b8605Smrgvalidate_clear_buffer_format(struct gl_context *ctx, 370848b8605Smrg GLenum internalformat, 371848b8605Smrg GLenum format, GLenum type, 372848b8605Smrg const char *caller) 373848b8605Smrg{ 374848b8605Smrg mesa_format mesaFormat; 375848b8605Smrg GLenum errorFormatType; 376848b8605Smrg 377848b8605Smrg mesaFormat = _mesa_validate_texbuffer_format(ctx, internalformat); 378848b8605Smrg if (mesaFormat == MESA_FORMAT_NONE) { 379848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, 380848b8605Smrg "%s(invalid internalformat)", caller); 381848b8605Smrg return MESA_FORMAT_NONE; 382848b8605Smrg } 383848b8605Smrg 384848b8605Smrg /* NOTE: not mentioned in ARB_clear_buffer_object but according to 385848b8605Smrg * EXT_texture_integer there is no conversion between integer and 386848b8605Smrg * non-integer formats 387848b8605Smrg */ 388848b8605Smrg if (_mesa_is_enum_format_signed_int(format) != 389848b8605Smrg _mesa_is_format_integer_color(mesaFormat)) { 390848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 391848b8605Smrg "%s(integer vs non-integer)", caller); 392848b8605Smrg return MESA_FORMAT_NONE; 393848b8605Smrg } 394848b8605Smrg 395848b8605Smrg if (!_mesa_is_color_format(format)) { 396b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, 397848b8605Smrg "%s(format is not a color format)", caller); 398848b8605Smrg return MESA_FORMAT_NONE; 399848b8605Smrg } 400848b8605Smrg 401848b8605Smrg errorFormatType = _mesa_error_check_format_and_type(ctx, format, type); 402848b8605Smrg if (errorFormatType != GL_NO_ERROR) { 403b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, 404848b8605Smrg "%s(invalid format or type)", caller); 405848b8605Smrg return MESA_FORMAT_NONE; 406848b8605Smrg } 407848b8605Smrg 408848b8605Smrg return mesaFormat; 409848b8605Smrg} 410848b8605Smrg 411848b8605Smrg 412848b8605Smrg/** 413848b8605Smrg * Convert user-specified clear value to the specified internal format. 414848b8605Smrg * 415848b8605Smrg * \param ctx GL context. 416848b8605Smrg * \param internalformat Format to which the data is converted. 417848b8605Smrg * \param clearValue Points to the converted clear value. 418848b8605Smrg * \param format Format of the supplied data. 419848b8605Smrg * \param type Type of the supplied data. 420848b8605Smrg * \param data Data which is to be converted to internalformat. 421848b8605Smrg * \param caller Name of calling function for recording errors. 422848b8605Smrg * \return true if data could be converted, false otherwise. 423848b8605Smrg * 424848b8605Smrg * \sa glClearBufferData, glClearBufferSubData 425848b8605Smrg */ 426848b8605Smrgstatic bool 427848b8605Smrgconvert_clear_buffer_data(struct gl_context *ctx, 428848b8605Smrg mesa_format internalformat, 429848b8605Smrg GLubyte *clearValue, GLenum format, GLenum type, 430848b8605Smrg const GLvoid *data, const char *caller) 431848b8605Smrg{ 432848b8605Smrg GLenum internalformatBase = _mesa_get_format_base_format(internalformat); 433848b8605Smrg 434848b8605Smrg if (_mesa_texstore(ctx, 1, internalformatBase, internalformat, 435848b8605Smrg 0, &clearValue, 1, 1, 1, 436848b8605Smrg format, type, data, &ctx->Unpack)) { 437848b8605Smrg return true; 438848b8605Smrg } 439848b8605Smrg else { 440848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller); 441848b8605Smrg return false; 442848b8605Smrg } 443848b8605Smrg} 444848b8605Smrg 445848b8605Smrg 446848b8605Smrg/** 447848b8605Smrg * Allocate and initialize a new buffer object. 448b8e80941Smrg * 449848b8605Smrg * Default callback for the \c dd_function_table::NewBufferObject() hook. 450848b8605Smrg */ 451848b8605Smrgstatic struct gl_buffer_object * 452b8e80941Smrg_mesa_new_buffer_object(struct gl_context *ctx, GLuint name) 453848b8605Smrg{ 454b8e80941Smrg struct gl_buffer_object *obj = MALLOC_STRUCT(gl_buffer_object); 455b8e80941Smrg if (!obj) 456b8e80941Smrg return NULL; 457848b8605Smrg 458b8e80941Smrg _mesa_initialize_buffer_object(ctx, obj, name); 459848b8605Smrg return obj; 460848b8605Smrg} 461848b8605Smrg 462848b8605Smrg 463848b8605Smrg/** 464848b8605Smrg * Delete a buffer object. 465b8e80941Smrg * 466848b8605Smrg * Default callback for the \c dd_function_table::DeleteBuffer() hook. 467848b8605Smrg */ 468b8e80941Smrgvoid 469848b8605Smrg_mesa_delete_buffer_object(struct gl_context *ctx, 470848b8605Smrg struct gl_buffer_object *bufObj) 471848b8605Smrg{ 472848b8605Smrg (void) ctx; 473848b8605Smrg 474b8e80941Smrg vbo_delete_minmax_cache(bufObj); 475848b8605Smrg _mesa_align_free(bufObj->Data); 476848b8605Smrg 477848b8605Smrg /* assign strange values here to help w/ debugging */ 478848b8605Smrg bufObj->RefCount = -1000; 479848b8605Smrg bufObj->Name = ~0; 480848b8605Smrg 481b8e80941Smrg simple_mtx_destroy(&bufObj->MinMaxCacheMutex); 482848b8605Smrg free(bufObj->Label); 483848b8605Smrg free(bufObj); 484848b8605Smrg} 485848b8605Smrg 486848b8605Smrg 487848b8605Smrg 488848b8605Smrg/** 489848b8605Smrg * Set ptr to bufObj w/ reference counting. 490848b8605Smrg * This is normally only called from the _mesa_reference_buffer_object() macro 491848b8605Smrg * when there's a real pointer change. 492848b8605Smrg */ 493848b8605Smrgvoid 494848b8605Smrg_mesa_reference_buffer_object_(struct gl_context *ctx, 495848b8605Smrg struct gl_buffer_object **ptr, 496848b8605Smrg struct gl_buffer_object *bufObj) 497848b8605Smrg{ 498848b8605Smrg if (*ptr) { 499848b8605Smrg /* Unreference the old buffer */ 500848b8605Smrg struct gl_buffer_object *oldObj = *ptr; 501848b8605Smrg 502b8e80941Smrg if (p_atomic_dec_zero(&oldObj->RefCount)) { 503b8e80941Smrg assert(ctx->Driver.DeleteBuffer); 504848b8605Smrg ctx->Driver.DeleteBuffer(ctx, oldObj); 505848b8605Smrg } 506848b8605Smrg 507848b8605Smrg *ptr = NULL; 508848b8605Smrg } 509b8e80941Smrg assert(!*ptr); 510848b8605Smrg 511848b8605Smrg if (bufObj) { 512848b8605Smrg /* reference new buffer */ 513b8e80941Smrg p_atomic_inc(&bufObj->RefCount); 514b8e80941Smrg *ptr = bufObj; 515b8e80941Smrg } 516b8e80941Smrg} 517b8e80941Smrg 518b8e80941Smrg 519b8e80941Smrg/** 520b8e80941Smrg * Get the value of MESA_NO_MINMAX_CACHE. 521b8e80941Smrg */ 522b8e80941Smrgstatic bool 523b8e80941Smrgget_no_minmax_cache() 524b8e80941Smrg{ 525b8e80941Smrg static bool read = false; 526b8e80941Smrg static bool disable = false; 527b8e80941Smrg 528b8e80941Smrg if (!read) { 529b8e80941Smrg disable = env_var_as_boolean("MESA_NO_MINMAX_CACHE", false); 530b8e80941Smrg read = true; 531848b8605Smrg } 532b8e80941Smrg 533b8e80941Smrg return disable; 534848b8605Smrg} 535848b8605Smrg 536848b8605Smrg 537848b8605Smrg/** 538848b8605Smrg * Initialize a buffer object to default values. 539848b8605Smrg */ 540848b8605Smrgvoid 541b8e80941Smrg_mesa_initialize_buffer_object(struct gl_context *ctx, 542b8e80941Smrg struct gl_buffer_object *obj, 543b8e80941Smrg GLuint name) 544848b8605Smrg{ 545848b8605Smrg memset(obj, 0, sizeof(struct gl_buffer_object)); 546848b8605Smrg obj->RefCount = 1; 547848b8605Smrg obj->Name = name; 548848b8605Smrg obj->Usage = GL_STATIC_DRAW_ARB; 549b8e80941Smrg 550b8e80941Smrg simple_mtx_init(&obj->MinMaxCacheMutex, mtx_plain); 551b8e80941Smrg if (get_no_minmax_cache()) 552b8e80941Smrg obj->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE; 553848b8605Smrg} 554848b8605Smrg 555848b8605Smrg 556848b8605Smrg 557848b8605Smrg/** 558848b8605Smrg * Callback called from _mesa_HashWalk() 559848b8605Smrg */ 560848b8605Smrgstatic void 561848b8605Smrgcount_buffer_size(GLuint key, void *data, void *userData) 562848b8605Smrg{ 563848b8605Smrg const struct gl_buffer_object *bufObj = 564848b8605Smrg (const struct gl_buffer_object *) data; 565848b8605Smrg GLuint *total = (GLuint *) userData; 566848b8605Smrg 567b8e80941Smrg (void) key; 568848b8605Smrg *total = *total + bufObj->Size; 569848b8605Smrg} 570848b8605Smrg 571848b8605Smrg 572848b8605Smrg/** 573848b8605Smrg * Compute total size (in bytes) of all buffer objects for the given context. 574848b8605Smrg * For debugging purposes. 575848b8605Smrg */ 576848b8605SmrgGLuint 577848b8605Smrg_mesa_total_buffer_object_memory(struct gl_context *ctx) 578848b8605Smrg{ 579848b8605Smrg GLuint total = 0; 580848b8605Smrg 581848b8605Smrg _mesa_HashWalk(ctx->Shared->BufferObjects, count_buffer_size, &total); 582848b8605Smrg 583848b8605Smrg return total; 584848b8605Smrg} 585848b8605Smrg 586848b8605Smrg 587848b8605Smrg/** 588848b8605Smrg * Allocate space for and store data in a buffer object. Any data that was 589848b8605Smrg * previously stored in the buffer object is lost. If \c data is \c NULL, 590848b8605Smrg * memory will be allocated, but no copy will occur. 591848b8605Smrg * 592848b8605Smrg * This is the default callback for \c dd_function_table::BufferData() 593848b8605Smrg * Note that all GL error checking will have been done already. 594848b8605Smrg * 595848b8605Smrg * \param ctx GL context. 596848b8605Smrg * \param target Buffer object target on which to operate. 597848b8605Smrg * \param size Size, in bytes, of the new data store. 598848b8605Smrg * \param data Pointer to the data to store in the buffer object. This 599848b8605Smrg * pointer may be \c NULL. 600848b8605Smrg * \param usage Hints about how the data will be used. 601848b8605Smrg * \param bufObj Object to be used. 602848b8605Smrg * 603848b8605Smrg * \return GL_TRUE for success, GL_FALSE for failure 604848b8605Smrg * \sa glBufferDataARB, dd_function_table::BufferData. 605848b8605Smrg */ 606848b8605Smrgstatic GLboolean 607b8e80941Smrgbuffer_data_fallback(struct gl_context *ctx, GLenum target, GLsizeiptrARB size, 608b8e80941Smrg const GLvoid *data, GLenum usage, GLenum storageFlags, 609b8e80941Smrg struct gl_buffer_object *bufObj) 610848b8605Smrg{ 611848b8605Smrg void * new_data; 612848b8605Smrg 613848b8605Smrg (void) target; 614848b8605Smrg 615848b8605Smrg _mesa_align_free( bufObj->Data ); 616848b8605Smrg 617848b8605Smrg new_data = _mesa_align_malloc( size, ctx->Const.MinMapBufferAlignment ); 618848b8605Smrg if (new_data) { 619848b8605Smrg bufObj->Data = (GLubyte *) new_data; 620848b8605Smrg bufObj->Size = size; 621848b8605Smrg bufObj->Usage = usage; 622848b8605Smrg bufObj->StorageFlags = storageFlags; 623848b8605Smrg 624848b8605Smrg if (data) { 625848b8605Smrg memcpy( bufObj->Data, data, size ); 626848b8605Smrg } 627848b8605Smrg 628848b8605Smrg return GL_TRUE; 629848b8605Smrg } 630848b8605Smrg else { 631848b8605Smrg return GL_FALSE; 632848b8605Smrg } 633848b8605Smrg} 634848b8605Smrg 635848b8605Smrg 636848b8605Smrg/** 637848b8605Smrg * Replace data in a subrange of buffer object. If the data range 638848b8605Smrg * specified by \c size + \c offset extends beyond the end of the buffer or 639848b8605Smrg * if \c data is \c NULL, no copy is performed. 640848b8605Smrg * 641848b8605Smrg * This is the default callback for \c dd_function_table::BufferSubData() 642848b8605Smrg * Note that all GL error checking will have been done already. 643848b8605Smrg * 644848b8605Smrg * \param ctx GL context. 645848b8605Smrg * \param offset Offset of the first byte to be modified. 646848b8605Smrg * \param size Size, in bytes, of the data range. 647848b8605Smrg * \param data Pointer to the data to store in the buffer object. 648848b8605Smrg * \param bufObj Object to be used. 649848b8605Smrg * 650848b8605Smrg * \sa glBufferSubDataARB, dd_function_table::BufferSubData. 651848b8605Smrg */ 652848b8605Smrgstatic void 653b8e80941Smrgbuffer_sub_data_fallback(struct gl_context *ctx, GLintptrARB offset, 654b8e80941Smrg GLsizeiptrARB size, const GLvoid *data, 655b8e80941Smrg struct gl_buffer_object *bufObj) 656848b8605Smrg{ 657848b8605Smrg (void) ctx; 658848b8605Smrg 659848b8605Smrg /* this should have been caught in _mesa_BufferSubData() */ 660b8e80941Smrg assert(size + offset <= bufObj->Size); 661848b8605Smrg 662848b8605Smrg if (bufObj->Data) { 663848b8605Smrg memcpy( (GLubyte *) bufObj->Data + offset, data, size ); 664848b8605Smrg } 665848b8605Smrg} 666848b8605Smrg 667848b8605Smrg 668848b8605Smrg/** 669848b8605Smrg * Retrieve data from a subrange of buffer object. If the data range 670848b8605Smrg * specified by \c size + \c offset extends beyond the end of the buffer or 671848b8605Smrg * if \c data is \c NULL, no copy is performed. 672848b8605Smrg * 673848b8605Smrg * This is the default callback for \c dd_function_table::GetBufferSubData() 674848b8605Smrg * Note that all GL error checking will have been done already. 675848b8605Smrg * 676848b8605Smrg * \param ctx GL context. 677848b8605Smrg * \param target Buffer object target on which to operate. 678848b8605Smrg * \param offset Offset of the first byte to be fetched. 679848b8605Smrg * \param size Size, in bytes, of the data range. 680848b8605Smrg * \param data Destination for data 681848b8605Smrg * \param bufObj Object to be used. 682848b8605Smrg * 683848b8605Smrg * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData. 684848b8605Smrg */ 685848b8605Smrgstatic void 686b8e80941Smrgbuffer_get_subdata(struct gl_context *ctx, GLintptrARB offset, 687b8e80941Smrg GLsizeiptrARB size, GLvoid *data, 688b8e80941Smrg struct gl_buffer_object *bufObj ) 689848b8605Smrg{ 690848b8605Smrg (void) ctx; 691848b8605Smrg 692848b8605Smrg if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) { 693848b8605Smrg memcpy( data, (GLubyte *) bufObj->Data + offset, size ); 694848b8605Smrg } 695848b8605Smrg} 696848b8605Smrg 697848b8605Smrg 698848b8605Smrg/** 699848b8605Smrg * Clear a subrange of the buffer object with copies of the supplied data. 700848b8605Smrg * If data is NULL the buffer is filled with zeros. 701848b8605Smrg * 702848b8605Smrg * This is the default callback for \c dd_function_table::ClearBufferSubData() 703848b8605Smrg * Note that all GL error checking will have been done already. 704848b8605Smrg * 705848b8605Smrg * \param ctx GL context. 706848b8605Smrg * \param offset Offset of the first byte to be cleared. 707848b8605Smrg * \param size Size, in bytes, of the to be cleared range. 708848b8605Smrg * \param clearValue Source of the data. 709848b8605Smrg * \param clearValueSize Size, in bytes, of the supplied data. 710848b8605Smrg * \param bufObj Object to be cleared. 711848b8605Smrg * 712848b8605Smrg * \sa glClearBufferSubData, glClearBufferData and 713848b8605Smrg * dd_function_table::ClearBufferSubData. 714848b8605Smrg */ 715848b8605Smrgvoid 716b8e80941Smrg_mesa_ClearBufferSubData_sw(struct gl_context *ctx, 717b8e80941Smrg GLintptr offset, GLsizeiptr size, 718b8e80941Smrg const GLvoid *clearValue, 719b8e80941Smrg GLsizeiptr clearValueSize, 720b8e80941Smrg struct gl_buffer_object *bufObj) 721848b8605Smrg{ 722848b8605Smrg GLsizeiptr i; 723848b8605Smrg GLubyte *dest; 724848b8605Smrg 725b8e80941Smrg assert(ctx->Driver.MapBufferRange); 726848b8605Smrg dest = ctx->Driver.MapBufferRange(ctx, offset, size, 727848b8605Smrg GL_MAP_WRITE_BIT | 728848b8605Smrg GL_MAP_INVALIDATE_RANGE_BIT, 729848b8605Smrg bufObj, MAP_INTERNAL); 730848b8605Smrg 731848b8605Smrg if (!dest) { 732848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClearBuffer[Sub]Data"); 733848b8605Smrg return; 734848b8605Smrg } 735848b8605Smrg 736848b8605Smrg if (clearValue == NULL) { 737848b8605Smrg /* Clear with zeros, per the spec */ 738848b8605Smrg memset(dest, 0, size); 739848b8605Smrg ctx->Driver.UnmapBuffer(ctx, bufObj, MAP_INTERNAL); 740848b8605Smrg return; 741848b8605Smrg } 742848b8605Smrg 743848b8605Smrg for (i = 0; i < size/clearValueSize; ++i) { 744848b8605Smrg memcpy(dest, clearValue, clearValueSize); 745848b8605Smrg dest += clearValueSize; 746848b8605Smrg } 747848b8605Smrg 748848b8605Smrg ctx->Driver.UnmapBuffer(ctx, bufObj, MAP_INTERNAL); 749848b8605Smrg} 750848b8605Smrg 751848b8605Smrg 752848b8605Smrg/** 753848b8605Smrg * Default fallback for \c dd_function_table::MapBufferRange(). 754848b8605Smrg * Called via glMapBufferRange(). 755848b8605Smrg */ 756848b8605Smrgstatic void * 757b8e80941Smrgmap_buffer_range_fallback(struct gl_context *ctx, GLintptr offset, 758b8e80941Smrg GLsizeiptr length, GLbitfield access, 759b8e80941Smrg struct gl_buffer_object *bufObj, 760b8e80941Smrg gl_map_buffer_index index) 761848b8605Smrg{ 762848b8605Smrg (void) ctx; 763848b8605Smrg assert(!_mesa_bufferobj_mapped(bufObj, index)); 764848b8605Smrg /* Just return a direct pointer to the data */ 765848b8605Smrg bufObj->Mappings[index].Pointer = bufObj->Data + offset; 766848b8605Smrg bufObj->Mappings[index].Length = length; 767848b8605Smrg bufObj->Mappings[index].Offset = offset; 768848b8605Smrg bufObj->Mappings[index].AccessFlags = access; 769848b8605Smrg return bufObj->Mappings[index].Pointer; 770848b8605Smrg} 771848b8605Smrg 772848b8605Smrg 773848b8605Smrg/** 774848b8605Smrg * Default fallback for \c dd_function_table::FlushMappedBufferRange(). 775848b8605Smrg * Called via glFlushMappedBufferRange(). 776848b8605Smrg */ 777848b8605Smrgstatic void 778b8e80941Smrgflush_mapped_buffer_range_fallback(struct gl_context *ctx, 779b8e80941Smrg GLintptr offset, GLsizeiptr length, 780b8e80941Smrg struct gl_buffer_object *obj, 781b8e80941Smrg gl_map_buffer_index index) 782848b8605Smrg{ 783848b8605Smrg (void) ctx; 784848b8605Smrg (void) offset; 785848b8605Smrg (void) length; 786848b8605Smrg (void) obj; 787b8e80941Smrg (void) index; 788848b8605Smrg /* no-op */ 789848b8605Smrg} 790848b8605Smrg 791848b8605Smrg 792848b8605Smrg/** 793b8e80941Smrg * Default callback for \c dd_function_table::UnmapBuffer(). 794848b8605Smrg * 795848b8605Smrg * The input parameters will have been already tested for errors. 796848b8605Smrg * 797848b8605Smrg * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer 798848b8605Smrg */ 799848b8605Smrgstatic GLboolean 800b8e80941Smrgunmap_buffer_fallback(struct gl_context *ctx, struct gl_buffer_object *bufObj, 801b8e80941Smrg gl_map_buffer_index index) 802848b8605Smrg{ 803848b8605Smrg (void) ctx; 804848b8605Smrg /* XXX we might assert here that bufObj->Pointer is non-null */ 805848b8605Smrg bufObj->Mappings[index].Pointer = NULL; 806848b8605Smrg bufObj->Mappings[index].Length = 0; 807848b8605Smrg bufObj->Mappings[index].Offset = 0; 808848b8605Smrg bufObj->Mappings[index].AccessFlags = 0x0; 809848b8605Smrg return GL_TRUE; 810848b8605Smrg} 811848b8605Smrg 812848b8605Smrg 813848b8605Smrg/** 814848b8605Smrg * Default fallback for \c dd_function_table::CopyBufferSubData(). 815848b8605Smrg * Called via glCopyBufferSubData(). 816848b8605Smrg */ 817848b8605Smrgstatic void 818b8e80941Smrgcopy_buffer_sub_data_fallback(struct gl_context *ctx, 819b8e80941Smrg struct gl_buffer_object *src, 820b8e80941Smrg struct gl_buffer_object *dst, 821b8e80941Smrg GLintptr readOffset, GLintptr writeOffset, 822b8e80941Smrg GLsizeiptr size) 823848b8605Smrg{ 824848b8605Smrg GLubyte *srcPtr, *dstPtr; 825848b8605Smrg 826848b8605Smrg if (src == dst) { 827848b8605Smrg srcPtr = dstPtr = ctx->Driver.MapBufferRange(ctx, 0, src->Size, 828848b8605Smrg GL_MAP_READ_BIT | 829848b8605Smrg GL_MAP_WRITE_BIT, src, 830848b8605Smrg MAP_INTERNAL); 831848b8605Smrg 832848b8605Smrg if (!srcPtr) 833848b8605Smrg return; 834848b8605Smrg 835848b8605Smrg srcPtr += readOffset; 836848b8605Smrg dstPtr += writeOffset; 837848b8605Smrg } else { 838848b8605Smrg srcPtr = ctx->Driver.MapBufferRange(ctx, readOffset, size, 839848b8605Smrg GL_MAP_READ_BIT, src, 840848b8605Smrg MAP_INTERNAL); 841848b8605Smrg dstPtr = ctx->Driver.MapBufferRange(ctx, writeOffset, size, 842848b8605Smrg (GL_MAP_WRITE_BIT | 843848b8605Smrg GL_MAP_INVALIDATE_RANGE_BIT), dst, 844848b8605Smrg MAP_INTERNAL); 845848b8605Smrg } 846848b8605Smrg 847848b8605Smrg /* Note: the src and dst regions will never overlap. Trying to do so 848848b8605Smrg * would generate GL_INVALID_VALUE earlier. 849848b8605Smrg */ 850848b8605Smrg if (srcPtr && dstPtr) 851848b8605Smrg memcpy(dstPtr, srcPtr, size); 852848b8605Smrg 853848b8605Smrg ctx->Driver.UnmapBuffer(ctx, src, MAP_INTERNAL); 854848b8605Smrg if (dst != src) 855848b8605Smrg ctx->Driver.UnmapBuffer(ctx, dst, MAP_INTERNAL); 856848b8605Smrg} 857848b8605Smrg 858848b8605Smrg 859848b8605Smrg 860848b8605Smrg/** 861848b8605Smrg * Initialize the state associated with buffer objects 862848b8605Smrg */ 863848b8605Smrgvoid 864848b8605Smrg_mesa_init_buffer_objects( struct gl_context *ctx ) 865848b8605Smrg{ 866848b8605Smrg GLuint i; 867848b8605Smrg 868848b8605Smrg memset(&DummyBufferObject, 0, sizeof(DummyBufferObject)); 869b8e80941Smrg simple_mtx_init(&DummyBufferObject.MinMaxCacheMutex, mtx_plain); 870848b8605Smrg DummyBufferObject.RefCount = 1000*1000*1000; /* never delete */ 871848b8605Smrg 872848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, 873848b8605Smrg ctx->Shared->NullBufferObj); 874848b8605Smrg 875848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, 876848b8605Smrg ctx->Shared->NullBufferObj); 877848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, 878848b8605Smrg ctx->Shared->NullBufferObj); 879848b8605Smrg 880848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, 881848b8605Smrg ctx->Shared->NullBufferObj); 882848b8605Smrg 883b8e80941Smrg _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer, 884b8e80941Smrg ctx->Shared->NullBufferObj); 885b8e80941Smrg 886848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, 887848b8605Smrg ctx->Shared->NullBufferObj); 888848b8605Smrg 889848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->DrawIndirectBuffer, 890848b8605Smrg ctx->Shared->NullBufferObj); 891848b8605Smrg 892b8e80941Smrg _mesa_reference_buffer_object(ctx, &ctx->ParameterBuffer, 893b8e80941Smrg ctx->Shared->NullBufferObj); 894b8e80941Smrg 895b8e80941Smrg _mesa_reference_buffer_object(ctx, &ctx->DispatchIndirectBuffer, 896b8e80941Smrg ctx->Shared->NullBufferObj); 897b8e80941Smrg 898b8e80941Smrg _mesa_reference_buffer_object(ctx, &ctx->QueryBuffer, 899b8e80941Smrg ctx->Shared->NullBufferObj); 900b8e80941Smrg 901848b8605Smrg for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) { 902848b8605Smrg _mesa_reference_buffer_object(ctx, 903848b8605Smrg &ctx->UniformBufferBindings[i].BufferObject, 904848b8605Smrg ctx->Shared->NullBufferObj); 905848b8605Smrg ctx->UniformBufferBindings[i].Offset = -1; 906848b8605Smrg ctx->UniformBufferBindings[i].Size = -1; 907848b8605Smrg } 908848b8605Smrg 909b8e80941Smrg for (i = 0; i < MAX_COMBINED_SHADER_STORAGE_BUFFERS; i++) { 910b8e80941Smrg _mesa_reference_buffer_object(ctx, 911b8e80941Smrg &ctx->ShaderStorageBufferBindings[i].BufferObject, 912b8e80941Smrg ctx->Shared->NullBufferObj); 913b8e80941Smrg ctx->ShaderStorageBufferBindings[i].Offset = -1; 914b8e80941Smrg ctx->ShaderStorageBufferBindings[i].Size = -1; 915b8e80941Smrg } 916b8e80941Smrg 917848b8605Smrg for (i = 0; i < MAX_COMBINED_ATOMIC_BUFFERS; i++) { 918848b8605Smrg _mesa_reference_buffer_object(ctx, 919848b8605Smrg &ctx->AtomicBufferBindings[i].BufferObject, 920848b8605Smrg ctx->Shared->NullBufferObj); 921b8e80941Smrg ctx->AtomicBufferBindings[i].Offset = 0; 922b8e80941Smrg ctx->AtomicBufferBindings[i].Size = 0; 923848b8605Smrg } 924848b8605Smrg} 925848b8605Smrg 926848b8605Smrg 927848b8605Smrgvoid 928848b8605Smrg_mesa_free_buffer_objects( struct gl_context *ctx ) 929848b8605Smrg{ 930848b8605Smrg GLuint i; 931848b8605Smrg 932848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL); 933848b8605Smrg 934848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, NULL); 935848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, NULL); 936848b8605Smrg 937848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, NULL); 938848b8605Smrg 939b8e80941Smrg _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer, NULL); 940b8e80941Smrg 941848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, NULL); 942848b8605Smrg 943848b8605Smrg _mesa_reference_buffer_object(ctx, &ctx->DrawIndirectBuffer, NULL); 944848b8605Smrg 945b8e80941Smrg _mesa_reference_buffer_object(ctx, &ctx->ParameterBuffer, NULL); 946b8e80941Smrg 947b8e80941Smrg _mesa_reference_buffer_object(ctx, &ctx->DispatchIndirectBuffer, NULL); 948b8e80941Smrg 949b8e80941Smrg _mesa_reference_buffer_object(ctx, &ctx->QueryBuffer, NULL); 950b8e80941Smrg 951848b8605Smrg for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) { 952848b8605Smrg _mesa_reference_buffer_object(ctx, 953848b8605Smrg &ctx->UniformBufferBindings[i].BufferObject, 954848b8605Smrg NULL); 955848b8605Smrg } 956848b8605Smrg 957b8e80941Smrg for (i = 0; i < MAX_COMBINED_SHADER_STORAGE_BUFFERS; i++) { 958b8e80941Smrg _mesa_reference_buffer_object(ctx, 959b8e80941Smrg &ctx->ShaderStorageBufferBindings[i].BufferObject, 960b8e80941Smrg NULL); 961b8e80941Smrg } 962b8e80941Smrg 963848b8605Smrg for (i = 0; i < MAX_COMBINED_ATOMIC_BUFFERS; i++) { 964848b8605Smrg _mesa_reference_buffer_object(ctx, 965848b8605Smrg &ctx->AtomicBufferBindings[i].BufferObject, 966848b8605Smrg NULL); 967848b8605Smrg } 968848b8605Smrg 969848b8605Smrg} 970848b8605Smrg 971848b8605Smrgbool 972848b8605Smrg_mesa_handle_bind_buffer_gen(struct gl_context *ctx, 973848b8605Smrg GLuint buffer, 974848b8605Smrg struct gl_buffer_object **buf_handle, 975848b8605Smrg const char *caller) 976848b8605Smrg{ 977848b8605Smrg struct gl_buffer_object *buf = *buf_handle; 978848b8605Smrg 979b8e80941Smrg if (!buf && (ctx->API == API_OPENGL_CORE)) { 980848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", caller); 981848b8605Smrg return false; 982848b8605Smrg } 983848b8605Smrg 984848b8605Smrg if (!buf || buf == &DummyBufferObject) { 985848b8605Smrg /* If this is a new buffer object id, or one which was generated but 986848b8605Smrg * never used before, allocate a buffer object now. 987848b8605Smrg */ 988b8e80941Smrg buf = ctx->Driver.NewBufferObject(ctx, buffer); 989848b8605Smrg if (!buf) { 990848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller); 991848b8605Smrg return false; 992848b8605Smrg } 993848b8605Smrg _mesa_HashInsert(ctx->Shared->BufferObjects, buffer, buf); 994848b8605Smrg *buf_handle = buf; 995848b8605Smrg } 996848b8605Smrg 997848b8605Smrg return true; 998848b8605Smrg} 999848b8605Smrg 1000848b8605Smrg/** 1001848b8605Smrg * Bind the specified target to buffer for the specified context. 1002848b8605Smrg * Called by glBindBuffer() and other functions. 1003848b8605Smrg */ 1004848b8605Smrgstatic void 1005b8e80941Smrgbind_buffer_object(struct gl_context *ctx, 1006b8e80941Smrg struct gl_buffer_object **bindTarget, GLuint buffer) 1007848b8605Smrg{ 1008848b8605Smrg struct gl_buffer_object *oldBufObj; 1009848b8605Smrg struct gl_buffer_object *newBufObj = NULL; 1010848b8605Smrg 1011b8e80941Smrg assert(bindTarget); 1012848b8605Smrg 1013848b8605Smrg /* Get pointer to old buffer object (to be unbound) */ 1014848b8605Smrg oldBufObj = *bindTarget; 1015848b8605Smrg if (oldBufObj && oldBufObj->Name == buffer && !oldBufObj->DeletePending) 1016848b8605Smrg return; /* rebinding the same buffer object- no change */ 1017848b8605Smrg 1018848b8605Smrg /* 1019848b8605Smrg * Get pointer to new buffer object (newBufObj) 1020848b8605Smrg */ 1021848b8605Smrg if (buffer == 0) { 1022848b8605Smrg /* The spec says there's not a buffer object named 0, but we use 1023848b8605Smrg * one internally because it simplifies things. 1024848b8605Smrg */ 1025848b8605Smrg newBufObj = ctx->Shared->NullBufferObj; 1026848b8605Smrg } 1027848b8605Smrg else { 1028848b8605Smrg /* non-default buffer object */ 1029848b8605Smrg newBufObj = _mesa_lookup_bufferobj(ctx, buffer); 1030b8e80941Smrg if (!_mesa_handle_bind_buffer_gen(ctx, buffer, 1031848b8605Smrg &newBufObj, "glBindBuffer")) 1032848b8605Smrg return; 1033848b8605Smrg } 1034b8e80941Smrg 1035b8e80941Smrg /* record usage history */ 1036b8e80941Smrg if (bindTarget == &ctx->Pack.BufferObj) { 1037b8e80941Smrg newBufObj->UsageHistory |= USAGE_PIXEL_PACK_BUFFER; 1038b8e80941Smrg } 1039b8e80941Smrg 1040848b8605Smrg /* bind new buffer */ 1041848b8605Smrg _mesa_reference_buffer_object(ctx, bindTarget, newBufObj); 1042848b8605Smrg} 1043848b8605Smrg 1044848b8605Smrg 1045848b8605Smrg/** 1046848b8605Smrg * Update the default buffer objects in the given context to reference those 1047b8e80941Smrg * specified in the shared state and release those referencing the old 1048848b8605Smrg * shared state. 1049848b8605Smrg */ 1050848b8605Smrgvoid 1051848b8605Smrg_mesa_update_default_objects_buffer_objects(struct gl_context *ctx) 1052848b8605Smrg{ 1053848b8605Smrg /* Bind the NullBufferObj to remove references to those 1054848b8605Smrg * in the shared context hash table. 1055848b8605Smrg */ 1056b8e80941Smrg bind_buffer_object(ctx, &ctx->Array.ArrayBufferObj, 0); 1057b8e80941Smrg bind_buffer_object(ctx, &ctx->Array.VAO->IndexBufferObj, 0); 1058b8e80941Smrg bind_buffer_object(ctx, &ctx->Pack.BufferObj, 0); 1059b8e80941Smrg bind_buffer_object(ctx, &ctx->Unpack.BufferObj, 0); 1060848b8605Smrg} 1061848b8605Smrg 1062848b8605Smrg 1063848b8605Smrg 1064848b8605Smrg/** 1065848b8605Smrg * Return the gl_buffer_object for the given ID. 1066848b8605Smrg * Always return NULL for ID 0. 1067848b8605Smrg */ 1068848b8605Smrgstruct gl_buffer_object * 1069848b8605Smrg_mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer) 1070848b8605Smrg{ 1071848b8605Smrg if (buffer == 0) 1072848b8605Smrg return NULL; 1073848b8605Smrg else 1074848b8605Smrg return (struct gl_buffer_object *) 1075848b8605Smrg _mesa_HashLookup(ctx->Shared->BufferObjects, buffer); 1076848b8605Smrg} 1077848b8605Smrg 1078848b8605Smrg 1079848b8605Smrgstruct gl_buffer_object * 1080848b8605Smrg_mesa_lookup_bufferobj_locked(struct gl_context *ctx, GLuint buffer) 1081848b8605Smrg{ 1082b8e80941Smrg if (buffer == 0) 1083b8e80941Smrg return NULL; 1084b8e80941Smrg else 1085b8e80941Smrg return (struct gl_buffer_object *) 1086b8e80941Smrg _mesa_HashLookupLocked(ctx->Shared->BufferObjects, buffer); 1087848b8605Smrg} 1088848b8605Smrg 1089b8e80941Smrg/** 1090b8e80941Smrg * A convenience function for direct state access functions that throws 1091b8e80941Smrg * GL_INVALID_OPERATION if buffer is not the name of an existing 1092b8e80941Smrg * buffer object. 1093b8e80941Smrg */ 1094b8e80941Smrgstruct gl_buffer_object * 1095b8e80941Smrg_mesa_lookup_bufferobj_err(struct gl_context *ctx, GLuint buffer, 1096b8e80941Smrg const char *caller) 1097848b8605Smrg{ 1098b8e80941Smrg struct gl_buffer_object *bufObj; 1099848b8605Smrg 1100b8e80941Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 1101b8e80941Smrg if (!bufObj || bufObj == &DummyBufferObject) { 1102b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1103b8e80941Smrg "%s(non-existent buffer object %u)", caller, buffer); 1104b8e80941Smrg return NULL; 1105b8e80941Smrg } 1106848b8605Smrg 1107b8e80941Smrg return bufObj; 1108848b8605Smrg} 1109848b8605Smrg 1110848b8605Smrg 1111848b8605Smrg/** 1112848b8605Smrg * Look up a buffer object for a multi-bind function. 1113848b8605Smrg * 1114848b8605Smrg * Unlike _mesa_lookup_bufferobj(), this function also takes care 1115848b8605Smrg * of generating an error if the buffer ID is not zero or the name 1116848b8605Smrg * of an existing buffer object. 1117848b8605Smrg * 1118848b8605Smrg * If the buffer ID refers to an existing buffer object, a pointer 1119848b8605Smrg * to the buffer object is returned. If the ID is zero, a pointer 1120848b8605Smrg * to the shared NullBufferObj is returned. If the ID is not zero 1121848b8605Smrg * and does not refer to a valid buffer object, this function 1122848b8605Smrg * returns NULL. 1123848b8605Smrg * 1124848b8605Smrg * This function assumes that the caller has already locked the 1125b8e80941Smrg * hash table mutex by calling 1126b8e80941Smrg * _mesa_HashLockMutex(ctx->Shared->BufferObjects). 1127848b8605Smrg */ 1128848b8605Smrgstruct gl_buffer_object * 1129848b8605Smrg_mesa_multi_bind_lookup_bufferobj(struct gl_context *ctx, 1130848b8605Smrg const GLuint *buffers, 1131848b8605Smrg GLuint index, const char *caller) 1132848b8605Smrg{ 1133848b8605Smrg struct gl_buffer_object *bufObj; 1134848b8605Smrg 1135848b8605Smrg if (buffers[index] != 0) { 1136848b8605Smrg bufObj = _mesa_lookup_bufferobj_locked(ctx, buffers[index]); 1137848b8605Smrg 1138848b8605Smrg /* The multi-bind functions don't create the buffer objects 1139848b8605Smrg when they don't exist. */ 1140848b8605Smrg if (bufObj == &DummyBufferObject) 1141848b8605Smrg bufObj = NULL; 1142848b8605Smrg } else 1143848b8605Smrg bufObj = ctx->Shared->NullBufferObj; 1144848b8605Smrg 1145848b8605Smrg if (!bufObj) { 1146848b8605Smrg /* The ARB_multi_bind spec says: 1147848b8605Smrg * 1148848b8605Smrg * "An INVALID_OPERATION error is generated if any value 1149848b8605Smrg * in <buffers> is not zero or the name of an existing 1150848b8605Smrg * buffer object (per binding)." 1151848b8605Smrg */ 1152848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1153848b8605Smrg "%s(buffers[%u]=%u is not zero or the name " 1154848b8605Smrg "of an existing buffer object)", 1155848b8605Smrg caller, index, buffers[index]); 1156848b8605Smrg } 1157848b8605Smrg 1158848b8605Smrg return bufObj; 1159848b8605Smrg} 1160848b8605Smrg 1161848b8605Smrg 1162848b8605Smrg/** 1163848b8605Smrg * If *ptr points to obj, set ptr = the Null/default buffer object. 1164848b8605Smrg * This is a helper for buffer object deletion. 1165848b8605Smrg * The GL spec says that deleting a buffer object causes it to get 1166848b8605Smrg * unbound from all arrays in the current context. 1167848b8605Smrg */ 1168848b8605Smrgstatic void 1169848b8605Smrgunbind(struct gl_context *ctx, 1170b8e80941Smrg struct gl_vertex_array_object *vao, unsigned index, 1171848b8605Smrg struct gl_buffer_object *obj) 1172848b8605Smrg{ 1173b8e80941Smrg if (vao->BufferBinding[index].BufferObj == obj) { 1174b8e80941Smrg _mesa_bind_vertex_buffer(ctx, vao, index, ctx->Shared->NullBufferObj, 1175b8e80941Smrg vao->BufferBinding[index].Offset, 1176b8e80941Smrg vao->BufferBinding[index].Stride); 1177848b8605Smrg } 1178848b8605Smrg} 1179848b8605Smrg 1180848b8605Smrg 1181848b8605Smrg/** 1182848b8605Smrg * Plug default/fallback buffer object functions into the device 1183848b8605Smrg * driver hooks. 1184848b8605Smrg */ 1185848b8605Smrgvoid 1186848b8605Smrg_mesa_init_buffer_object_functions(struct dd_function_table *driver) 1187848b8605Smrg{ 1188848b8605Smrg /* GL_ARB_vertex/pixel_buffer_object */ 1189848b8605Smrg driver->NewBufferObject = _mesa_new_buffer_object; 1190848b8605Smrg driver->DeleteBuffer = _mesa_delete_buffer_object; 1191b8e80941Smrg driver->BufferData = buffer_data_fallback; 1192b8e80941Smrg driver->BufferSubData = buffer_sub_data_fallback; 1193b8e80941Smrg driver->GetBufferSubData = buffer_get_subdata; 1194b8e80941Smrg driver->UnmapBuffer = unmap_buffer_fallback; 1195848b8605Smrg 1196848b8605Smrg /* GL_ARB_clear_buffer_object */ 1197b8e80941Smrg driver->ClearBufferSubData = _mesa_ClearBufferSubData_sw; 1198848b8605Smrg 1199848b8605Smrg /* GL_ARB_map_buffer_range */ 1200b8e80941Smrg driver->MapBufferRange = map_buffer_range_fallback; 1201b8e80941Smrg driver->FlushMappedBufferRange = flush_mapped_buffer_range_fallback; 1202848b8605Smrg 1203848b8605Smrg /* GL_ARB_copy_buffer */ 1204b8e80941Smrg driver->CopyBufferSubData = copy_buffer_sub_data_fallback; 1205848b8605Smrg} 1206848b8605Smrg 1207848b8605Smrg 1208848b8605Smrgvoid 1209848b8605Smrg_mesa_buffer_unmap_all_mappings(struct gl_context *ctx, 1210848b8605Smrg struct gl_buffer_object *bufObj) 1211848b8605Smrg{ 1212b8e80941Smrg for (int i = 0; i < MAP_COUNT; i++) { 1213848b8605Smrg if (_mesa_bufferobj_mapped(bufObj, i)) { 1214848b8605Smrg ctx->Driver.UnmapBuffer(ctx, bufObj, i); 1215b8e80941Smrg assert(bufObj->Mappings[i].Pointer == NULL); 1216848b8605Smrg bufObj->Mappings[i].AccessFlags = 0; 1217848b8605Smrg } 1218848b8605Smrg } 1219848b8605Smrg} 1220848b8605Smrg 1221848b8605Smrg 1222848b8605Smrg/**********************************************************************/ 1223848b8605Smrg/* API Functions */ 1224848b8605Smrg/**********************************************************************/ 1225848b8605Smrg 1226848b8605Smrgvoid GLAPIENTRY 1227b8e80941Smrg_mesa_BindBuffer_no_error(GLenum target, GLuint buffer) 1228848b8605Smrg{ 1229848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1230848b8605Smrg 1231b8e80941Smrg struct gl_buffer_object **bindTarget = get_buffer_target(ctx, target); 1232b8e80941Smrg bind_buffer_object(ctx, bindTarget, buffer); 1233848b8605Smrg} 1234848b8605Smrg 1235848b8605Smrg 1236848b8605Smrgvoid GLAPIENTRY 1237b8e80941Smrg_mesa_BindBuffer(GLenum target, GLuint buffer) 1238848b8605Smrg{ 1239848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1240848b8605Smrg 1241b8e80941Smrg if (MESA_VERBOSE & VERBOSE_API) { 1242b8e80941Smrg _mesa_debug(ctx, "glBindBuffer(%s, %u)\n", 1243b8e80941Smrg _mesa_enum_to_string(target), buffer); 1244848b8605Smrg } 1245848b8605Smrg 1246b8e80941Smrg struct gl_buffer_object **bindTarget = get_buffer_target(ctx, target); 1247b8e80941Smrg if (!bindTarget) { 1248b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target %s)", 1249b8e80941Smrg _mesa_enum_to_string(target)); 1250b8e80941Smrg return; 1251848b8605Smrg } 1252848b8605Smrg 1253b8e80941Smrg bind_buffer_object(ctx, bindTarget, buffer); 1254848b8605Smrg} 1255848b8605Smrg 1256848b8605Smrg/** 1257b8e80941Smrg * Binds a buffer object to a binding point. 1258b8e80941Smrg * 1259b8e80941Smrg * The caller is responsible for validating the offset, 1260b8e80941Smrg * flushing the vertices and updating NewDriverState. 1261848b8605Smrg */ 1262b8e80941Smrgstatic void 1263b8e80941Smrgset_buffer_binding(struct gl_context *ctx, 1264b8e80941Smrg struct gl_buffer_binding *binding, 1265b8e80941Smrg struct gl_buffer_object *bufObj, 1266b8e80941Smrg GLintptr offset, 1267b8e80941Smrg GLsizeiptr size, 1268b8e80941Smrg bool autoSize, gl_buffer_usage usage) 1269848b8605Smrg{ 1270b8e80941Smrg _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj); 1271848b8605Smrg 1272b8e80941Smrg binding->Offset = offset; 1273b8e80941Smrg binding->Size = size; 1274b8e80941Smrg binding->AutomaticSize = autoSize; 1275848b8605Smrg 1276b8e80941Smrg /* If this is a real buffer object, mark it has having been used 1277b8e80941Smrg * at some point as an atomic counter buffer. 1278b8e80941Smrg */ 1279b8e80941Smrg if (size >= 0) 1280b8e80941Smrg bufObj->UsageHistory |= usage; 1281b8e80941Smrg} 1282b8e80941Smrg 1283b8e80941Smrgstatic void 1284b8e80941Smrgset_buffer_multi_binding(struct gl_context *ctx, 1285b8e80941Smrg const GLuint *buffers, 1286b8e80941Smrg int idx, 1287b8e80941Smrg const char *caller, 1288b8e80941Smrg struct gl_buffer_binding *binding, 1289b8e80941Smrg GLintptr offset, 1290b8e80941Smrg GLsizeiptr size, 1291b8e80941Smrg bool range, 1292b8e80941Smrg gl_buffer_usage usage) 1293b8e80941Smrg{ 1294b8e80941Smrg struct gl_buffer_object *bufObj; 1295b8e80941Smrg if (binding->BufferObject && binding->BufferObject->Name == buffers[idx]) 1296b8e80941Smrg bufObj = binding->BufferObject; 1297b8e80941Smrg else 1298b8e80941Smrg bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, idx, caller); 1299b8e80941Smrg 1300b8e80941Smrg if (bufObj) { 1301b8e80941Smrg if (bufObj == ctx->Shared->NullBufferObj) 1302b8e80941Smrg set_buffer_binding(ctx, binding, bufObj, -1, -1, !range, usage); 1303b8e80941Smrg else 1304b8e80941Smrg set_buffer_binding(ctx, binding, bufObj, offset, size, !range, usage); 1305848b8605Smrg } 1306b8e80941Smrg} 1307848b8605Smrg 1308b8e80941Smrgstatic void 1309b8e80941Smrgbind_buffer(struct gl_context *ctx, 1310b8e80941Smrg struct gl_buffer_binding *binding, 1311b8e80941Smrg struct gl_buffer_object *bufObj, 1312b8e80941Smrg GLintptr offset, 1313b8e80941Smrg GLsizeiptr size, 1314b8e80941Smrg GLboolean autoSize, 1315b8e80941Smrg uint64_t driver_state, 1316b8e80941Smrg gl_buffer_usage usage) 1317b8e80941Smrg{ 1318b8e80941Smrg if (binding->BufferObject == bufObj && 1319b8e80941Smrg binding->Offset == offset && 1320b8e80941Smrg binding->Size == size && 1321b8e80941Smrg binding->AutomaticSize == autoSize) { 1322848b8605Smrg return; 1323848b8605Smrg } 1324848b8605Smrg 1325b8e80941Smrg FLUSH_VERTICES(ctx, 0); 1326b8e80941Smrg ctx->NewDriverState |= driver_state; 1327848b8605Smrg 1328b8e80941Smrg set_buffer_binding(ctx, binding, bufObj, offset, size, autoSize, usage); 1329848b8605Smrg} 1330848b8605Smrg 1331b8e80941Smrg/** 1332b8e80941Smrg * Binds a buffer object to a uniform buffer binding point. 1333b8e80941Smrg * 1334b8e80941Smrg * Unlike set_buffer_binding(), this function also flushes vertices 1335b8e80941Smrg * and updates NewDriverState. It also checks if the binding 1336b8e80941Smrg * has actually changed before updating it. 1337b8e80941Smrg */ 1338b8e80941Smrgstatic void 1339b8e80941Smrgbind_uniform_buffer(struct gl_context *ctx, 1340b8e80941Smrg GLuint index, 1341b8e80941Smrg struct gl_buffer_object *bufObj, 1342b8e80941Smrg GLintptr offset, 1343b8e80941Smrg GLsizeiptr size, 1344b8e80941Smrg GLboolean autoSize) 1345b8e80941Smrg{ 1346b8e80941Smrg bind_buffer(ctx, &ctx->UniformBufferBindings[index], 1347b8e80941Smrg bufObj, offset, size, autoSize, 1348b8e80941Smrg ctx->DriverFlags.NewUniformBuffer, 1349b8e80941Smrg USAGE_UNIFORM_BUFFER); 1350b8e80941Smrg} 1351b8e80941Smrg 1352b8e80941Smrg/** 1353b8e80941Smrg * Binds a buffer object to a shader storage buffer binding point. 1354b8e80941Smrg * 1355b8e80941Smrg * Unlike set_ssbo_binding(), this function also flushes vertices 1356b8e80941Smrg * and updates NewDriverState. It also checks if the binding 1357b8e80941Smrg * has actually changed before updating it. 1358b8e80941Smrg */ 1359b8e80941Smrgstatic void 1360b8e80941Smrgbind_shader_storage_buffer(struct gl_context *ctx, 1361b8e80941Smrg GLuint index, 1362b8e80941Smrg struct gl_buffer_object *bufObj, 1363b8e80941Smrg GLintptr offset, 1364b8e80941Smrg GLsizeiptr size, 1365b8e80941Smrg GLboolean autoSize) 1366b8e80941Smrg{ 1367b8e80941Smrg bind_buffer(ctx, &ctx->ShaderStorageBufferBindings[index], 1368b8e80941Smrg bufObj, offset, size, autoSize, 1369b8e80941Smrg ctx->DriverFlags.NewShaderStorageBuffer, 1370b8e80941Smrg USAGE_SHADER_STORAGE_BUFFER); 1371b8e80941Smrg} 1372b8e80941Smrg 1373b8e80941Smrg/** 1374b8e80941Smrg * Binds a buffer object to an atomic buffer binding point. 1375b8e80941Smrg * 1376b8e80941Smrg * Unlike set_atomic_binding(), this function also flushes vertices 1377b8e80941Smrg * and updates NewDriverState. It also checks if the binding 1378b8e80941Smrg * has actually changed before updating it. 1379b8e80941Smrg */ 1380b8e80941Smrgstatic void 1381b8e80941Smrgbind_atomic_buffer(struct gl_context *ctx, unsigned index, 1382b8e80941Smrg struct gl_buffer_object *bufObj, GLintptr offset, 1383b8e80941Smrg GLsizeiptr size, GLboolean autoSize) 1384b8e80941Smrg{ 1385b8e80941Smrg bind_buffer(ctx, &ctx->AtomicBufferBindings[index], 1386b8e80941Smrg bufObj, offset, size, autoSize, 1387b8e80941Smrg ctx->DriverFlags.NewAtomicBuffer, 1388b8e80941Smrg USAGE_ATOMIC_COUNTER_BUFFER); 1389b8e80941Smrg} 1390b8e80941Smrg 1391b8e80941Smrg/** 1392b8e80941Smrg * Bind a buffer object to a uniform block binding point. 1393b8e80941Smrg * As above, but offset = 0. 1394b8e80941Smrg */ 1395b8e80941Smrgstatic void 1396b8e80941Smrgbind_buffer_base_uniform_buffer(struct gl_context *ctx, 1397b8e80941Smrg GLuint index, 1398b8e80941Smrg struct gl_buffer_object *bufObj) 1399b8e80941Smrg{ 1400b8e80941Smrg if (index >= ctx->Const.MaxUniformBufferBindings) { 1401b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index); 1402b8e80941Smrg return; 1403b8e80941Smrg } 1404b8e80941Smrg 1405b8e80941Smrg _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj); 1406b8e80941Smrg 1407b8e80941Smrg if (bufObj == ctx->Shared->NullBufferObj) 1408b8e80941Smrg bind_uniform_buffer(ctx, index, bufObj, -1, -1, GL_TRUE); 1409b8e80941Smrg else 1410b8e80941Smrg bind_uniform_buffer(ctx, index, bufObj, 0, 0, GL_TRUE); 1411b8e80941Smrg} 1412b8e80941Smrg 1413b8e80941Smrg/** 1414b8e80941Smrg * Bind a buffer object to a shader storage block binding point. 1415b8e80941Smrg * As above, but offset = 0. 1416b8e80941Smrg */ 1417b8e80941Smrgstatic void 1418b8e80941Smrgbind_buffer_base_shader_storage_buffer(struct gl_context *ctx, 1419b8e80941Smrg GLuint index, 1420b8e80941Smrg struct gl_buffer_object *bufObj) 1421b8e80941Smrg{ 1422b8e80941Smrg if (index >= ctx->Const.MaxShaderStorageBufferBindings) { 1423b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index); 1424b8e80941Smrg return; 1425b8e80941Smrg } 1426b8e80941Smrg 1427b8e80941Smrg _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer, bufObj); 1428b8e80941Smrg 1429b8e80941Smrg if (bufObj == ctx->Shared->NullBufferObj) 1430b8e80941Smrg bind_shader_storage_buffer(ctx, index, bufObj, -1, -1, GL_TRUE); 1431b8e80941Smrg else 1432b8e80941Smrg bind_shader_storage_buffer(ctx, index, bufObj, 0, 0, GL_TRUE); 1433b8e80941Smrg} 1434b8e80941Smrg 1435b8e80941Smrg/** 1436b8e80941Smrg * Bind a buffer object to a shader storage block binding point. 1437b8e80941Smrg * As above, but offset = 0. 1438b8e80941Smrg */ 1439b8e80941Smrgstatic void 1440b8e80941Smrgbind_buffer_base_atomic_buffer(struct gl_context *ctx, 1441b8e80941Smrg GLuint index, 1442b8e80941Smrg struct gl_buffer_object *bufObj) 1443b8e80941Smrg{ 1444b8e80941Smrg if (index >= ctx->Const.MaxAtomicBufferBindings) { 1445b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index); 1446b8e80941Smrg return; 1447b8e80941Smrg } 1448b8e80941Smrg 1449b8e80941Smrg _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, bufObj); 1450b8e80941Smrg 1451b8e80941Smrg if (bufObj == ctx->Shared->NullBufferObj) 1452b8e80941Smrg bind_atomic_buffer(ctx, index, bufObj, -1, -1, GL_TRUE); 1453b8e80941Smrg else 1454b8e80941Smrg bind_atomic_buffer(ctx, index, bufObj, 0, 0, GL_TRUE); 1455b8e80941Smrg} 1456b8e80941Smrg 1457b8e80941Smrg/** 1458b8e80941Smrg * Delete a set of buffer objects. 1459b8e80941Smrg * 1460b8e80941Smrg * \param n Number of buffer objects to delete. 1461b8e80941Smrg * \param ids Array of \c n buffer object IDs. 1462b8e80941Smrg */ 1463b8e80941Smrgstatic void 1464b8e80941Smrgdelete_buffers(struct gl_context *ctx, GLsizei n, const GLuint *ids) 1465b8e80941Smrg{ 1466b8e80941Smrg FLUSH_VERTICES(ctx, 0); 1467b8e80941Smrg 1468b8e80941Smrg _mesa_HashLockMutex(ctx->Shared->BufferObjects); 1469b8e80941Smrg 1470b8e80941Smrg for (GLsizei i = 0; i < n; i++) { 1471b8e80941Smrg struct gl_buffer_object *bufObj = 1472b8e80941Smrg _mesa_lookup_bufferobj_locked(ctx, ids[i]); 1473b8e80941Smrg if (bufObj) { 1474b8e80941Smrg struct gl_vertex_array_object *vao = ctx->Array.VAO; 1475b8e80941Smrg GLuint j; 1476b8e80941Smrg 1477b8e80941Smrg assert(bufObj->Name == ids[i] || bufObj == &DummyBufferObject); 1478b8e80941Smrg 1479b8e80941Smrg _mesa_buffer_unmap_all_mappings(ctx, bufObj); 1480b8e80941Smrg 1481b8e80941Smrg /* unbind any vertex pointers bound to this buffer */ 1482b8e80941Smrg for (j = 0; j < ARRAY_SIZE(vao->BufferBinding); j++) { 1483b8e80941Smrg unbind(ctx, vao, j, bufObj); 1484b8e80941Smrg } 1485b8e80941Smrg 1486b8e80941Smrg if (ctx->Array.ArrayBufferObj == bufObj) { 1487b8e80941Smrg bind_buffer_object(ctx, &ctx->Array.ArrayBufferObj, 0); 1488b8e80941Smrg } 1489b8e80941Smrg if (vao->IndexBufferObj == bufObj) { 1490b8e80941Smrg bind_buffer_object(ctx, &vao->IndexBufferObj, 0); 1491b8e80941Smrg } 1492b8e80941Smrg 1493b8e80941Smrg /* unbind ARB_draw_indirect binding point */ 1494b8e80941Smrg if (ctx->DrawIndirectBuffer == bufObj) { 1495b8e80941Smrg bind_buffer_object(ctx, &ctx->DrawIndirectBuffer, 0); 1496b8e80941Smrg } 1497b8e80941Smrg 1498b8e80941Smrg /* unbind ARB_indirect_parameters binding point */ 1499b8e80941Smrg if (ctx->ParameterBuffer == bufObj) { 1500b8e80941Smrg bind_buffer_object(ctx, &ctx->ParameterBuffer, 0); 1501b8e80941Smrg } 1502b8e80941Smrg 1503b8e80941Smrg /* unbind ARB_compute_shader binding point */ 1504b8e80941Smrg if (ctx->DispatchIndirectBuffer == bufObj) { 1505b8e80941Smrg bind_buffer_object(ctx, &ctx->DispatchIndirectBuffer, 0); 1506b8e80941Smrg } 1507b8e80941Smrg 1508b8e80941Smrg /* unbind ARB_copy_buffer binding points */ 1509b8e80941Smrg if (ctx->CopyReadBuffer == bufObj) { 1510b8e80941Smrg bind_buffer_object(ctx, &ctx->CopyReadBuffer, 0); 1511b8e80941Smrg } 1512b8e80941Smrg if (ctx->CopyWriteBuffer == bufObj) { 1513b8e80941Smrg bind_buffer_object(ctx, &ctx->CopyWriteBuffer, 0); 1514b8e80941Smrg } 1515b8e80941Smrg 1516b8e80941Smrg /* unbind transform feedback binding points */ 1517b8e80941Smrg if (ctx->TransformFeedback.CurrentBuffer == bufObj) { 1518b8e80941Smrg bind_buffer_object(ctx, &ctx->TransformFeedback.CurrentBuffer, 0); 1519b8e80941Smrg } 1520b8e80941Smrg for (j = 0; j < MAX_FEEDBACK_BUFFERS; j++) { 1521b8e80941Smrg if (ctx->TransformFeedback.CurrentObject->Buffers[j] == bufObj) { 1522b8e80941Smrg _mesa_bind_buffer_base_transform_feedback(ctx, 1523b8e80941Smrg ctx->TransformFeedback.CurrentObject, 1524b8e80941Smrg j, ctx->Shared->NullBufferObj, 1525b8e80941Smrg false); 1526b8e80941Smrg } 1527b8e80941Smrg } 1528b8e80941Smrg 1529b8e80941Smrg /* unbind UBO binding points */ 1530b8e80941Smrg for (j = 0; j < ctx->Const.MaxUniformBufferBindings; j++) { 1531b8e80941Smrg if (ctx->UniformBufferBindings[j].BufferObject == bufObj) { 1532b8e80941Smrg bind_buffer_base_uniform_buffer(ctx, j, 1533b8e80941Smrg ctx->Shared->NullBufferObj); 1534b8e80941Smrg } 1535b8e80941Smrg } 1536b8e80941Smrg 1537b8e80941Smrg if (ctx->UniformBuffer == bufObj) { 1538b8e80941Smrg bind_buffer_object(ctx, &ctx->UniformBuffer, 0); 1539b8e80941Smrg } 1540b8e80941Smrg 1541b8e80941Smrg /* unbind SSBO binding points */ 1542b8e80941Smrg for (j = 0; j < ctx->Const.MaxShaderStorageBufferBindings; j++) { 1543b8e80941Smrg if (ctx->ShaderStorageBufferBindings[j].BufferObject == bufObj) { 1544b8e80941Smrg bind_buffer_base_shader_storage_buffer(ctx, j, 1545b8e80941Smrg ctx->Shared->NullBufferObj); 1546b8e80941Smrg } 1547b8e80941Smrg } 1548b8e80941Smrg 1549b8e80941Smrg if (ctx->ShaderStorageBuffer == bufObj) { 1550b8e80941Smrg bind_buffer_object(ctx, &ctx->ShaderStorageBuffer, 0); 1551b8e80941Smrg } 1552b8e80941Smrg 1553b8e80941Smrg /* unbind Atomci Buffer binding points */ 1554b8e80941Smrg for (j = 0; j < ctx->Const.MaxAtomicBufferBindings; j++) { 1555b8e80941Smrg if (ctx->AtomicBufferBindings[j].BufferObject == bufObj) { 1556b8e80941Smrg bind_buffer_base_atomic_buffer(ctx, j, 1557b8e80941Smrg ctx->Shared->NullBufferObj); 1558b8e80941Smrg } 1559b8e80941Smrg } 1560b8e80941Smrg 1561b8e80941Smrg if (ctx->AtomicBuffer == bufObj) { 1562b8e80941Smrg bind_buffer_object(ctx, &ctx->AtomicBuffer, 0); 1563b8e80941Smrg } 1564b8e80941Smrg 1565b8e80941Smrg /* unbind any pixel pack/unpack pointers bound to this buffer */ 1566b8e80941Smrg if (ctx->Pack.BufferObj == bufObj) { 1567b8e80941Smrg bind_buffer_object(ctx, &ctx->Pack.BufferObj, 0); 1568b8e80941Smrg } 1569b8e80941Smrg if (ctx->Unpack.BufferObj == bufObj) { 1570b8e80941Smrg bind_buffer_object(ctx, &ctx->Unpack.BufferObj, 0); 1571b8e80941Smrg } 1572b8e80941Smrg 1573b8e80941Smrg if (ctx->Texture.BufferObject == bufObj) { 1574b8e80941Smrg bind_buffer_object(ctx, &ctx->Texture.BufferObject, 0); 1575b8e80941Smrg } 1576b8e80941Smrg 1577b8e80941Smrg if (ctx->ExternalVirtualMemoryBuffer == bufObj) { 1578b8e80941Smrg bind_buffer_object(ctx, &ctx->ExternalVirtualMemoryBuffer, 0); 1579b8e80941Smrg } 1580b8e80941Smrg 1581b8e80941Smrg /* unbind query buffer binding point */ 1582b8e80941Smrg if (ctx->QueryBuffer == bufObj) { 1583b8e80941Smrg bind_buffer_object(ctx, &ctx->QueryBuffer, 0); 1584b8e80941Smrg } 1585b8e80941Smrg 1586b8e80941Smrg /* The ID is immediately freed for re-use */ 1587b8e80941Smrg _mesa_HashRemoveLocked(ctx->Shared->BufferObjects, ids[i]); 1588b8e80941Smrg /* Make sure we do not run into the classic ABA problem on bind. 1589b8e80941Smrg * We don't want to allow re-binding a buffer object that's been 1590b8e80941Smrg * "deleted" by glDeleteBuffers(). 1591b8e80941Smrg * 1592b8e80941Smrg * The explicit rebinding to the default object in the current context 1593b8e80941Smrg * prevents the above in the current context, but another context 1594b8e80941Smrg * sharing the same objects might suffer from this problem. 1595b8e80941Smrg * The alternative would be to do the hash lookup in any case on bind 1596b8e80941Smrg * which would introduce more runtime overhead than this. 1597b8e80941Smrg */ 1598b8e80941Smrg bufObj->DeletePending = GL_TRUE; 1599b8e80941Smrg _mesa_reference_buffer_object(ctx, &bufObj, NULL); 1600b8e80941Smrg } 1601b8e80941Smrg } 1602b8e80941Smrg 1603b8e80941Smrg _mesa_HashUnlockMutex(ctx->Shared->BufferObjects); 1604b8e80941Smrg} 1605b8e80941Smrg 1606b8e80941Smrg 1607b8e80941Smrgvoid GLAPIENTRY 1608b8e80941Smrg_mesa_DeleteBuffers_no_error(GLsizei n, const GLuint *ids) 1609b8e80941Smrg{ 1610b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 1611b8e80941Smrg delete_buffers(ctx, n, ids); 1612b8e80941Smrg} 1613b8e80941Smrg 1614b8e80941Smrg 1615b8e80941Smrgvoid GLAPIENTRY 1616b8e80941Smrg_mesa_DeleteBuffers(GLsizei n, const GLuint *ids) 1617b8e80941Smrg{ 1618b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 1619b8e80941Smrg 1620b8e80941Smrg if (n < 0) { 1621b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)"); 1622b8e80941Smrg return; 1623b8e80941Smrg } 1624b8e80941Smrg 1625b8e80941Smrg delete_buffers(ctx, n, ids); 1626b8e80941Smrg} 1627b8e80941Smrg 1628b8e80941Smrg 1629b8e80941Smrg/** 1630b8e80941Smrg * This is the implementation for glGenBuffers and glCreateBuffers. It is not 1631b8e80941Smrg * exposed to the rest of Mesa to encourage the use of nameless buffers in 1632b8e80941Smrg * driver internals. 1633b8e80941Smrg */ 1634b8e80941Smrgstatic void 1635b8e80941Smrgcreate_buffers(struct gl_context *ctx, GLsizei n, GLuint *buffers, bool dsa) 1636b8e80941Smrg{ 1637b8e80941Smrg GLuint first; 1638b8e80941Smrg struct gl_buffer_object *buf; 1639b8e80941Smrg 1640b8e80941Smrg if (!buffers) 1641b8e80941Smrg return; 1642b8e80941Smrg 1643b8e80941Smrg /* 1644b8e80941Smrg * This must be atomic (generation and allocation of buffer object IDs) 1645b8e80941Smrg */ 1646b8e80941Smrg _mesa_HashLockMutex(ctx->Shared->BufferObjects); 1647b8e80941Smrg 1648b8e80941Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n); 1649b8e80941Smrg 1650b8e80941Smrg /* Insert the ID and pointer into the hash table. If non-DSA, insert a 1651b8e80941Smrg * DummyBufferObject. Otherwise, create a new buffer object and insert 1652b8e80941Smrg * it. 1653b8e80941Smrg */ 1654b8e80941Smrg for (int i = 0; i < n; i++) { 1655b8e80941Smrg buffers[i] = first + i; 1656b8e80941Smrg if (dsa) { 1657b8e80941Smrg assert(ctx->Driver.NewBufferObject); 1658b8e80941Smrg buf = ctx->Driver.NewBufferObject(ctx, buffers[i]); 1659b8e80941Smrg if (!buf) { 1660b8e80941Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCreateBuffers"); 1661b8e80941Smrg _mesa_HashUnlockMutex(ctx->Shared->BufferObjects); 1662b8e80941Smrg return; 1663b8e80941Smrg } 1664b8e80941Smrg } 1665b8e80941Smrg else 1666b8e80941Smrg buf = &DummyBufferObject; 1667b8e80941Smrg 1668b8e80941Smrg _mesa_HashInsertLocked(ctx->Shared->BufferObjects, buffers[i], buf); 1669b8e80941Smrg } 1670b8e80941Smrg 1671b8e80941Smrg _mesa_HashUnlockMutex(ctx->Shared->BufferObjects); 1672b8e80941Smrg} 1673b8e80941Smrg 1674b8e80941Smrg 1675b8e80941Smrgstatic void 1676b8e80941Smrgcreate_buffers_err(struct gl_context *ctx, GLsizei n, GLuint *buffers, bool dsa) 1677b8e80941Smrg{ 1678b8e80941Smrg const char *func = dsa ? "glCreateBuffers" : "glGenBuffers"; 1679b8e80941Smrg 1680b8e80941Smrg if (MESA_VERBOSE & VERBOSE_API) 1681b8e80941Smrg _mesa_debug(ctx, "%s(%d)\n", func, n); 1682b8e80941Smrg 1683b8e80941Smrg if (n < 0) { 1684b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(n %d < 0)", func, n); 1685b8e80941Smrg return; 1686b8e80941Smrg } 1687b8e80941Smrg 1688b8e80941Smrg create_buffers(ctx, n, buffers, dsa); 1689b8e80941Smrg} 1690b8e80941Smrg 1691b8e80941Smrg/** 1692b8e80941Smrg * Generate a set of unique buffer object IDs and store them in \c buffers. 1693b8e80941Smrg * 1694b8e80941Smrg * \param n Number of IDs to generate. 1695b8e80941Smrg * \param buffers Array of \c n locations to store the IDs. 1696b8e80941Smrg */ 1697b8e80941Smrgvoid GLAPIENTRY 1698b8e80941Smrg_mesa_GenBuffers_no_error(GLsizei n, GLuint *buffers) 1699b8e80941Smrg{ 1700b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 1701b8e80941Smrg create_buffers(ctx, n, buffers, false); 1702b8e80941Smrg} 1703b8e80941Smrg 1704b8e80941Smrg 1705b8e80941Smrgvoid GLAPIENTRY 1706b8e80941Smrg_mesa_GenBuffers(GLsizei n, GLuint *buffers) 1707b8e80941Smrg{ 1708b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 1709b8e80941Smrg create_buffers_err(ctx, n, buffers, false); 1710b8e80941Smrg} 1711b8e80941Smrg 1712b8e80941Smrg/** 1713b8e80941Smrg * Create a set of buffer objects and store their unique IDs in \c buffers. 1714b8e80941Smrg * 1715b8e80941Smrg * \param n Number of IDs to generate. 1716b8e80941Smrg * \param buffers Array of \c n locations to store the IDs. 1717b8e80941Smrg */ 1718b8e80941Smrgvoid GLAPIENTRY 1719b8e80941Smrg_mesa_CreateBuffers_no_error(GLsizei n, GLuint *buffers) 1720b8e80941Smrg{ 1721b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 1722b8e80941Smrg create_buffers(ctx, n, buffers, true); 1723b8e80941Smrg} 1724b8e80941Smrg 1725b8e80941Smrg 1726b8e80941Smrgvoid GLAPIENTRY 1727b8e80941Smrg_mesa_CreateBuffers(GLsizei n, GLuint *buffers) 1728b8e80941Smrg{ 1729b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 1730b8e80941Smrg create_buffers_err(ctx, n, buffers, true); 1731b8e80941Smrg} 1732b8e80941Smrg 1733b8e80941Smrg 1734848b8605Smrg/** 1735848b8605Smrg * Determine if ID is the name of a buffer object. 1736b8e80941Smrg * 1737848b8605Smrg * \param id ID of the potential buffer object. 1738b8e80941Smrg * \return \c GL_TRUE if \c id is the name of a buffer object, 1739848b8605Smrg * \c GL_FALSE otherwise. 1740848b8605Smrg */ 1741848b8605SmrgGLboolean GLAPIENTRY 1742848b8605Smrg_mesa_IsBuffer(GLuint id) 1743848b8605Smrg{ 1744848b8605Smrg struct gl_buffer_object *bufObj; 1745848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1746848b8605Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 1747848b8605Smrg 1748848b8605Smrg bufObj = _mesa_lookup_bufferobj(ctx, id); 1749848b8605Smrg 1750848b8605Smrg return bufObj && bufObj != &DummyBufferObject; 1751848b8605Smrg} 1752848b8605Smrg 1753848b8605Smrg 1754b8e80941Smrgstatic bool 1755b8e80941Smrgvalidate_buffer_storage(struct gl_context *ctx, 1756b8e80941Smrg struct gl_buffer_object *bufObj, GLsizeiptr size, 1757b8e80941Smrg GLbitfield flags, const char *func) 1758848b8605Smrg{ 1759848b8605Smrg if (size <= 0) { 1760b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(size <= 0)", func); 1761b8e80941Smrg return false; 1762848b8605Smrg } 1763848b8605Smrg 1764b8e80941Smrg GLbitfield valid_flags = GL_MAP_READ_BIT | 1765b8e80941Smrg GL_MAP_WRITE_BIT | 1766b8e80941Smrg GL_MAP_PERSISTENT_BIT | 1767b8e80941Smrg GL_MAP_COHERENT_BIT | 1768b8e80941Smrg GL_DYNAMIC_STORAGE_BIT | 1769b8e80941Smrg GL_CLIENT_STORAGE_BIT; 1770b8e80941Smrg 1771b8e80941Smrg if (ctx->Extensions.ARB_sparse_buffer) 1772b8e80941Smrg valid_flags |= GL_SPARSE_STORAGE_BIT_ARB; 1773b8e80941Smrg 1774b8e80941Smrg if (flags & ~valid_flags) { 1775b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid flag bits set)", func); 1776b8e80941Smrg return false; 1777b8e80941Smrg } 1778b8e80941Smrg 1779b8e80941Smrg /* The Errors section of the GL_ARB_sparse_buffer spec says: 1780b8e80941Smrg * 1781b8e80941Smrg * "INVALID_VALUE is generated by BufferStorage if <flags> contains 1782b8e80941Smrg * SPARSE_STORAGE_BIT_ARB and <flags> also contains any combination of 1783b8e80941Smrg * MAP_READ_BIT or MAP_WRITE_BIT." 1784b8e80941Smrg */ 1785b8e80941Smrg if (flags & GL_SPARSE_STORAGE_BIT_ARB && 1786b8e80941Smrg flags & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) { 1787b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(SPARSE_STORAGE and READ/WRITE)", func); 1788b8e80941Smrg return false; 1789848b8605Smrg } 1790848b8605Smrg 1791848b8605Smrg if (flags & GL_MAP_PERSISTENT_BIT && 1792848b8605Smrg !(flags & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT))) { 1793b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, 1794b8e80941Smrg "%s(PERSISTENT and flags!=READ/WRITE)", func); 1795b8e80941Smrg return false; 1796848b8605Smrg } 1797848b8605Smrg 1798848b8605Smrg if (flags & GL_MAP_COHERENT_BIT && !(flags & GL_MAP_PERSISTENT_BIT)) { 1799b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, 1800b8e80941Smrg "%s(COHERENT and flags!=PERSISTENT)", func); 1801b8e80941Smrg return false; 1802848b8605Smrg } 1803848b8605Smrg 1804b8e80941Smrg if (bufObj->Immutable || bufObj->HandleAllocated) { 1805b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(immutable)", func); 1806b8e80941Smrg return false; 1807848b8605Smrg } 1808848b8605Smrg 1809b8e80941Smrg return true; 1810b8e80941Smrg} 1811b8e80941Smrg 1812b8e80941Smrg 1813b8e80941Smrgstatic void 1814b8e80941Smrgbuffer_storage(struct gl_context *ctx, struct gl_buffer_object *bufObj, 1815b8e80941Smrg struct gl_memory_object *memObj, GLenum target, 1816b8e80941Smrg GLsizeiptr size, const GLvoid *data, GLbitfield flags, 1817b8e80941Smrg GLuint64 offset, const char *func) 1818b8e80941Smrg{ 1819b8e80941Smrg GLboolean res; 1820b8e80941Smrg 1821848b8605Smrg /* Unmap the existing buffer. We'll replace it now. Not an error. */ 1822848b8605Smrg _mesa_buffer_unmap_all_mappings(ctx, bufObj); 1823848b8605Smrg 1824b8e80941Smrg FLUSH_VERTICES(ctx, 0); 1825848b8605Smrg 1826848b8605Smrg bufObj->Written = GL_TRUE; 1827848b8605Smrg bufObj->Immutable = GL_TRUE; 1828b8e80941Smrg bufObj->MinMaxCacheDirty = true; 1829b8e80941Smrg 1830b8e80941Smrg if (memObj) { 1831b8e80941Smrg assert(ctx->Driver.BufferDataMem); 1832b8e80941Smrg res = ctx->Driver.BufferDataMem(ctx, target, size, memObj, offset, 1833b8e80941Smrg GL_DYNAMIC_DRAW, bufObj); 1834b8e80941Smrg } 1835b8e80941Smrg else { 1836b8e80941Smrg assert(ctx->Driver.BufferData); 1837b8e80941Smrg res = ctx->Driver.BufferData(ctx, target, size, data, GL_DYNAMIC_DRAW, 1838b8e80941Smrg flags, bufObj); 1839b8e80941Smrg } 1840848b8605Smrg 1841b8e80941Smrg if (!res) { 1842b8e80941Smrg if (target == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD) { 1843b8e80941Smrg /* Even though the interaction between AMD_pinned_memory and 1844b8e80941Smrg * glBufferStorage is not described in the spec, Graham Sellers 1845b8e80941Smrg * said that it should behave the same as glBufferData. 1846b8e80941Smrg */ 1847b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func); 1848b8e80941Smrg } 1849b8e80941Smrg else { 1850b8e80941Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); 1851b8e80941Smrg } 1852848b8605Smrg } 1853848b8605Smrg} 1854848b8605Smrg 1855848b8605Smrg 1856b8e80941Smrgstatic ALWAYS_INLINE void 1857b8e80941Smrginlined_buffer_storage(GLenum target, GLuint buffer, GLsizeiptr size, 1858b8e80941Smrg const GLvoid *data, GLbitfield flags, 1859b8e80941Smrg GLuint memory, GLuint64 offset, 1860b8e80941Smrg bool dsa, bool mem, bool no_error, const char *func) 1861848b8605Smrg{ 1862848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1863848b8605Smrg struct gl_buffer_object *bufObj; 1864b8e80941Smrg struct gl_memory_object *memObj = NULL; 1865848b8605Smrg 1866b8e80941Smrg if (mem) { 1867b8e80941Smrg if (!no_error) { 1868b8e80941Smrg if (!ctx->Extensions.EXT_memory_object) { 1869b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func); 1870b8e80941Smrg return; 1871b8e80941Smrg } 1872848b8605Smrg 1873b8e80941Smrg /* From the EXT_external_objects spec: 1874b8e80941Smrg * 1875b8e80941Smrg * "An INVALID_VALUE error is generated by BufferStorageMemEXT and 1876b8e80941Smrg * NamedBufferStorageMemEXT if <memory> is 0, or ..." 1877b8e80941Smrg */ 1878b8e80941Smrg if (memory == 0) { 1879b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(memory == 0)", func); 1880b8e80941Smrg } 1881b8e80941Smrg } 1882b8e80941Smrg 1883b8e80941Smrg memObj = _mesa_lookup_memory_object(ctx, memory); 1884b8e80941Smrg if (!memObj) 1885b8e80941Smrg return; 1886b8e80941Smrg 1887b8e80941Smrg /* From the EXT_external_objects spec: 1888b8e80941Smrg * 1889b8e80941Smrg * "An INVALID_OPERATION error is generated if <memory> names a 1890b8e80941Smrg * valid memory object which has no associated memory." 1891b8e80941Smrg */ 1892b8e80941Smrg if (!no_error && !memObj->Immutable) { 1893b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(no associated memory)", 1894b8e80941Smrg func); 1895b8e80941Smrg return; 1896b8e80941Smrg } 1897848b8605Smrg } 1898848b8605Smrg 1899b8e80941Smrg if (dsa) { 1900b8e80941Smrg if (no_error) { 1901b8e80941Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 1902b8e80941Smrg } else { 1903b8e80941Smrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, func); 1904b8e80941Smrg if (!bufObj) 1905b8e80941Smrg return; 1906b8e80941Smrg } 1907b8e80941Smrg } else { 1908b8e80941Smrg if (no_error) { 1909b8e80941Smrg struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target); 1910b8e80941Smrg bufObj = *bufObjPtr; 1911b8e80941Smrg } else { 1912b8e80941Smrg bufObj = get_buffer(ctx, func, target, GL_INVALID_OPERATION); 1913b8e80941Smrg if (!bufObj) 1914b8e80941Smrg return; 1915b8e80941Smrg } 1916b8e80941Smrg } 1917848b8605Smrg 1918b8e80941Smrg if (no_error || validate_buffer_storage(ctx, bufObj, size, flags, func)) 1919b8e80941Smrg buffer_storage(ctx, bufObj, memObj, target, size, data, flags, offset, func); 1920b8e80941Smrg} 1921848b8605Smrg 1922848b8605Smrg 1923b8e80941Smrgvoid GLAPIENTRY 1924b8e80941Smrg_mesa_BufferStorage_no_error(GLenum target, GLsizeiptr size, 1925b8e80941Smrg const GLvoid *data, GLbitfield flags) 1926b8e80941Smrg{ 1927b8e80941Smrg inlined_buffer_storage(target, 0, size, data, flags, GL_NONE, 0, 1928b8e80941Smrg false, false, true, "glBufferStorage"); 1929b8e80941Smrg} 1930848b8605Smrg 1931b8e80941Smrg 1932b8e80941Smrgvoid GLAPIENTRY 1933b8e80941Smrg_mesa_BufferStorage(GLenum target, GLsizeiptr size, const GLvoid *data, 1934b8e80941Smrg GLbitfield flags) 1935b8e80941Smrg{ 1936b8e80941Smrg inlined_buffer_storage(target, 0, size, data, flags, GL_NONE, 0, 1937b8e80941Smrg false, false, false, "glBufferStorage"); 1938b8e80941Smrg} 1939b8e80941Smrg 1940b8e80941Smrg 1941b8e80941Smrgvoid GLAPIENTRY 1942b8e80941Smrg_mesa_BufferStorageMemEXT(GLenum target, GLsizeiptr size, 1943b8e80941Smrg GLuint memory, GLuint64 offset) 1944b8e80941Smrg{ 1945b8e80941Smrg inlined_buffer_storage(target, 0, size, NULL, 0, memory, offset, 1946b8e80941Smrg false, true, false, "glBufferStorageMemEXT"); 1947b8e80941Smrg} 1948b8e80941Smrg 1949b8e80941Smrg 1950b8e80941Smrgvoid GLAPIENTRY 1951b8e80941Smrg_mesa_BufferStorageMemEXT_no_error(GLenum target, GLsizeiptr size, 1952b8e80941Smrg GLuint memory, GLuint64 offset) 1953b8e80941Smrg{ 1954b8e80941Smrg inlined_buffer_storage(target, 0, size, NULL, 0, memory, offset, 1955b8e80941Smrg false, true, true, "glBufferStorageMemEXT"); 1956b8e80941Smrg} 1957b8e80941Smrg 1958b8e80941Smrg 1959b8e80941Smrgvoid GLAPIENTRY 1960b8e80941Smrg_mesa_NamedBufferStorage_no_error(GLuint buffer, GLsizeiptr size, 1961b8e80941Smrg const GLvoid *data, GLbitfield flags) 1962b8e80941Smrg{ 1963b8e80941Smrg /* In direct state access, buffer objects have an unspecified target 1964b8e80941Smrg * since they are not required to be bound. 1965b8e80941Smrg */ 1966b8e80941Smrg inlined_buffer_storage(GL_NONE, buffer, size, data, flags, GL_NONE, 0, 1967b8e80941Smrg true, false, true, "glNamedBufferStorage"); 1968b8e80941Smrg} 1969b8e80941Smrg 1970b8e80941Smrg 1971b8e80941Smrgvoid GLAPIENTRY 1972b8e80941Smrg_mesa_NamedBufferStorage(GLuint buffer, GLsizeiptr size, const GLvoid *data, 1973b8e80941Smrg GLbitfield flags) 1974b8e80941Smrg{ 1975b8e80941Smrg /* In direct state access, buffer objects have an unspecified target 1976b8e80941Smrg * since they are not required to be bound. 1977b8e80941Smrg */ 1978b8e80941Smrg inlined_buffer_storage(GL_NONE, buffer, size, data, flags, GL_NONE, 0, 1979b8e80941Smrg true, false, false, "glNamedBufferStorage"); 1980b8e80941Smrg} 1981b8e80941Smrg 1982b8e80941Smrgvoid GLAPIENTRY 1983b8e80941Smrg_mesa_NamedBufferStorageMemEXT(GLuint buffer, GLsizeiptr size, 1984b8e80941Smrg GLuint memory, GLuint64 offset) 1985b8e80941Smrg{ 1986b8e80941Smrg inlined_buffer_storage(GL_NONE, buffer, size, GL_NONE, 0, memory, offset, 1987b8e80941Smrg true, true, false, "glNamedBufferStorageMemEXT"); 1988b8e80941Smrg} 1989b8e80941Smrg 1990b8e80941Smrg 1991b8e80941Smrgvoid GLAPIENTRY 1992b8e80941Smrg_mesa_NamedBufferStorageMemEXT_no_error(GLuint buffer, GLsizeiptr size, 1993b8e80941Smrg GLuint memory, GLuint64 offset) 1994b8e80941Smrg{ 1995b8e80941Smrg inlined_buffer_storage(GL_NONE, buffer, size, GL_NONE, 0, memory, offset, 1996b8e80941Smrg true, true, true, "glNamedBufferStorageMemEXT"); 1997b8e80941Smrg} 1998b8e80941Smrg 1999b8e80941Smrg 2000b8e80941Smrgstatic ALWAYS_INLINE void 2001b8e80941Smrgbuffer_data(struct gl_context *ctx, struct gl_buffer_object *bufObj, 2002b8e80941Smrg GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage, 2003b8e80941Smrg const char *func, bool no_error) 2004b8e80941Smrg{ 2005b8e80941Smrg bool valid_usage; 2006b8e80941Smrg 2007b8e80941Smrg if (MESA_VERBOSE & VERBOSE_API) { 2008b8e80941Smrg _mesa_debug(ctx, "%s(%s, %ld, %p, %s)\n", 2009b8e80941Smrg func, 2010b8e80941Smrg _mesa_enum_to_string(target), 2011b8e80941Smrg (long int) size, data, 2012b8e80941Smrg _mesa_enum_to_string(usage)); 2013848b8605Smrg } 2014848b8605Smrg 2015b8e80941Smrg if (!no_error) { 2016b8e80941Smrg if (size < 0) { 2017b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", func); 2018b8e80941Smrg return; 2019b8e80941Smrg } 2020848b8605Smrg 2021b8e80941Smrg switch (usage) { 2022b8e80941Smrg case GL_STREAM_DRAW_ARB: 2023b8e80941Smrg valid_usage = (ctx->API != API_OPENGLES); 2024b8e80941Smrg break; 2025b8e80941Smrg case GL_STATIC_DRAW_ARB: 2026b8e80941Smrg case GL_DYNAMIC_DRAW_ARB: 2027b8e80941Smrg valid_usage = true; 2028b8e80941Smrg break; 2029b8e80941Smrg case GL_STREAM_READ_ARB: 2030b8e80941Smrg case GL_STREAM_COPY_ARB: 2031b8e80941Smrg case GL_STATIC_READ_ARB: 2032b8e80941Smrg case GL_STATIC_COPY_ARB: 2033b8e80941Smrg case GL_DYNAMIC_READ_ARB: 2034b8e80941Smrg case GL_DYNAMIC_COPY_ARB: 2035b8e80941Smrg valid_usage = _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx); 2036b8e80941Smrg break; 2037b8e80941Smrg default: 2038b8e80941Smrg valid_usage = false; 2039b8e80941Smrg break; 2040b8e80941Smrg } 2041b8e80941Smrg 2042b8e80941Smrg if (!valid_usage) { 2043b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid usage: %s)", func, 2044b8e80941Smrg _mesa_enum_to_string(usage)); 2045b8e80941Smrg return; 2046b8e80941Smrg } 2047b8e80941Smrg 2048b8e80941Smrg if (bufObj->Immutable || bufObj->HandleAllocated) { 2049b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(immutable)", func); 2050b8e80941Smrg return; 2051b8e80941Smrg } 2052848b8605Smrg } 2053848b8605Smrg 2054848b8605Smrg /* Unmap the existing buffer. We'll replace it now. Not an error. */ 2055848b8605Smrg _mesa_buffer_unmap_all_mappings(ctx, bufObj); 2056848b8605Smrg 2057b8e80941Smrg FLUSH_VERTICES(ctx, 0); 2058848b8605Smrg 2059848b8605Smrg bufObj->Written = GL_TRUE; 2060b8e80941Smrg bufObj->MinMaxCacheDirty = true; 2061848b8605Smrg 2062848b8605Smrg#ifdef VBO_DEBUG 2063848b8605Smrg printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n", 2064848b8605Smrg bufObj->Name, size, data, usage); 2065848b8605Smrg#endif 2066848b8605Smrg 2067848b8605Smrg#ifdef BOUNDS_CHECK 2068848b8605Smrg size += 100; 2069848b8605Smrg#endif 2070848b8605Smrg 2071b8e80941Smrg assert(ctx->Driver.BufferData); 2072848b8605Smrg if (!ctx->Driver.BufferData(ctx, target, size, data, usage, 2073848b8605Smrg GL_MAP_READ_BIT | 2074848b8605Smrg GL_MAP_WRITE_BIT | 2075848b8605Smrg GL_DYNAMIC_STORAGE_BIT, 2076848b8605Smrg bufObj)) { 2077b8e80941Smrg if (target == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD) { 2078b8e80941Smrg if (!no_error) { 2079b8e80941Smrg /* From GL_AMD_pinned_memory: 2080b8e80941Smrg * 2081b8e80941Smrg * INVALID_OPERATION is generated by BufferData if <target> is 2082b8e80941Smrg * EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, and the store cannot be 2083b8e80941Smrg * mapped to the GPU address space. 2084b8e80941Smrg */ 2085b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func); 2086b8e80941Smrg } 2087b8e80941Smrg } else { 2088b8e80941Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); 2089b8e80941Smrg } 2090b8e80941Smrg } 2091b8e80941Smrg} 2092b8e80941Smrg 2093b8e80941Smrgstatic void 2094b8e80941Smrgbuffer_data_error(struct gl_context *ctx, struct gl_buffer_object *bufObj, 2095b8e80941Smrg GLenum target, GLsizeiptr size, const GLvoid *data, 2096b8e80941Smrg GLenum usage, const char *func) 2097b8e80941Smrg{ 2098b8e80941Smrg buffer_data(ctx, bufObj, target, size, data, usage, func, false); 2099b8e80941Smrg} 2100b8e80941Smrg 2101b8e80941Smrgstatic void 2102b8e80941Smrgbuffer_data_no_error(struct gl_context *ctx, struct gl_buffer_object *bufObj, 2103b8e80941Smrg GLenum target, GLsizeiptr size, const GLvoid *data, 2104b8e80941Smrg GLenum usage, const char *func) 2105b8e80941Smrg{ 2106b8e80941Smrg buffer_data(ctx, bufObj, target, size, data, usage, func, true); 2107b8e80941Smrg} 2108b8e80941Smrg 2109b8e80941Smrgvoid 2110b8e80941Smrg_mesa_buffer_data(struct gl_context *ctx, struct gl_buffer_object *bufObj, 2111b8e80941Smrg GLenum target, GLsizeiptr size, const GLvoid *data, 2112b8e80941Smrg GLenum usage, const char *func) 2113b8e80941Smrg{ 2114b8e80941Smrg buffer_data_error(ctx, bufObj, target, size, data, usage, func); 2115b8e80941Smrg} 2116b8e80941Smrg 2117b8e80941Smrgvoid GLAPIENTRY 2118b8e80941Smrg_mesa_BufferData_no_error(GLenum target, GLsizeiptr size, const GLvoid *data, 2119b8e80941Smrg GLenum usage) 2120b8e80941Smrg{ 2121b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 2122b8e80941Smrg 2123b8e80941Smrg struct gl_buffer_object **bufObj = get_buffer_target(ctx, target); 2124b8e80941Smrg buffer_data_no_error(ctx, *bufObj, target, size, data, usage, 2125b8e80941Smrg "glBufferData"); 2126b8e80941Smrg} 2127b8e80941Smrg 2128b8e80941Smrgvoid GLAPIENTRY 2129b8e80941Smrg_mesa_BufferData(GLenum target, GLsizeiptr size, 2130b8e80941Smrg const GLvoid *data, GLenum usage) 2131b8e80941Smrg{ 2132b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 2133b8e80941Smrg struct gl_buffer_object *bufObj; 2134b8e80941Smrg 2135b8e80941Smrg bufObj = get_buffer(ctx, "glBufferData", target, GL_INVALID_OPERATION); 2136b8e80941Smrg if (!bufObj) 2137b8e80941Smrg return; 2138b8e80941Smrg 2139b8e80941Smrg _mesa_buffer_data(ctx, bufObj, target, size, data, usage, 2140b8e80941Smrg "glBufferData"); 2141b8e80941Smrg} 2142b8e80941Smrg 2143b8e80941Smrgvoid GLAPIENTRY 2144b8e80941Smrg_mesa_NamedBufferData_no_error(GLuint buffer, GLsizeiptr size, 2145b8e80941Smrg const GLvoid *data, GLenum usage) 2146b8e80941Smrg{ 2147b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 2148b8e80941Smrg 2149b8e80941Smrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 2150b8e80941Smrg buffer_data_no_error(ctx, bufObj, GL_NONE, size, data, usage, 2151b8e80941Smrg "glNamedBufferData"); 2152b8e80941Smrg} 2153b8e80941Smrg 2154b8e80941Smrgvoid GLAPIENTRY 2155b8e80941Smrg_mesa_NamedBufferData(GLuint buffer, GLsizeiptr size, const GLvoid *data, 2156b8e80941Smrg GLenum usage) 2157b8e80941Smrg{ 2158b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 2159b8e80941Smrg struct gl_buffer_object *bufObj; 2160b8e80941Smrg 2161b8e80941Smrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glNamedBufferData"); 2162b8e80941Smrg if (!bufObj) 2163b8e80941Smrg return; 2164b8e80941Smrg 2165b8e80941Smrg /* In direct state access, buffer objects have an unspecified target since 2166b8e80941Smrg * they are not required to be bound. 2167b8e80941Smrg */ 2168b8e80941Smrg _mesa_buffer_data(ctx, bufObj, GL_NONE, size, data, usage, 2169b8e80941Smrg "glNamedBufferData"); 2170b8e80941Smrg} 2171b8e80941Smrg 2172b8e80941Smrg 2173b8e80941Smrgstatic bool 2174b8e80941Smrgvalidate_buffer_sub_data(struct gl_context *ctx, 2175b8e80941Smrg struct gl_buffer_object *bufObj, 2176b8e80941Smrg GLintptr offset, GLsizeiptr size, 2177b8e80941Smrg const char *func) 2178b8e80941Smrg{ 2179b8e80941Smrg if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size, 2180b8e80941Smrg true, func)) { 2181b8e80941Smrg /* error already recorded */ 2182b8e80941Smrg return false; 2183b8e80941Smrg } 2184b8e80941Smrg 2185b8e80941Smrg if (bufObj->Immutable && 2186b8e80941Smrg !(bufObj->StorageFlags & GL_DYNAMIC_STORAGE_BIT)) { 2187b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func); 2188b8e80941Smrg return false; 2189b8e80941Smrg } 2190b8e80941Smrg 2191b8e80941Smrg if ((bufObj->Usage == GL_STATIC_DRAW || 2192b8e80941Smrg bufObj->Usage == GL_STATIC_COPY) && 2193b8e80941Smrg bufObj->NumSubDataCalls >= BUFFER_WARNING_CALL_COUNT - 1) { 2194b8e80941Smrg /* If the application declared the buffer as static draw/copy or stream 2195b8e80941Smrg * draw, it should not be frequently modified with glBufferSubData. 2196b8e80941Smrg */ 2197b8e80941Smrg BUFFER_USAGE_WARNING(ctx, 2198b8e80941Smrg "using %s(buffer %u, offset %u, size %u) to " 2199b8e80941Smrg "update a %s buffer", 2200b8e80941Smrg func, bufObj->Name, offset, size, 2201b8e80941Smrg _mesa_enum_to_string(bufObj->Usage)); 2202b8e80941Smrg } 2203b8e80941Smrg 2204b8e80941Smrg return true; 2205b8e80941Smrg} 2206b8e80941Smrg 2207b8e80941Smrg 2208b8e80941Smrg/** 2209b8e80941Smrg * Implementation for glBufferSubData and glNamedBufferSubData. 2210b8e80941Smrg * 2211b8e80941Smrg * \param ctx GL context. 2212b8e80941Smrg * \param bufObj The buffer object. 2213b8e80941Smrg * \param offset Offset of the first byte of the subdata range. 2214b8e80941Smrg * \param size Size, in bytes, of the subdata range. 2215b8e80941Smrg * \param data The data store. 2216b8e80941Smrg * \param func Name of calling function for recording errors. 2217b8e80941Smrg * 2218b8e80941Smrg */ 2219b8e80941Smrgvoid 2220b8e80941Smrg_mesa_buffer_sub_data(struct gl_context *ctx, struct gl_buffer_object *bufObj, 2221b8e80941Smrg GLintptr offset, GLsizeiptr size, const GLvoid *data) 2222b8e80941Smrg{ 2223b8e80941Smrg if (size == 0) 2224b8e80941Smrg return; 2225b8e80941Smrg 2226b8e80941Smrg bufObj->NumSubDataCalls++; 2227b8e80941Smrg bufObj->Written = GL_TRUE; 2228b8e80941Smrg bufObj->MinMaxCacheDirty = true; 2229b8e80941Smrg 2230b8e80941Smrg assert(ctx->Driver.BufferSubData); 2231b8e80941Smrg ctx->Driver.BufferSubData(ctx, offset, size, data, bufObj); 2232b8e80941Smrg} 2233b8e80941Smrg 2234b8e80941Smrg 2235b8e80941Smrgstatic ALWAYS_INLINE void 2236b8e80941Smrgbuffer_sub_data(GLenum target, GLuint buffer, GLintptr offset, 2237b8e80941Smrg GLsizeiptr size, const GLvoid *data, 2238b8e80941Smrg bool dsa, bool no_error, const char *func) 2239b8e80941Smrg{ 2240b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 2241b8e80941Smrg struct gl_buffer_object *bufObj; 2242b8e80941Smrg 2243b8e80941Smrg if (dsa) { 2244b8e80941Smrg if (no_error) { 2245b8e80941Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 2246b8e80941Smrg } else { 2247b8e80941Smrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, func); 2248b8e80941Smrg if (!bufObj) 2249b8e80941Smrg return; 2250b8e80941Smrg } 2251b8e80941Smrg } else { 2252b8e80941Smrg if (no_error) { 2253b8e80941Smrg struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target); 2254b8e80941Smrg bufObj = *bufObjPtr; 2255b8e80941Smrg } else { 2256b8e80941Smrg bufObj = get_buffer(ctx, func, target, GL_INVALID_OPERATION); 2257b8e80941Smrg if (!bufObj) 2258b8e80941Smrg return; 2259b8e80941Smrg } 2260848b8605Smrg } 2261b8e80941Smrg 2262b8e80941Smrg if (no_error || validate_buffer_sub_data(ctx, bufObj, offset, size, func)) 2263b8e80941Smrg _mesa_buffer_sub_data(ctx, bufObj, offset, size, data); 2264b8e80941Smrg} 2265b8e80941Smrg 2266b8e80941Smrg 2267b8e80941Smrgvoid GLAPIENTRY 2268b8e80941Smrg_mesa_BufferSubData_no_error(GLenum target, GLintptr offset, 2269b8e80941Smrg GLsizeiptr size, const GLvoid *data) 2270b8e80941Smrg{ 2271b8e80941Smrg buffer_sub_data(target, 0, offset, size, data, false, true, 2272b8e80941Smrg "glBufferSubData"); 2273b8e80941Smrg} 2274b8e80941Smrg 2275b8e80941Smrg 2276b8e80941Smrgvoid GLAPIENTRY 2277b8e80941Smrg_mesa_BufferSubData(GLenum target, GLintptr offset, 2278b8e80941Smrg GLsizeiptr size, const GLvoid *data) 2279b8e80941Smrg{ 2280b8e80941Smrg buffer_sub_data(target, 0, offset, size, data, false, false, 2281b8e80941Smrg "glBufferSubData"); 2282b8e80941Smrg} 2283b8e80941Smrg 2284b8e80941Smrgvoid GLAPIENTRY 2285b8e80941Smrg_mesa_NamedBufferSubData_no_error(GLuint buffer, GLintptr offset, 2286b8e80941Smrg GLsizeiptr size, const GLvoid *data) 2287b8e80941Smrg{ 2288b8e80941Smrg buffer_sub_data(0, buffer, offset, size, data, true, true, 2289b8e80941Smrg "glNamedBufferSubData"); 2290b8e80941Smrg} 2291b8e80941Smrg 2292b8e80941Smrgvoid GLAPIENTRY 2293b8e80941Smrg_mesa_NamedBufferSubData(GLuint buffer, GLintptr offset, 2294b8e80941Smrg GLsizeiptr size, const GLvoid *data) 2295b8e80941Smrg{ 2296b8e80941Smrg buffer_sub_data(0, buffer, offset, size, data, true, false, 2297b8e80941Smrg "glNamedBufferSubData"); 2298848b8605Smrg} 2299848b8605Smrg 2300848b8605Smrg 2301848b8605Smrgvoid GLAPIENTRY 2302b8e80941Smrg_mesa_GetBufferSubData(GLenum target, GLintptr offset, 2303b8e80941Smrg GLsizeiptr size, GLvoid *data) 2304848b8605Smrg{ 2305848b8605Smrg GET_CURRENT_CONTEXT(ctx); 2306848b8605Smrg struct gl_buffer_object *bufObj; 2307848b8605Smrg 2308b8e80941Smrg bufObj = get_buffer(ctx, "glGetBufferSubData", target, 2309b8e80941Smrg GL_INVALID_OPERATION); 2310b8e80941Smrg if (!bufObj) 2311848b8605Smrg return; 2312848b8605Smrg 2313b8e80941Smrg if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size, false, 2314b8e80941Smrg "glGetBufferSubData")) { 2315848b8605Smrg return; 2316848b8605Smrg } 2317848b8605Smrg 2318b8e80941Smrg assert(ctx->Driver.GetBufferSubData); 2319b8e80941Smrg ctx->Driver.GetBufferSubData(ctx, offset, size, data, bufObj); 2320848b8605Smrg} 2321848b8605Smrg 2322848b8605Smrgvoid GLAPIENTRY 2323b8e80941Smrg_mesa_GetNamedBufferSubData(GLuint buffer, GLintptr offset, 2324b8e80941Smrg GLsizeiptr size, GLvoid *data) 2325848b8605Smrg{ 2326848b8605Smrg GET_CURRENT_CONTEXT(ctx); 2327848b8605Smrg struct gl_buffer_object *bufObj; 2328848b8605Smrg 2329b8e80941Smrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, 2330b8e80941Smrg "glGetNamedBufferSubData"); 2331b8e80941Smrg if (!bufObj) 2332b8e80941Smrg return; 2333b8e80941Smrg 2334b8e80941Smrg if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size, false, 2335b8e80941Smrg "glGetNamedBufferSubData")) { 2336848b8605Smrg return; 2337848b8605Smrg } 2338848b8605Smrg 2339b8e80941Smrg assert(ctx->Driver.GetBufferSubData); 2340b8e80941Smrg ctx->Driver.GetBufferSubData(ctx, offset, size, data, bufObj); 2341848b8605Smrg} 2342848b8605Smrg 2343848b8605Smrg 2344b8e80941Smrg/** 2345b8e80941Smrg * \param subdata true if caller is *SubData, false if *Data 2346b8e80941Smrg */ 2347b8e80941Smrgstatic ALWAYS_INLINE void 2348b8e80941Smrgclear_buffer_sub_data(struct gl_context *ctx, struct gl_buffer_object *bufObj, 2349b8e80941Smrg GLenum internalformat, GLintptr offset, GLsizeiptr size, 2350b8e80941Smrg GLenum format, GLenum type, const GLvoid *data, 2351b8e80941Smrg const char *func, bool subdata, bool no_error) 2352848b8605Smrg{ 2353848b8605Smrg mesa_format mesaFormat; 2354848b8605Smrg GLubyte clearValue[MAX_PIXEL_BYTES]; 2355848b8605Smrg GLsizeiptr clearValueSize; 2356848b8605Smrg 2357b8e80941Smrg /* This checks for disallowed mappings. */ 2358b8e80941Smrg if (!no_error && !buffer_object_subdata_range_good(ctx, bufObj, offset, size, 2359b8e80941Smrg subdata, func)) { 2360848b8605Smrg return; 2361848b8605Smrg } 2362848b8605Smrg 2363b8e80941Smrg if (no_error) { 2364b8e80941Smrg mesaFormat = _mesa_get_texbuffer_format(ctx, internalformat); 2365b8e80941Smrg } else { 2366b8e80941Smrg mesaFormat = validate_clear_buffer_format(ctx, internalformat, 2367b8e80941Smrg format, type, func); 2368848b8605Smrg } 2369848b8605Smrg 2370b8e80941Smrg if (mesaFormat == MESA_FORMAT_NONE) 2371848b8605Smrg return; 2372848b8605Smrg 2373848b8605Smrg clearValueSize = _mesa_get_format_bytes(mesaFormat); 2374b8e80941Smrg if (!no_error && 2375b8e80941Smrg (offset % clearValueSize != 0 || size % clearValueSize != 0)) { 2376848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2377b8e80941Smrg "%s(offset or size is not a multiple of " 2378b8e80941Smrg "internalformat size)", func); 2379848b8605Smrg return; 2380848b8605Smrg } 2381848b8605Smrg 2382b8e80941Smrg /* Bail early. Negative size has already been checked. */ 2383b8e80941Smrg if (size == 0) 2384b8e80941Smrg return; 2385b8e80941Smrg 2386b8e80941Smrg bufObj->MinMaxCacheDirty = true; 2387b8e80941Smrg 2388848b8605Smrg if (data == NULL) { 2389848b8605Smrg /* clear to zeros, per the spec */ 2390b8e80941Smrg ctx->Driver.ClearBufferSubData(ctx, offset, size, 2391848b8605Smrg NULL, clearValueSize, bufObj); 2392848b8605Smrg return; 2393848b8605Smrg } 2394848b8605Smrg 2395848b8605Smrg if (!convert_clear_buffer_data(ctx, mesaFormat, clearValue, 2396b8e80941Smrg format, type, data, func)) { 2397848b8605Smrg return; 2398848b8605Smrg } 2399848b8605Smrg 2400b8e80941Smrg ctx->Driver.ClearBufferSubData(ctx, offset, size, 2401848b8605Smrg clearValue, clearValueSize, bufObj); 2402848b8605Smrg} 2403848b8605Smrg 2404b8e80941Smrgstatic void 2405b8e80941Smrgclear_buffer_sub_data_error(struct gl_context *ctx, 2406b8e80941Smrg struct gl_buffer_object *bufObj, 2407b8e80941Smrg GLenum internalformat, GLintptr offset, 2408b8e80941Smrg GLsizeiptr size, GLenum format, GLenum type, 2409b8e80941Smrg const GLvoid *data, const char *func, bool subdata) 2410b8e80941Smrg{ 2411b8e80941Smrg clear_buffer_sub_data(ctx, bufObj, internalformat, offset, size, format, 2412b8e80941Smrg type, data, func, subdata, false); 2413b8e80941Smrg} 2414b8e80941Smrg 2415b8e80941Smrg 2416b8e80941Smrgstatic void 2417b8e80941Smrgclear_buffer_sub_data_no_error(struct gl_context *ctx, 2418b8e80941Smrg struct gl_buffer_object *bufObj, 2419b8e80941Smrg GLenum internalformat, GLintptr offset, 2420b8e80941Smrg GLsizeiptr size, GLenum format, GLenum type, 2421b8e80941Smrg const GLvoid *data, const char *func, 2422b8e80941Smrg bool subdata) 2423b8e80941Smrg{ 2424b8e80941Smrg clear_buffer_sub_data(ctx, bufObj, internalformat, offset, size, format, 2425b8e80941Smrg type, data, func, subdata, true); 2426b8e80941Smrg} 2427b8e80941Smrg 2428848b8605Smrg 2429848b8605Smrgvoid GLAPIENTRY 2430b8e80941Smrg_mesa_ClearBufferData_no_error(GLenum target, GLenum internalformat, 2431b8e80941Smrg GLenum format, GLenum type, const GLvoid *data) 2432848b8605Smrg{ 2433848b8605Smrg GET_CURRENT_CONTEXT(ctx); 2434848b8605Smrg 2435b8e80941Smrg struct gl_buffer_object **bufObj = get_buffer_target(ctx, target); 2436b8e80941Smrg clear_buffer_sub_data_no_error(ctx, *bufObj, internalformat, 0, 2437b8e80941Smrg (*bufObj)->Size, format, type, data, 2438b8e80941Smrg "glClearBufferData", false); 2439b8e80941Smrg} 2440848b8605Smrg 2441848b8605Smrg 2442b8e80941Smrgvoid GLAPIENTRY 2443b8e80941Smrg_mesa_ClearBufferData(GLenum target, GLenum internalformat, GLenum format, 2444b8e80941Smrg GLenum type, const GLvoid *data) 2445b8e80941Smrg{ 2446b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 2447b8e80941Smrg struct gl_buffer_object *bufObj; 2448848b8605Smrg 2449b8e80941Smrg bufObj = get_buffer(ctx, "glClearBufferData", target, GL_INVALID_VALUE); 2450b8e80941Smrg if (!bufObj) 2451848b8605Smrg return; 2452848b8605Smrg 2453b8e80941Smrg clear_buffer_sub_data_error(ctx, bufObj, internalformat, 0, bufObj->Size, 2454b8e80941Smrg format, type, data, "glClearBufferData", false); 2455848b8605Smrg} 2456848b8605Smrg 2457848b8605Smrg 2458b8e80941Smrgvoid GLAPIENTRY 2459b8e80941Smrg_mesa_ClearNamedBufferData_no_error(GLuint buffer, GLenum internalformat, 2460b8e80941Smrg GLenum format, GLenum type, 2461b8e80941Smrg const GLvoid *data) 2462848b8605Smrg{ 2463848b8605Smrg GET_CURRENT_CONTEXT(ctx); 2464848b8605Smrg 2465b8e80941Smrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 2466b8e80941Smrg clear_buffer_sub_data_no_error(ctx, bufObj, internalformat, 0, bufObj->Size, 2467b8e80941Smrg format, type, data, "glClearNamedBufferData", 2468b8e80941Smrg false); 2469b8e80941Smrg} 2470848b8605Smrg 2471848b8605Smrg 2472b8e80941Smrgvoid GLAPIENTRY 2473b8e80941Smrg_mesa_ClearNamedBufferData(GLuint buffer, GLenum internalformat, 2474b8e80941Smrg GLenum format, GLenum type, const GLvoid *data) 2475b8e80941Smrg{ 2476b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 2477b8e80941Smrg struct gl_buffer_object *bufObj; 2478848b8605Smrg 2479b8e80941Smrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glClearNamedBufferData"); 2480848b8605Smrg if (!bufObj) 2481b8e80941Smrg return; 2482848b8605Smrg 2483b8e80941Smrg clear_buffer_sub_data_error(ctx, bufObj, internalformat, 0, bufObj->Size, 2484b8e80941Smrg format, type, data, "glClearNamedBufferData", 2485b8e80941Smrg false); 2486b8e80941Smrg} 2487848b8605Smrg 2488848b8605Smrg 2489b8e80941Smrgvoid GLAPIENTRY 2490b8e80941Smrg_mesa_ClearBufferSubData_no_error(GLenum target, GLenum internalformat, 2491b8e80941Smrg GLintptr offset, GLsizeiptr size, 2492b8e80941Smrg GLenum format, GLenum type, 2493b8e80941Smrg const GLvoid *data) 2494b8e80941Smrg{ 2495b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 2496848b8605Smrg 2497b8e80941Smrg struct gl_buffer_object **bufObj = get_buffer_target(ctx, target); 2498b8e80941Smrg clear_buffer_sub_data_no_error(ctx, *bufObj, internalformat, offset, size, 2499b8e80941Smrg format, type, data, "glClearBufferSubData", 2500b8e80941Smrg true); 2501b8e80941Smrg} 2502848b8605Smrg 2503848b8605Smrg 2504b8e80941Smrgvoid GLAPIENTRY 2505b8e80941Smrg_mesa_ClearBufferSubData(GLenum target, GLenum internalformat, 2506b8e80941Smrg GLintptr offset, GLsizeiptr size, 2507b8e80941Smrg GLenum format, GLenum type, 2508b8e80941Smrg const GLvoid *data) 2509b8e80941Smrg{ 2510b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 2511b8e80941Smrg struct gl_buffer_object *bufObj; 2512848b8605Smrg 2513b8e80941Smrg bufObj = get_buffer(ctx, "glClearBufferSubData", target, GL_INVALID_VALUE); 2514b8e80941Smrg if (!bufObj) 2515b8e80941Smrg return; 2516b8e80941Smrg 2517b8e80941Smrg clear_buffer_sub_data_error(ctx, bufObj, internalformat, offset, size, 2518b8e80941Smrg format, type, data, "glClearBufferSubData", 2519b8e80941Smrg true); 2520b8e80941Smrg} 2521848b8605Smrg 2522848b8605Smrg 2523b8e80941Smrgvoid GLAPIENTRY 2524b8e80941Smrg_mesa_ClearNamedBufferSubData_no_error(GLuint buffer, GLenum internalformat, 2525b8e80941Smrg GLintptr offset, GLsizeiptr size, 2526b8e80941Smrg GLenum format, GLenum type, 2527b8e80941Smrg const GLvoid *data) 2528b8e80941Smrg{ 2529b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 2530b8e80941Smrg 2531b8e80941Smrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 2532b8e80941Smrg clear_buffer_sub_data_no_error(ctx, bufObj, internalformat, offset, size, 2533b8e80941Smrg format, type, data, 2534b8e80941Smrg "glClearNamedBufferSubData", true); 2535848b8605Smrg} 2536848b8605Smrg 2537848b8605Smrg 2538b8e80941Smrgvoid GLAPIENTRY 2539b8e80941Smrg_mesa_ClearNamedBufferSubData(GLuint buffer, GLenum internalformat, 2540b8e80941Smrg GLintptr offset, GLsizeiptr size, 2541b8e80941Smrg GLenum format, GLenum type, 2542b8e80941Smrg const GLvoid *data) 2543848b8605Smrg{ 2544848b8605Smrg GET_CURRENT_CONTEXT(ctx); 2545848b8605Smrg struct gl_buffer_object *bufObj; 2546848b8605Smrg 2547b8e80941Smrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, 2548b8e80941Smrg "glClearNamedBufferSubData"); 2549848b8605Smrg if (!bufObj) 2550b8e80941Smrg return; 2551b8e80941Smrg 2552b8e80941Smrg clear_buffer_sub_data_error(ctx, bufObj, internalformat, offset, size, 2553b8e80941Smrg format, type, data, "glClearNamedBufferSubData", 2554b8e80941Smrg true); 2555b8e80941Smrg} 2556b8e80941Smrg 2557b8e80941Smrgstatic GLboolean 2558b8e80941Smrgunmap_buffer(struct gl_context *ctx, struct gl_buffer_object *bufObj) 2559b8e80941Smrg{ 2560b8e80941Smrg GLboolean status = ctx->Driver.UnmapBuffer(ctx, bufObj, MAP_USER); 2561b8e80941Smrg bufObj->Mappings[MAP_USER].AccessFlags = 0; 2562b8e80941Smrg assert(bufObj->Mappings[MAP_USER].Pointer == NULL); 2563b8e80941Smrg assert(bufObj->Mappings[MAP_USER].Offset == 0); 2564b8e80941Smrg assert(bufObj->Mappings[MAP_USER].Length == 0); 2565b8e80941Smrg 2566b8e80941Smrg return status; 2567b8e80941Smrg} 2568b8e80941Smrg 2569b8e80941Smrgstatic GLboolean 2570b8e80941Smrgvalidate_and_unmap_buffer(struct gl_context *ctx, 2571b8e80941Smrg struct gl_buffer_object *bufObj, 2572b8e80941Smrg const char *func) 2573b8e80941Smrg{ 2574b8e80941Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 2575848b8605Smrg 2576848b8605Smrg if (!_mesa_bufferobj_mapped(bufObj, MAP_USER)) { 2577b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2578b8e80941Smrg "%s(buffer is not mapped)", func); 2579848b8605Smrg return GL_FALSE; 2580848b8605Smrg } 2581848b8605Smrg 2582848b8605Smrg#ifdef BOUNDS_CHECK 2583848b8605Smrg if (bufObj->Access != GL_READ_ONLY_ARB) { 2584848b8605Smrg GLubyte *buf = (GLubyte *) bufObj->Pointer; 2585848b8605Smrg GLuint i; 2586848b8605Smrg /* check that last 100 bytes are still = magic value */ 2587848b8605Smrg for (i = 0; i < 100; i++) { 2588848b8605Smrg GLuint pos = bufObj->Size - i - 1; 2589848b8605Smrg if (buf[pos] != 123) { 2590848b8605Smrg _mesa_warning(ctx, "Out of bounds buffer object write detected" 2591848b8605Smrg " at position %d (value = %u)\n", 2592848b8605Smrg pos, buf[pos]); 2593848b8605Smrg } 2594848b8605Smrg } 2595848b8605Smrg } 2596848b8605Smrg#endif 2597848b8605Smrg 2598848b8605Smrg#ifdef VBO_DEBUG 2599848b8605Smrg if (bufObj->AccessFlags & GL_MAP_WRITE_BIT) { 2600848b8605Smrg GLuint i, unchanged = 0; 2601848b8605Smrg GLubyte *b = (GLubyte *) bufObj->Pointer; 2602848b8605Smrg GLint pos = -1; 2603848b8605Smrg /* check which bytes changed */ 2604848b8605Smrg for (i = 0; i < bufObj->Size - 1; i++) { 2605848b8605Smrg if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) { 2606848b8605Smrg unchanged++; 2607848b8605Smrg if (pos == -1) 2608848b8605Smrg pos = i; 2609848b8605Smrg } 2610848b8605Smrg } 2611848b8605Smrg if (unchanged) { 2612848b8605Smrg printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n", 2613848b8605Smrg bufObj->Name, unchanged, bufObj->Size, pos); 2614848b8605Smrg } 2615848b8605Smrg } 2616848b8605Smrg#endif 2617848b8605Smrg 2618b8e80941Smrg return unmap_buffer(ctx, bufObj); 2619848b8605Smrg} 2620848b8605Smrg 2621b8e80941SmrgGLboolean GLAPIENTRY 2622b8e80941Smrg_mesa_UnmapBuffer_no_error(GLenum target) 2623b8e80941Smrg{ 2624b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 2625b8e80941Smrg struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target); 2626b8e80941Smrg struct gl_buffer_object *bufObj = *bufObjPtr; 2627b8e80941Smrg 2628b8e80941Smrg return unmap_buffer(ctx, bufObj); 2629b8e80941Smrg} 2630848b8605Smrg 2631b8e80941SmrgGLboolean GLAPIENTRY 2632b8e80941Smrg_mesa_UnmapBuffer(GLenum target) 2633848b8605Smrg{ 2634848b8605Smrg GET_CURRENT_CONTEXT(ctx); 2635848b8605Smrg struct gl_buffer_object *bufObj; 2636848b8605Smrg 2637b8e80941Smrg bufObj = get_buffer(ctx, "glUnmapBuffer", target, GL_INVALID_OPERATION); 2638848b8605Smrg if (!bufObj) 2639b8e80941Smrg return GL_FALSE; 2640848b8605Smrg 2641b8e80941Smrg return validate_and_unmap_buffer(ctx, bufObj, "glUnmapBuffer"); 2642848b8605Smrg} 2643848b8605Smrg 2644b8e80941SmrgGLboolean GLAPIENTRY 2645b8e80941Smrg_mesa_UnmapNamedBuffer_no_error(GLuint buffer) 2646b8e80941Smrg{ 2647b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 2648b8e80941Smrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 2649848b8605Smrg 2650b8e80941Smrg return unmap_buffer(ctx, bufObj); 2651b8e80941Smrg} 2652b8e80941Smrg 2653b8e80941SmrgGLboolean GLAPIENTRY 2654b8e80941Smrg_mesa_UnmapNamedBuffer(GLuint buffer) 2655848b8605Smrg{ 2656848b8605Smrg GET_CURRENT_CONTEXT(ctx); 2657848b8605Smrg struct gl_buffer_object *bufObj; 2658848b8605Smrg 2659b8e80941Smrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glUnmapNamedBuffer"); 2660848b8605Smrg if (!bufObj) 2661b8e80941Smrg return GL_FALSE; 2662b8e80941Smrg 2663b8e80941Smrg return validate_and_unmap_buffer(ctx, bufObj, "glUnmapNamedBuffer"); 2664b8e80941Smrg} 2665b8e80941Smrg 2666848b8605Smrg 2667b8e80941Smrgstatic bool 2668b8e80941Smrgget_buffer_parameter(struct gl_context *ctx, 2669b8e80941Smrg struct gl_buffer_object *bufObj, GLenum pname, 2670b8e80941Smrg GLint64 *params, const char *func) 2671b8e80941Smrg{ 2672848b8605Smrg switch (pname) { 2673848b8605Smrg case GL_BUFFER_SIZE_ARB: 2674848b8605Smrg *params = bufObj->Size; 2675b8e80941Smrg break; 2676848b8605Smrg case GL_BUFFER_USAGE_ARB: 2677848b8605Smrg *params = bufObj->Usage; 2678b8e80941Smrg break; 2679848b8605Smrg case GL_BUFFER_ACCESS_ARB: 2680848b8605Smrg *params = simplified_access_mode(ctx, 2681b8e80941Smrg bufObj->Mappings[MAP_USER].AccessFlags); 2682b8e80941Smrg break; 2683b8e80941Smrg case GL_BUFFER_MAPPED_ARB: 2684b8e80941Smrg *params = _mesa_bufferobj_mapped(bufObj, MAP_USER); 2685b8e80941Smrg break; 2686848b8605Smrg case GL_BUFFER_ACCESS_FLAGS: 2687848b8605Smrg if (!ctx->Extensions.ARB_map_buffer_range) 2688848b8605Smrg goto invalid_pname; 2689848b8605Smrg *params = bufObj->Mappings[MAP_USER].AccessFlags; 2690b8e80941Smrg break; 2691848b8605Smrg case GL_BUFFER_MAP_OFFSET: 2692848b8605Smrg if (!ctx->Extensions.ARB_map_buffer_range) 2693848b8605Smrg goto invalid_pname; 2694848b8605Smrg *params = bufObj->Mappings[MAP_USER].Offset; 2695b8e80941Smrg break; 2696848b8605Smrg case GL_BUFFER_MAP_LENGTH: 2697848b8605Smrg if (!ctx->Extensions.ARB_map_buffer_range) 2698848b8605Smrg goto invalid_pname; 2699848b8605Smrg *params = bufObj->Mappings[MAP_USER].Length; 2700b8e80941Smrg break; 2701848b8605Smrg case GL_BUFFER_IMMUTABLE_STORAGE: 2702848b8605Smrg if (!ctx->Extensions.ARB_buffer_storage) 2703848b8605Smrg goto invalid_pname; 2704848b8605Smrg *params = bufObj->Immutable; 2705b8e80941Smrg break; 2706848b8605Smrg case GL_BUFFER_STORAGE_FLAGS: 2707848b8605Smrg if (!ctx->Extensions.ARB_buffer_storage) 2708848b8605Smrg goto invalid_pname; 2709848b8605Smrg *params = bufObj->StorageFlags; 2710b8e80941Smrg break; 2711848b8605Smrg default: 2712b8e80941Smrg goto invalid_pname; 2713848b8605Smrg } 2714848b8605Smrg 2715b8e80941Smrg return true; 2716b8e80941Smrg 2717848b8605Smrginvalid_pname: 2718b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname: %s)", func, 2719b8e80941Smrg _mesa_enum_to_string(pname)); 2720b8e80941Smrg return false; 2721b8e80941Smrg} 2722b8e80941Smrg 2723b8e80941Smrgvoid GLAPIENTRY 2724b8e80941Smrg_mesa_GetBufferParameteriv(GLenum target, GLenum pname, GLint *params) 2725b8e80941Smrg{ 2726b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 2727b8e80941Smrg struct gl_buffer_object *bufObj; 2728b8e80941Smrg GLint64 parameter; 2729b8e80941Smrg 2730b8e80941Smrg bufObj = get_buffer(ctx, "glGetBufferParameteriv", target, 2731b8e80941Smrg GL_INVALID_OPERATION); 2732b8e80941Smrg if (!bufObj) 2733b8e80941Smrg return; 2734b8e80941Smrg 2735b8e80941Smrg if (!get_buffer_parameter(ctx, bufObj, pname, ¶meter, 2736b8e80941Smrg "glGetBufferParameteriv")) 2737b8e80941Smrg return; /* Error already recorded. */ 2738b8e80941Smrg 2739b8e80941Smrg *params = (GLint) parameter; 2740b8e80941Smrg} 2741b8e80941Smrg 2742b8e80941Smrgvoid GLAPIENTRY 2743b8e80941Smrg_mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params) 2744b8e80941Smrg{ 2745b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 2746b8e80941Smrg struct gl_buffer_object *bufObj; 2747b8e80941Smrg GLint64 parameter; 2748b8e80941Smrg 2749b8e80941Smrg bufObj = get_buffer(ctx, "glGetBufferParameteri64v", target, 2750b8e80941Smrg GL_INVALID_OPERATION); 2751b8e80941Smrg if (!bufObj) 2752b8e80941Smrg return; 2753b8e80941Smrg 2754b8e80941Smrg if (!get_buffer_parameter(ctx, bufObj, pname, ¶meter, 2755b8e80941Smrg "glGetBufferParameteri64v")) 2756b8e80941Smrg return; /* Error already recorded. */ 2757b8e80941Smrg 2758b8e80941Smrg *params = parameter; 2759b8e80941Smrg} 2760b8e80941Smrg 2761b8e80941Smrgvoid GLAPIENTRY 2762b8e80941Smrg_mesa_GetNamedBufferParameteriv(GLuint buffer, GLenum pname, GLint *params) 2763b8e80941Smrg{ 2764b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 2765b8e80941Smrg struct gl_buffer_object *bufObj; 2766b8e80941Smrg GLint64 parameter; 2767b8e80941Smrg 2768b8e80941Smrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, 2769b8e80941Smrg "glGetNamedBufferParameteriv"); 2770b8e80941Smrg if (!bufObj) 2771b8e80941Smrg return; 2772b8e80941Smrg 2773b8e80941Smrg if (!get_buffer_parameter(ctx, bufObj, pname, ¶meter, 2774b8e80941Smrg "glGetNamedBufferParameteriv")) 2775b8e80941Smrg return; /* Error already recorded. */ 2776b8e80941Smrg 2777b8e80941Smrg *params = (GLint) parameter; 2778b8e80941Smrg} 2779b8e80941Smrg 2780b8e80941Smrgvoid GLAPIENTRY 2781b8e80941Smrg_mesa_GetNamedBufferParameteri64v(GLuint buffer, GLenum pname, 2782b8e80941Smrg GLint64 *params) 2783b8e80941Smrg{ 2784b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 2785b8e80941Smrg struct gl_buffer_object *bufObj; 2786b8e80941Smrg GLint64 parameter; 2787b8e80941Smrg 2788b8e80941Smrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, 2789b8e80941Smrg "glGetNamedBufferParameteri64v"); 2790b8e80941Smrg if (!bufObj) 2791b8e80941Smrg return; 2792b8e80941Smrg 2793b8e80941Smrg if (!get_buffer_parameter(ctx, bufObj, pname, ¶meter, 2794b8e80941Smrg "glGetNamedBufferParameteri64v")) 2795b8e80941Smrg return; /* Error already recorded. */ 2796b8e80941Smrg 2797b8e80941Smrg *params = parameter; 2798848b8605Smrg} 2799848b8605Smrg 2800848b8605Smrg 2801848b8605Smrgvoid GLAPIENTRY 2802848b8605Smrg_mesa_GetBufferPointerv(GLenum target, GLenum pname, GLvoid **params) 2803848b8605Smrg{ 2804848b8605Smrg GET_CURRENT_CONTEXT(ctx); 2805b8e80941Smrg struct gl_buffer_object *bufObj; 2806848b8605Smrg 2807b8e80941Smrg if (pname != GL_BUFFER_MAP_POINTER) { 2808b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointerv(pname != " 2809b8e80941Smrg "GL_BUFFER_MAP_POINTER)"); 2810848b8605Smrg return; 2811848b8605Smrg } 2812848b8605Smrg 2813b8e80941Smrg bufObj = get_buffer(ctx, "glGetBufferPointerv", target, 2814848b8605Smrg GL_INVALID_OPERATION); 2815848b8605Smrg if (!bufObj) 2816848b8605Smrg return; 2817848b8605Smrg 2818848b8605Smrg *params = bufObj->Mappings[MAP_USER].Pointer; 2819848b8605Smrg} 2820848b8605Smrg 2821848b8605Smrgvoid GLAPIENTRY 2822b8e80941Smrg_mesa_GetNamedBufferPointerv(GLuint buffer, GLenum pname, GLvoid **params) 2823848b8605Smrg{ 2824848b8605Smrg GET_CURRENT_CONTEXT(ctx); 2825b8e80941Smrg struct gl_buffer_object *bufObj; 2826848b8605Smrg 2827b8e80941Smrg if (pname != GL_BUFFER_MAP_POINTER) { 2828b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetNamedBufferPointerv(pname != " 2829b8e80941Smrg "GL_BUFFER_MAP_POINTER)"); 2830848b8605Smrg return; 2831b8e80941Smrg } 2832848b8605Smrg 2833b8e80941Smrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, 2834b8e80941Smrg "glGetNamedBufferPointerv"); 2835b8e80941Smrg if (!bufObj) 2836848b8605Smrg return; 2837848b8605Smrg 2838b8e80941Smrg *params = bufObj->Mappings[MAP_USER].Pointer; 2839b8e80941Smrg} 2840b8e80941Smrg 2841b8e80941Smrg 2842b8e80941Smrgstatic void 2843b8e80941Smrgcopy_buffer_sub_data(struct gl_context *ctx, struct gl_buffer_object *src, 2844b8e80941Smrg struct gl_buffer_object *dst, GLintptr readOffset, 2845b8e80941Smrg GLintptr writeOffset, GLsizeiptr size, const char *func) 2846b8e80941Smrg{ 2847848b8605Smrg if (_mesa_check_disallowed_mapping(src)) { 2848848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2849b8e80941Smrg "%s(readBuffer is mapped)", func); 2850848b8605Smrg return; 2851848b8605Smrg } 2852848b8605Smrg 2853848b8605Smrg if (_mesa_check_disallowed_mapping(dst)) { 2854848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 2855b8e80941Smrg "%s(writeBuffer is mapped)", func); 2856848b8605Smrg return; 2857848b8605Smrg } 2858848b8605Smrg 2859848b8605Smrg if (readOffset < 0) { 2860848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2861b8e80941Smrg "%s(readOffset %d < 0)", func, (int) readOffset); 2862848b8605Smrg return; 2863848b8605Smrg } 2864848b8605Smrg 2865848b8605Smrg if (writeOffset < 0) { 2866848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2867b8e80941Smrg "%s(writeOffset %d < 0)", func, (int) writeOffset); 2868848b8605Smrg return; 2869848b8605Smrg } 2870848b8605Smrg 2871848b8605Smrg if (size < 0) { 2872848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2873b8e80941Smrg "%s(size %d < 0)", func, (int) size); 2874848b8605Smrg return; 2875848b8605Smrg } 2876848b8605Smrg 2877848b8605Smrg if (readOffset + size > src->Size) { 2878848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2879b8e80941Smrg "%s(readOffset %d + size %d > src_buffer_size %d)", func, 2880b8e80941Smrg (int) readOffset, (int) size, (int) src->Size); 2881848b8605Smrg return; 2882848b8605Smrg } 2883848b8605Smrg 2884848b8605Smrg if (writeOffset + size > dst->Size) { 2885848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2886b8e80941Smrg "%s(writeOffset %d + size %d > dst_buffer_size %d)", func, 2887b8e80941Smrg (int) writeOffset, (int) size, (int) dst->Size); 2888848b8605Smrg return; 2889848b8605Smrg } 2890848b8605Smrg 2891848b8605Smrg if (src == dst) { 2892848b8605Smrg if (readOffset + size <= writeOffset) { 2893848b8605Smrg /* OK */ 2894848b8605Smrg } 2895848b8605Smrg else if (writeOffset + size <= readOffset) { 2896848b8605Smrg /* OK */ 2897848b8605Smrg } 2898848b8605Smrg else { 2899848b8605Smrg /* overlapping src/dst is illegal */ 2900848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 2901b8e80941Smrg "%s(overlapping src/dst)", func); 2902848b8605Smrg return; 2903848b8605Smrg } 2904848b8605Smrg } 2905848b8605Smrg 2906b8e80941Smrg dst->MinMaxCacheDirty = true; 2907b8e80941Smrg 2908848b8605Smrg ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size); 2909848b8605Smrg} 2910848b8605Smrg 2911b8e80941Smrgvoid GLAPIENTRY 2912b8e80941Smrg_mesa_CopyBufferSubData_no_error(GLenum readTarget, GLenum writeTarget, 2913b8e80941Smrg GLintptr readOffset, GLintptr writeOffset, 2914b8e80941Smrg GLsizeiptr size) 2915b8e80941Smrg{ 2916b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 2917b8e80941Smrg 2918b8e80941Smrg struct gl_buffer_object **src_ptr = get_buffer_target(ctx, readTarget); 2919b8e80941Smrg struct gl_buffer_object *src = *src_ptr; 2920848b8605Smrg 2921b8e80941Smrg struct gl_buffer_object **dst_ptr = get_buffer_target(ctx, writeTarget); 2922b8e80941Smrg struct gl_buffer_object *dst = *dst_ptr; 2923b8e80941Smrg 2924b8e80941Smrg dst->MinMaxCacheDirty = true; 2925b8e80941Smrg ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, 2926b8e80941Smrg size); 2927b8e80941Smrg} 2928b8e80941Smrg 2929b8e80941Smrgvoid GLAPIENTRY 2930b8e80941Smrg_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, 2931b8e80941Smrg GLintptr readOffset, GLintptr writeOffset, 2932b8e80941Smrg GLsizeiptr size) 2933848b8605Smrg{ 2934848b8605Smrg GET_CURRENT_CONTEXT(ctx); 2935b8e80941Smrg struct gl_buffer_object *src, *dst; 2936848b8605Smrg 2937b8e80941Smrg src = get_buffer(ctx, "glCopyBufferSubData", readTarget, 2938b8e80941Smrg GL_INVALID_OPERATION); 2939b8e80941Smrg if (!src) 2940b8e80941Smrg return; 2941848b8605Smrg 2942b8e80941Smrg dst = get_buffer(ctx, "glCopyBufferSubData", writeTarget, 2943b8e80941Smrg GL_INVALID_OPERATION); 2944b8e80941Smrg if (!dst) 2945b8e80941Smrg return; 2946b8e80941Smrg 2947b8e80941Smrg copy_buffer_sub_data(ctx, src, dst, readOffset, writeOffset, size, 2948b8e80941Smrg "glCopyBufferSubData"); 2949b8e80941Smrg} 2950b8e80941Smrg 2951b8e80941Smrgvoid GLAPIENTRY 2952b8e80941Smrg_mesa_CopyNamedBufferSubData_no_error(GLuint readBuffer, GLuint writeBuffer, 2953b8e80941Smrg GLintptr readOffset, 2954b8e80941Smrg GLintptr writeOffset, GLsizeiptr size) 2955b8e80941Smrg{ 2956b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 2957b8e80941Smrg 2958b8e80941Smrg struct gl_buffer_object *src = _mesa_lookup_bufferobj(ctx, readBuffer); 2959b8e80941Smrg struct gl_buffer_object *dst = _mesa_lookup_bufferobj(ctx, writeBuffer); 2960b8e80941Smrg 2961b8e80941Smrg dst->MinMaxCacheDirty = true; 2962b8e80941Smrg ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, 2963b8e80941Smrg size); 2964b8e80941Smrg} 2965b8e80941Smrg 2966b8e80941Smrgvoid GLAPIENTRY 2967b8e80941Smrg_mesa_CopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer, 2968b8e80941Smrg GLintptr readOffset, GLintptr writeOffset, 2969b8e80941Smrg GLsizeiptr size) 2970b8e80941Smrg{ 2971b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 2972b8e80941Smrg struct gl_buffer_object *src, *dst; 2973b8e80941Smrg 2974b8e80941Smrg src = _mesa_lookup_bufferobj_err(ctx, readBuffer, 2975b8e80941Smrg "glCopyNamedBufferSubData"); 2976b8e80941Smrg if (!src) 2977b8e80941Smrg return; 2978b8e80941Smrg 2979b8e80941Smrg dst = _mesa_lookup_bufferobj_err(ctx, writeBuffer, 2980b8e80941Smrg "glCopyNamedBufferSubData"); 2981b8e80941Smrg if (!dst) 2982b8e80941Smrg return; 2983b8e80941Smrg 2984b8e80941Smrg copy_buffer_sub_data(ctx, src, dst, readOffset, writeOffset, size, 2985b8e80941Smrg "glCopyNamedBufferSubData"); 2986b8e80941Smrg} 2987b8e80941Smrg 2988b8e80941Smrgstatic bool 2989b8e80941Smrgvalidate_map_buffer_range(struct gl_context *ctx, 2990b8e80941Smrg struct gl_buffer_object *bufObj, GLintptr offset, 2991b8e80941Smrg GLsizeiptr length, GLbitfield access, 2992b8e80941Smrg const char *func) 2993b8e80941Smrg{ 2994b8e80941Smrg GLbitfield allowed_access; 2995b8e80941Smrg 2996b8e80941Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, false); 2997848b8605Smrg 2998848b8605Smrg if (offset < 0) { 2999848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3000b8e80941Smrg "%s(offset %ld < 0)", func, (long) offset); 3001b8e80941Smrg return false; 3002848b8605Smrg } 3003848b8605Smrg 3004848b8605Smrg if (length < 0) { 3005848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3006b8e80941Smrg "%s(length %ld < 0)", func, (long) length); 3007b8e80941Smrg return false; 3008848b8605Smrg } 3009848b8605Smrg 3010848b8605Smrg /* Page 38 of the PDF of the OpenGL ES 3.0 spec says: 3011848b8605Smrg * 3012848b8605Smrg * "An INVALID_OPERATION error is generated for any of the following 3013848b8605Smrg * conditions: 3014848b8605Smrg * 3015848b8605Smrg * * <length> is zero." 3016b8e80941Smrg * 3017b8e80941Smrg * Additionally, page 94 of the PDF of the OpenGL 4.5 core spec 3018b8e80941Smrg * (30.10.2014) also says this, so it's no longer allowed for desktop GL, 3019b8e80941Smrg * either. 3020848b8605Smrg */ 3021b8e80941Smrg if (length == 0) { 3022b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(length = 0)", func); 3023b8e80941Smrg return false; 3024848b8605Smrg } 3025848b8605Smrg 3026848b8605Smrg allowed_access = GL_MAP_READ_BIT | 3027848b8605Smrg GL_MAP_WRITE_BIT | 3028848b8605Smrg GL_MAP_INVALIDATE_RANGE_BIT | 3029848b8605Smrg GL_MAP_INVALIDATE_BUFFER_BIT | 3030848b8605Smrg GL_MAP_FLUSH_EXPLICIT_BIT | 3031848b8605Smrg GL_MAP_UNSYNCHRONIZED_BIT; 3032848b8605Smrg 3033848b8605Smrg if (ctx->Extensions.ARB_buffer_storage) { 3034848b8605Smrg allowed_access |= GL_MAP_PERSISTENT_BIT | 3035848b8605Smrg GL_MAP_COHERENT_BIT; 3036848b8605Smrg } 3037848b8605Smrg 3038848b8605Smrg if (access & ~allowed_access) { 3039b8e80941Smrg /* generate an error if any bits other than those allowed are set */ 3040b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3041b8e80941Smrg "%s(access has undefined bits set)", func); 3042b8e80941Smrg return false; 3043848b8605Smrg } 3044848b8605Smrg 3045848b8605Smrg if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) { 3046848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3047b8e80941Smrg "%s(access indicates neither read or write)", func); 3048b8e80941Smrg return false; 3049848b8605Smrg } 3050848b8605Smrg 3051848b8605Smrg if ((access & GL_MAP_READ_BIT) && 3052848b8605Smrg (access & (GL_MAP_INVALIDATE_RANGE_BIT | 3053848b8605Smrg GL_MAP_INVALIDATE_BUFFER_BIT | 3054848b8605Smrg GL_MAP_UNSYNCHRONIZED_BIT))) { 3055848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3056b8e80941Smrg "%s(read access with disallowed bits)", func); 3057b8e80941Smrg return false; 3058848b8605Smrg } 3059848b8605Smrg 3060848b8605Smrg if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) && 3061848b8605Smrg ((access & GL_MAP_WRITE_BIT) == 0)) { 3062848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3063b8e80941Smrg "%s(access has flush explicit without write)", func); 3064b8e80941Smrg return false; 3065848b8605Smrg } 3066848b8605Smrg 3067848b8605Smrg if (access & GL_MAP_READ_BIT && 3068848b8605Smrg !(bufObj->StorageFlags & GL_MAP_READ_BIT)) { 3069848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3070b8e80941Smrg "%s(buffer does not allow read access)", func); 3071b8e80941Smrg return false; 3072848b8605Smrg } 3073848b8605Smrg 3074848b8605Smrg if (access & GL_MAP_WRITE_BIT && 3075848b8605Smrg !(bufObj->StorageFlags & GL_MAP_WRITE_BIT)) { 3076848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3077b8e80941Smrg "%s(buffer does not allow write access)", func); 3078b8e80941Smrg return false; 3079848b8605Smrg } 3080848b8605Smrg 3081848b8605Smrg if (access & GL_MAP_COHERENT_BIT && 3082848b8605Smrg !(bufObj->StorageFlags & GL_MAP_COHERENT_BIT)) { 3083848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3084b8e80941Smrg "%s(buffer does not allow coherent access)", func); 3085b8e80941Smrg return false; 3086848b8605Smrg } 3087848b8605Smrg 3088b8e80941Smrg if (access & GL_MAP_PERSISTENT_BIT && 3089b8e80941Smrg !(bufObj->StorageFlags & GL_MAP_PERSISTENT_BIT)) { 3090848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3091b8e80941Smrg "%s(buffer does not allow persistent access)", func); 3092b8e80941Smrg return false; 3093848b8605Smrg } 3094848b8605Smrg 3095b8e80941Smrg if (offset + length > bufObj->Size) { 3096848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3097b8e80941Smrg "%s(offset %lu + length %lu > buffer_size %lu)", func, 3098b8e80941Smrg (unsigned long) offset, (unsigned long) length, 3099b8e80941Smrg (unsigned long) bufObj->Size); 3100b8e80941Smrg return false; 3101848b8605Smrg } 3102848b8605Smrg 3103b8e80941Smrg if (_mesa_bufferobj_mapped(bufObj, MAP_USER)) { 3104b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3105b8e80941Smrg "%s(buffer already mapped)", func); 3106b8e80941Smrg return false; 3107b8e80941Smrg } 3108848b8605Smrg 3109b8e80941Smrg if (access & GL_MAP_WRITE_BIT) { 3110b8e80941Smrg bufObj->NumMapBufferWriteCalls++; 3111b8e80941Smrg if ((bufObj->Usage == GL_STATIC_DRAW || 3112b8e80941Smrg bufObj->Usage == GL_STATIC_COPY) && 3113b8e80941Smrg bufObj->NumMapBufferWriteCalls >= BUFFER_WARNING_CALL_COUNT) { 3114b8e80941Smrg BUFFER_USAGE_WARNING(ctx, 3115b8e80941Smrg "using %s(buffer %u, offset %u, length %u) to " 3116b8e80941Smrg "update a %s buffer", 3117b8e80941Smrg func, bufObj->Name, offset, length, 3118b8e80941Smrg _mesa_enum_to_string(bufObj->Usage)); 3119b8e80941Smrg } 3120b8e80941Smrg } 3121848b8605Smrg 3122b8e80941Smrg return true; 3123b8e80941Smrg} 3124848b8605Smrg 3125b8e80941Smrgstatic void * 3126b8e80941Smrgmap_buffer_range(struct gl_context *ctx, struct gl_buffer_object *bufObj, 3127b8e80941Smrg GLintptr offset, GLsizeiptr length, GLbitfield access, 3128b8e80941Smrg const char *func) 3129848b8605Smrg{ 3130b8e80941Smrg if (!bufObj->Size) { 3131b8e80941Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s(buffer size = 0)", func); 3132b8e80941Smrg return NULL; 3133b8e80941Smrg } 3134848b8605Smrg 3135b8e80941Smrg assert(ctx->Driver.MapBufferRange); 3136b8e80941Smrg void *map = ctx->Driver.MapBufferRange(ctx, offset, length, access, bufObj, 3137b8e80941Smrg MAP_USER); 3138b8e80941Smrg if (!map) { 3139b8e80941Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s(map failed)", func); 3140848b8605Smrg } 3141b8e80941Smrg else { 3142b8e80941Smrg /* The driver callback should have set all these fields. 3143b8e80941Smrg * This is important because other modules (like VBO) might call 3144b8e80941Smrg * the driver function directly. 3145b8e80941Smrg */ 3146b8e80941Smrg assert(bufObj->Mappings[MAP_USER].Pointer == map); 3147b8e80941Smrg assert(bufObj->Mappings[MAP_USER].Length == length); 3148b8e80941Smrg assert(bufObj->Mappings[MAP_USER].Offset == offset); 3149b8e80941Smrg assert(bufObj->Mappings[MAP_USER].AccessFlags == access); 3150848b8605Smrg } 3151848b8605Smrg 3152b8e80941Smrg if (access & GL_MAP_WRITE_BIT) { 3153b8e80941Smrg bufObj->Written = GL_TRUE; 3154b8e80941Smrg bufObj->MinMaxCacheDirty = true; 3155848b8605Smrg } 3156848b8605Smrg 3157b8e80941Smrg#ifdef VBO_DEBUG 3158b8e80941Smrg if (strstr(func, "Range") == NULL) { /* If not MapRange */ 3159b8e80941Smrg printf("glMapBuffer(%u, sz %ld, access 0x%x)\n", 3160b8e80941Smrg bufObj->Name, bufObj->Size, access); 3161b8e80941Smrg /* Access must be write only */ 3162b8e80941Smrg if ((access & GL_MAP_WRITE_BIT) && (!(access & ~GL_MAP_WRITE_BIT))) { 3163b8e80941Smrg GLuint i; 3164b8e80941Smrg GLubyte *b = (GLubyte *) bufObj->Pointer; 3165b8e80941Smrg for (i = 0; i < bufObj->Size; i++) 3166b8e80941Smrg b[i] = i & 0xff; 3167b8e80941Smrg } 3168b8e80941Smrg } 3169b8e80941Smrg#endif 3170848b8605Smrg 3171b8e80941Smrg#ifdef BOUNDS_CHECK 3172b8e80941Smrg if (strstr(func, "Range") == NULL) { /* If not MapRange */ 3173b8e80941Smrg GLubyte *buf = (GLubyte *) bufObj->Pointer; 3174b8e80941Smrg GLuint i; 3175b8e80941Smrg /* buffer is 100 bytes larger than requested, fill with magic value */ 3176b8e80941Smrg for (i = 0; i < 100; i++) { 3177b8e80941Smrg buf[bufObj->Size - i - 1] = 123; 3178b8e80941Smrg } 3179b8e80941Smrg } 3180b8e80941Smrg#endif 3181848b8605Smrg 3182b8e80941Smrg return map; 3183848b8605Smrg} 3184848b8605Smrg 3185b8e80941Smrgvoid * GLAPIENTRY 3186b8e80941Smrg_mesa_MapBufferRange_no_error(GLenum target, GLintptr offset, 3187b8e80941Smrg GLsizeiptr length, GLbitfield access) 3188848b8605Smrg{ 3189b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 3190848b8605Smrg 3191b8e80941Smrg struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target); 3192b8e80941Smrg struct gl_buffer_object *bufObj = *bufObjPtr; 3193848b8605Smrg 3194b8e80941Smrg return map_buffer_range(ctx, bufObj, offset, length, access, 3195b8e80941Smrg "glMapBufferRange"); 3196848b8605Smrg} 3197848b8605Smrg 3198b8e80941Smrgvoid * GLAPIENTRY 3199b8e80941Smrg_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, 3200b8e80941Smrg GLbitfield access) 3201848b8605Smrg{ 3202b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 3203b8e80941Smrg struct gl_buffer_object *bufObj; 3204848b8605Smrg 3205b8e80941Smrg if (!ctx->Extensions.ARB_map_buffer_range) { 3206848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3207b8e80941Smrg "glMapBufferRange(ARB_map_buffer_range not supported)"); 3208b8e80941Smrg return NULL; 3209848b8605Smrg } 3210848b8605Smrg 3211b8e80941Smrg bufObj = get_buffer(ctx, "glMapBufferRange", target, GL_INVALID_OPERATION); 3212b8e80941Smrg if (!bufObj) 3213b8e80941Smrg return NULL; 3214848b8605Smrg 3215b8e80941Smrg if (!validate_map_buffer_range(ctx, bufObj, offset, length, access, 3216b8e80941Smrg "glMapBufferRange")) 3217b8e80941Smrg return NULL; 3218848b8605Smrg 3219b8e80941Smrg return map_buffer_range(ctx, bufObj, offset, length, access, 3220b8e80941Smrg "glMapBufferRange"); 3221848b8605Smrg} 3222848b8605Smrg 3223b8e80941Smrgvoid * GLAPIENTRY 3224b8e80941Smrg_mesa_MapNamedBufferRange_no_error(GLuint buffer, GLintptr offset, 3225b8e80941Smrg GLsizeiptr length, GLbitfield access) 3226848b8605Smrg{ 3227848b8605Smrg GET_CURRENT_CONTEXT(ctx); 3228b8e80941Smrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 3229848b8605Smrg 3230b8e80941Smrg return map_buffer_range(ctx, bufObj, offset, length, access, 3231b8e80941Smrg "glMapNamedBufferRange"); 3232848b8605Smrg} 3233848b8605Smrg 3234b8e80941Smrgvoid * GLAPIENTRY 3235b8e80941Smrg_mesa_MapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, 3236b8e80941Smrg GLbitfield access) 3237848b8605Smrg{ 3238b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 3239848b8605Smrg struct gl_buffer_object *bufObj; 3240848b8605Smrg 3241b8e80941Smrg if (!ctx->Extensions.ARB_map_buffer_range) { 3242848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3243b8e80941Smrg "glMapNamedBufferRange(" 3244b8e80941Smrg "ARB_map_buffer_range not supported)"); 3245b8e80941Smrg return NULL; 3246848b8605Smrg } 3247848b8605Smrg 3248b8e80941Smrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glMapNamedBufferRange"); 3249b8e80941Smrg if (!bufObj) 3250b8e80941Smrg return NULL; 3251848b8605Smrg 3252b8e80941Smrg if (!validate_map_buffer_range(ctx, bufObj, offset, length, access, 3253b8e80941Smrg "glMapNamedBufferRange")) 3254b8e80941Smrg return NULL; 3255848b8605Smrg 3256b8e80941Smrg return map_buffer_range(ctx, bufObj, offset, length, access, 3257b8e80941Smrg "glMapNamedBufferRange"); 3258848b8605Smrg} 3259848b8605Smrg 3260b8e80941Smrg/** 3261b8e80941Smrg * Converts GLenum access from MapBuffer and MapNamedBuffer into 3262b8e80941Smrg * flags for input to map_buffer_range. 3263b8e80941Smrg * 3264b8e80941Smrg * \return true if the type of requested access is permissible. 3265b8e80941Smrg */ 3266b8e80941Smrgstatic bool 3267b8e80941Smrgget_map_buffer_access_flags(struct gl_context *ctx, GLenum access, 3268b8e80941Smrg GLbitfield *flags) 3269848b8605Smrg{ 3270b8e80941Smrg switch (access) { 3271b8e80941Smrg case GL_READ_ONLY_ARB: 3272b8e80941Smrg *flags = GL_MAP_READ_BIT; 3273b8e80941Smrg return _mesa_is_desktop_gl(ctx); 3274b8e80941Smrg case GL_WRITE_ONLY_ARB: 3275b8e80941Smrg *flags = GL_MAP_WRITE_BIT; 3276b8e80941Smrg return true; 3277b8e80941Smrg case GL_READ_WRITE_ARB: 3278b8e80941Smrg *flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; 3279b8e80941Smrg return _mesa_is_desktop_gl(ctx); 3280b8e80941Smrg default: 3281b8e80941Smrg *flags = 0; 3282b8e80941Smrg return false; 3283848b8605Smrg } 3284b8e80941Smrg} 3285848b8605Smrg 3286b8e80941Smrgvoid * GLAPIENTRY 3287b8e80941Smrg_mesa_MapBuffer_no_error(GLenum target, GLenum access) 3288b8e80941Smrg{ 3289b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 3290848b8605Smrg 3291b8e80941Smrg GLbitfield accessFlags; 3292b8e80941Smrg get_map_buffer_access_flags(ctx, access, &accessFlags); 3293848b8605Smrg 3294b8e80941Smrg struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target); 3295b8e80941Smrg struct gl_buffer_object *bufObj = *bufObjPtr; 3296848b8605Smrg 3297b8e80941Smrg return map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags, 3298b8e80941Smrg "glMapBuffer"); 3299848b8605Smrg} 3300848b8605Smrg 3301b8e80941Smrgvoid * GLAPIENTRY 3302b8e80941Smrg_mesa_MapBuffer(GLenum target, GLenum access) 3303848b8605Smrg{ 3304b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 3305b8e80941Smrg struct gl_buffer_object *bufObj; 3306b8e80941Smrg GLbitfield accessFlags; 3307848b8605Smrg 3308b8e80941Smrg if (!get_map_buffer_access_flags(ctx, access, &accessFlags)) { 3309b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glMapBuffer(invalid access)"); 3310b8e80941Smrg return NULL; 3311848b8605Smrg } 3312848b8605Smrg 3313b8e80941Smrg bufObj = get_buffer(ctx, "glMapBuffer", target, GL_INVALID_OPERATION); 3314b8e80941Smrg if (!bufObj) 3315b8e80941Smrg return NULL; 3316848b8605Smrg 3317b8e80941Smrg if (!validate_map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags, 3318b8e80941Smrg "glMapBuffer")) 3319b8e80941Smrg return NULL; 3320848b8605Smrg 3321b8e80941Smrg return map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags, 3322b8e80941Smrg "glMapBuffer"); 3323848b8605Smrg} 3324848b8605Smrg 3325b8e80941Smrgvoid * GLAPIENTRY 3326b8e80941Smrg_mesa_MapNamedBuffer_no_error(GLuint buffer, GLenum access) 3327b8e80941Smrg{ 3328b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 3329b8e80941Smrg 3330b8e80941Smrg GLbitfield accessFlags; 3331b8e80941Smrg get_map_buffer_access_flags(ctx, access, &accessFlags); 3332b8e80941Smrg 3333b8e80941Smrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 3334b8e80941Smrg 3335b8e80941Smrg return map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags, 3336b8e80941Smrg "glMapNamedBuffer"); 3337b8e80941Smrg} 3338848b8605Smrg 3339b8e80941Smrgvoid * GLAPIENTRY 3340b8e80941Smrg_mesa_MapNamedBuffer(GLuint buffer, GLenum access) 3341848b8605Smrg{ 3342848b8605Smrg GET_CURRENT_CONTEXT(ctx); 3343b8e80941Smrg struct gl_buffer_object *bufObj; 3344b8e80941Smrg GLbitfield accessFlags; 3345848b8605Smrg 3346b8e80941Smrg if (!get_map_buffer_access_flags(ctx, access, &accessFlags)) { 3347b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glMapNamedBuffer(invalid access)"); 3348b8e80941Smrg return NULL; 3349848b8605Smrg } 3350848b8605Smrg 3351b8e80941Smrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glMapNamedBuffer"); 3352b8e80941Smrg if (!bufObj) 3353b8e80941Smrg return NULL; 3354b8e80941Smrg 3355b8e80941Smrg if (!validate_map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags, 3356b8e80941Smrg "glMapNamedBuffer")) 3357b8e80941Smrg return NULL; 3358b8e80941Smrg 3359b8e80941Smrg return map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags, 3360b8e80941Smrg "glMapNamedBuffer"); 3361848b8605Smrg} 3362848b8605Smrg 3363848b8605Smrg 3364848b8605Smrgstatic void 3365b8e80941Smrgflush_mapped_buffer_range(struct gl_context *ctx, 3366b8e80941Smrg struct gl_buffer_object *bufObj, 3367b8e80941Smrg GLintptr offset, GLsizeiptr length, 3368b8e80941Smrg const char *func) 3369848b8605Smrg{ 3370b8e80941Smrg if (!ctx->Extensions.ARB_map_buffer_range) { 3371b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3372b8e80941Smrg "%s(ARB_map_buffer_range not supported)", func); 3373848b8605Smrg return; 3374848b8605Smrg } 3375848b8605Smrg 3376b8e80941Smrg if (offset < 0) { 3377b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3378b8e80941Smrg "%s(offset %ld < 0)", func, (long) offset); 3379b8e80941Smrg return; 3380848b8605Smrg } 3381848b8605Smrg 3382b8e80941Smrg if (length < 0) { 3383848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3384b8e80941Smrg "%s(length %ld < 0)", func, (long) length); 3385848b8605Smrg return; 3386848b8605Smrg } 3387848b8605Smrg 3388b8e80941Smrg if (!_mesa_bufferobj_mapped(bufObj, MAP_USER)) { 3389b8e80941Smrg /* buffer is not mapped */ 3390b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3391b8e80941Smrg "%s(buffer is not mapped)", func); 3392b8e80941Smrg return; 3393848b8605Smrg } 3394848b8605Smrg 3395b8e80941Smrg if ((bufObj->Mappings[MAP_USER].AccessFlags & 3396b8e80941Smrg GL_MAP_FLUSH_EXPLICIT_BIT) == 0) { 3397b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3398b8e80941Smrg "%s(GL_MAP_FLUSH_EXPLICIT_BIT not set)", func); 3399b8e80941Smrg return; 3400b8e80941Smrg } 3401848b8605Smrg 3402b8e80941Smrg if (offset + length > bufObj->Mappings[MAP_USER].Length) { 3403848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3404b8e80941Smrg "%s(offset %ld + length %ld > mapped length %ld)", func, 3405b8e80941Smrg (long) offset, (long) length, 3406b8e80941Smrg (long) bufObj->Mappings[MAP_USER].Length); 3407848b8605Smrg return; 3408848b8605Smrg } 3409848b8605Smrg 3410b8e80941Smrg assert(bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_WRITE_BIT); 3411b8e80941Smrg 3412b8e80941Smrg if (ctx->Driver.FlushMappedBufferRange) 3413b8e80941Smrg ctx->Driver.FlushMappedBufferRange(ctx, offset, length, bufObj, 3414b8e80941Smrg MAP_USER); 3415848b8605Smrg} 3416848b8605Smrg 3417b8e80941Smrgvoid GLAPIENTRY 3418b8e80941Smrg_mesa_FlushMappedBufferRange_no_error(GLenum target, GLintptr offset, 3419b8e80941Smrg GLsizeiptr length) 3420b8e80941Smrg{ 3421b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 3422b8e80941Smrg struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target); 3423b8e80941Smrg struct gl_buffer_object *bufObj = *bufObjPtr; 3424b8e80941Smrg 3425b8e80941Smrg if (ctx->Driver.FlushMappedBufferRange) 3426b8e80941Smrg ctx->Driver.FlushMappedBufferRange(ctx, offset, length, bufObj, 3427b8e80941Smrg MAP_USER); 3428b8e80941Smrg} 3429848b8605Smrg 3430848b8605Smrgvoid GLAPIENTRY 3431b8e80941Smrg_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, 3432b8e80941Smrg GLsizeiptr length) 3433848b8605Smrg{ 3434848b8605Smrg GET_CURRENT_CONTEXT(ctx); 3435b8e80941Smrg struct gl_buffer_object *bufObj; 3436848b8605Smrg 3437b8e80941Smrg bufObj = get_buffer(ctx, "glFlushMappedBufferRange", target, 3438b8e80941Smrg GL_INVALID_OPERATION); 3439b8e80941Smrg if (!bufObj) 3440848b8605Smrg return; 3441848b8605Smrg 3442b8e80941Smrg flush_mapped_buffer_range(ctx, bufObj, offset, length, 3443b8e80941Smrg "glFlushMappedBufferRange"); 3444848b8605Smrg} 3445848b8605Smrg 3446b8e80941Smrgvoid GLAPIENTRY 3447b8e80941Smrg_mesa_FlushMappedNamedBufferRange_no_error(GLuint buffer, GLintptr offset, 3448b8e80941Smrg GLsizeiptr length) 3449b8e80941Smrg{ 3450b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 3451b8e80941Smrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 3452b8e80941Smrg 3453b8e80941Smrg if (ctx->Driver.FlushMappedBufferRange) 3454b8e80941Smrg ctx->Driver.FlushMappedBufferRange(ctx, offset, length, bufObj, 3455b8e80941Smrg MAP_USER); 3456b8e80941Smrg} 3457b8e80941Smrg 3458b8e80941Smrgvoid GLAPIENTRY 3459b8e80941Smrg_mesa_FlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, 3460b8e80941Smrg GLsizeiptr length) 3461848b8605Smrg{ 3462b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 3463b8e80941Smrg struct gl_buffer_object *bufObj; 3464848b8605Smrg 3465b8e80941Smrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, 3466b8e80941Smrg "glFlushMappedNamedBufferRange"); 3467b8e80941Smrg if (!bufObj) 3468b8e80941Smrg return; 3469b8e80941Smrg 3470b8e80941Smrg flush_mapped_buffer_range(ctx, bufObj, offset, length, 3471b8e80941Smrg "glFlushMappedNamedBufferRange"); 3472848b8605Smrg} 3473848b8605Smrg 3474848b8605Smrgstatic void 3475b8e80941Smrgbind_buffer_range_uniform_buffer(struct gl_context *ctx, GLuint index, 3476b8e80941Smrg struct gl_buffer_object *bufObj, 3477b8e80941Smrg GLintptr offset, GLsizeiptr size) 3478848b8605Smrg{ 3479b8e80941Smrg if (bufObj == ctx->Shared->NullBufferObj) { 3480b8e80941Smrg offset = -1; 3481b8e80941Smrg size = -1; 3482848b8605Smrg } 3483848b8605Smrg 3484b8e80941Smrg _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj); 3485b8e80941Smrg bind_uniform_buffer(ctx, index, bufObj, offset, size, GL_FALSE); 3486848b8605Smrg} 3487848b8605Smrg 3488848b8605Smrg/** 3489848b8605Smrg * Bind a region of a buffer object to a uniform block binding point. 3490848b8605Smrg * \param index the uniform buffer binding point index 3491848b8605Smrg * \param bufObj the buffer object 3492848b8605Smrg * \param offset offset to the start of buffer object region 3493848b8605Smrg * \param size size of the buffer object region 3494848b8605Smrg */ 3495848b8605Smrgstatic void 3496b8e80941Smrgbind_buffer_range_uniform_buffer_err(struct gl_context *ctx, GLuint index, 3497b8e80941Smrg struct gl_buffer_object *bufObj, 3498b8e80941Smrg GLintptr offset, GLsizeiptr size) 3499848b8605Smrg{ 3500848b8605Smrg if (index >= ctx->Const.MaxUniformBufferBindings) { 3501848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index); 3502848b8605Smrg return; 3503848b8605Smrg } 3504848b8605Smrg 3505848b8605Smrg if (offset & (ctx->Const.UniformBufferOffsetAlignment - 1)) { 3506848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3507b8e80941Smrg "glBindBufferRange(offset misaligned %d/%d)", (int) offset, 3508848b8605Smrg ctx->Const.UniformBufferOffsetAlignment); 3509848b8605Smrg return; 3510848b8605Smrg } 3511848b8605Smrg 3512b8e80941Smrg bind_buffer_range_uniform_buffer(ctx, index, bufObj, offset, size); 3513b8e80941Smrg} 3514b8e80941Smrg 3515b8e80941Smrgstatic void 3516b8e80941Smrgbind_buffer_range_shader_storage_buffer(struct gl_context *ctx, 3517b8e80941Smrg GLuint index, 3518b8e80941Smrg struct gl_buffer_object *bufObj, 3519b8e80941Smrg GLintptr offset, 3520b8e80941Smrg GLsizeiptr size) 3521b8e80941Smrg{ 3522848b8605Smrg if (bufObj == ctx->Shared->NullBufferObj) { 3523848b8605Smrg offset = -1; 3524848b8605Smrg size = -1; 3525848b8605Smrg } 3526848b8605Smrg 3527b8e80941Smrg _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer, bufObj); 3528b8e80941Smrg bind_shader_storage_buffer(ctx, index, bufObj, offset, size, GL_FALSE); 3529848b8605Smrg} 3530848b8605Smrg 3531848b8605Smrg/** 3532b8e80941Smrg * Bind a region of a buffer object to a shader storage block binding point. 3533b8e80941Smrg * \param index the shader storage buffer binding point index 3534b8e80941Smrg * \param bufObj the buffer object 3535b8e80941Smrg * \param offset offset to the start of buffer object region 3536b8e80941Smrg * \param size size of the buffer object region 3537848b8605Smrg */ 3538848b8605Smrgstatic void 3539b8e80941Smrgbind_buffer_range_shader_storage_buffer_err(struct gl_context *ctx, 3540b8e80941Smrg GLuint index, 3541b8e80941Smrg struct gl_buffer_object *bufObj, 3542b8e80941Smrg GLintptr offset, GLsizeiptr size) 3543848b8605Smrg{ 3544b8e80941Smrg if (index >= ctx->Const.MaxShaderStorageBufferBindings) { 3545b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index); 3546848b8605Smrg return; 3547848b8605Smrg } 3548848b8605Smrg 3549b8e80941Smrg if (offset & (ctx->Const.ShaderStorageBufferOffsetAlignment - 1)) { 3550b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3551b8e80941Smrg "glBindBufferRange(offset misaligned %d/%d)", (int) offset, 3552b8e80941Smrg ctx->Const.ShaderStorageBufferOffsetAlignment); 3553b8e80941Smrg return; 3554b8e80941Smrg } 3555848b8605Smrg 3556b8e80941Smrg bind_buffer_range_shader_storage_buffer(ctx, index, bufObj, offset, size); 3557848b8605Smrg} 3558848b8605Smrg 3559848b8605Smrgstatic void 3560b8e80941Smrgbind_buffer_range_atomic_buffer(struct gl_context *ctx, GLuint index, 3561b8e80941Smrg struct gl_buffer_object *bufObj, 3562b8e80941Smrg GLintptr offset, GLsizeiptr size) 3563848b8605Smrg{ 3564848b8605Smrg if (bufObj == ctx->Shared->NullBufferObj) { 3565b8e80941Smrg offset = -1; 3566b8e80941Smrg size = -1; 3567848b8605Smrg } 3568b8e80941Smrg 3569b8e80941Smrg _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, bufObj); 3570b8e80941Smrg bind_atomic_buffer(ctx, index, bufObj, offset, size, GL_FALSE); 3571848b8605Smrg} 3572848b8605Smrg 3573848b8605Smrg/** 3574b8e80941Smrg * Bind a region of a buffer object to an atomic storage block binding point. 3575b8e80941Smrg * \param index the shader storage buffer binding point index 3576b8e80941Smrg * \param bufObj the buffer object 3577b8e80941Smrg * \param offset offset to the start of buffer object region 3578b8e80941Smrg * \param size size of the buffer object region 3579848b8605Smrg */ 3580848b8605Smrgstatic void 3581b8e80941Smrgbind_buffer_range_atomic_buffer_err(struct gl_context *ctx, 3582b8e80941Smrg GLuint index, 3583b8e80941Smrg struct gl_buffer_object *bufObj, 3584b8e80941Smrg GLintptr offset, GLsizeiptr size) 3585848b8605Smrg{ 3586848b8605Smrg if (index >= ctx->Const.MaxAtomicBufferBindings) { 3587b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index); 3588848b8605Smrg return; 3589848b8605Smrg } 3590848b8605Smrg 3591848b8605Smrg if (offset & (ATOMIC_COUNTER_SIZE - 1)) { 3592848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3593b8e80941Smrg "glBindBufferRange(offset misaligned %d/%d)", (int) offset, 3594b8e80941Smrg ATOMIC_COUNTER_SIZE); 3595848b8605Smrg return; 3596848b8605Smrg } 3597848b8605Smrg 3598b8e80941Smrg bind_buffer_range_atomic_buffer(ctx, index, bufObj, offset, size); 3599848b8605Smrg} 3600848b8605Smrg 3601848b8605Smrgstatic inline bool 3602848b8605Smrgbind_buffers_check_offset_and_size(struct gl_context *ctx, 3603848b8605Smrg GLuint index, 3604848b8605Smrg const GLintptr *offsets, 3605848b8605Smrg const GLsizeiptr *sizes) 3606848b8605Smrg{ 3607848b8605Smrg if (offsets[index] < 0) { 3608b8e80941Smrg /* The ARB_multi_bind spec says: 3609b8e80941Smrg * 3610b8e80941Smrg * "An INVALID_VALUE error is generated by BindBuffersRange if any 3611b8e80941Smrg * value in <offsets> is less than zero (per binding)." 3612b8e80941Smrg */ 3613848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3614848b8605Smrg "glBindBuffersRange(offsets[%u]=%" PRId64 " < 0)", 3615848b8605Smrg index, (int64_t) offsets[index]); 3616848b8605Smrg return false; 3617848b8605Smrg } 3618848b8605Smrg 3619848b8605Smrg if (sizes[index] <= 0) { 3620b8e80941Smrg /* The ARB_multi_bind spec says: 3621b8e80941Smrg * 3622b8e80941Smrg * "An INVALID_VALUE error is generated by BindBuffersRange if any 3623b8e80941Smrg * value in <sizes> is less than or equal to zero (per binding)." 3624b8e80941Smrg */ 3625848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3626848b8605Smrg "glBindBuffersRange(sizes[%u]=%" PRId64 " <= 0)", 3627848b8605Smrg index, (int64_t) sizes[index]); 3628848b8605Smrg return false; 3629848b8605Smrg } 3630848b8605Smrg 3631848b8605Smrg return true; 3632848b8605Smrg} 3633848b8605Smrg 3634848b8605Smrgstatic bool 3635848b8605Smrgerror_check_bind_uniform_buffers(struct gl_context *ctx, 3636848b8605Smrg GLuint first, GLsizei count, 3637848b8605Smrg const char *caller) 3638848b8605Smrg{ 3639848b8605Smrg if (!ctx->Extensions.ARB_uniform_buffer_object) { 3640848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, 3641848b8605Smrg "%s(target=GL_UNIFORM_BUFFER)", caller); 3642848b8605Smrg return false; 3643848b8605Smrg } 3644848b8605Smrg 3645848b8605Smrg /* The ARB_multi_bind_spec says: 3646848b8605Smrg * 3647848b8605Smrg * "An INVALID_OPERATION error is generated if <first> + <count> is 3648848b8605Smrg * greater than the number of target-specific indexed binding points, 3649848b8605Smrg * as described in section 6.7.1." 3650848b8605Smrg */ 3651848b8605Smrg if (first + count > ctx->Const.MaxUniformBufferBindings) { 3652848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3653848b8605Smrg "%s(first=%u + count=%d > the value of " 3654848b8605Smrg "GL_MAX_UNIFORM_BUFFER_BINDINGS=%u)", 3655848b8605Smrg caller, first, count, 3656848b8605Smrg ctx->Const.MaxUniformBufferBindings); 3657848b8605Smrg return false; 3658848b8605Smrg } 3659848b8605Smrg 3660848b8605Smrg return true; 3661848b8605Smrg} 3662848b8605Smrg 3663b8e80941Smrgstatic bool 3664b8e80941Smrgerror_check_bind_shader_storage_buffers(struct gl_context *ctx, 3665b8e80941Smrg GLuint first, GLsizei count, 3666b8e80941Smrg const char *caller) 3667b8e80941Smrg{ 3668b8e80941Smrg if (!ctx->Extensions.ARB_shader_storage_buffer_object) { 3669b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, 3670b8e80941Smrg "%s(target=GL_SHADER_STORAGE_BUFFER)", caller); 3671b8e80941Smrg return false; 3672b8e80941Smrg } 3673b8e80941Smrg 3674b8e80941Smrg /* The ARB_multi_bind_spec says: 3675b8e80941Smrg * 3676b8e80941Smrg * "An INVALID_OPERATION error is generated if <first> + <count> is 3677b8e80941Smrg * greater than the number of target-specific indexed binding points, 3678b8e80941Smrg * as described in section 6.7.1." 3679b8e80941Smrg */ 3680b8e80941Smrg if (first + count > ctx->Const.MaxShaderStorageBufferBindings) { 3681b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3682b8e80941Smrg "%s(first=%u + count=%d > the value of " 3683b8e80941Smrg "GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS=%u)", 3684b8e80941Smrg caller, first, count, 3685b8e80941Smrg ctx->Const.MaxShaderStorageBufferBindings); 3686b8e80941Smrg return false; 3687b8e80941Smrg } 3688b8e80941Smrg 3689b8e80941Smrg return true; 3690b8e80941Smrg} 3691b8e80941Smrg 3692848b8605Smrg/** 3693848b8605Smrg * Unbind all uniform buffers in the range 3694848b8605Smrg * <first> through <first>+<count>-1 3695848b8605Smrg */ 3696848b8605Smrgstatic void 3697848b8605Smrgunbind_uniform_buffers(struct gl_context *ctx, GLuint first, GLsizei count) 3698848b8605Smrg{ 3699848b8605Smrg struct gl_buffer_object *bufObj = ctx->Shared->NullBufferObj; 3700848b8605Smrg 3701b8e80941Smrg for (int i = 0; i < count; i++) 3702b8e80941Smrg set_buffer_binding(ctx, &ctx->UniformBufferBindings[first + i], 3703b8e80941Smrg bufObj, -1, -1, GL_TRUE, 0); 3704848b8605Smrg} 3705848b8605Smrg 3706b8e80941Smrg/** 3707b8e80941Smrg * Unbind all shader storage buffers in the range 3708b8e80941Smrg * <first> through <first>+<count>-1 3709b8e80941Smrg */ 3710848b8605Smrgstatic void 3711b8e80941Smrgunbind_shader_storage_buffers(struct gl_context *ctx, GLuint first, 3712b8e80941Smrg GLsizei count) 3713848b8605Smrg{ 3714b8e80941Smrg struct gl_buffer_object *bufObj = ctx->Shared->NullBufferObj; 3715b8e80941Smrg 3716b8e80941Smrg for (int i = 0; i < count; i++) 3717b8e80941Smrg set_buffer_binding(ctx, &ctx->ShaderStorageBufferBindings[first + i], 3718b8e80941Smrg bufObj, -1, -1, GL_TRUE, 0); 3719b8e80941Smrg} 3720848b8605Smrg 3721b8e80941Smrgstatic void 3722b8e80941Smrgbind_uniform_buffers(struct gl_context *ctx, GLuint first, GLsizei count, 3723b8e80941Smrg const GLuint *buffers, 3724b8e80941Smrg bool range, 3725b8e80941Smrg const GLintptr *offsets, const GLsizeiptr *sizes, 3726b8e80941Smrg const char *caller) 3727b8e80941Smrg{ 3728b8e80941Smrg if (!error_check_bind_uniform_buffers(ctx, first, count, caller)) 3729848b8605Smrg return; 3730848b8605Smrg 3731848b8605Smrg /* Assume that at least one binding will be changed */ 3732848b8605Smrg FLUSH_VERTICES(ctx, 0); 3733848b8605Smrg ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer; 3734848b8605Smrg 3735848b8605Smrg if (!buffers) { 3736848b8605Smrg /* The ARB_multi_bind spec says: 3737848b8605Smrg * 3738b8e80941Smrg * "If <buffers> is NULL, all bindings from <first> through 3739b8e80941Smrg * <first>+<count>-1 are reset to their unbound (zero) state. 3740b8e80941Smrg * In this case, the offsets and sizes associated with the 3741b8e80941Smrg * binding points are set to default values, ignoring 3742b8e80941Smrg * <offsets> and <sizes>." 3743848b8605Smrg */ 3744848b8605Smrg unbind_uniform_buffers(ctx, first, count); 3745848b8605Smrg return; 3746848b8605Smrg } 3747848b8605Smrg 3748848b8605Smrg /* Note that the error semantics for multi-bind commands differ from 3749848b8605Smrg * those of other GL commands. 3750848b8605Smrg * 3751848b8605Smrg * The Issues section in the ARB_multi_bind spec says: 3752848b8605Smrg * 3753848b8605Smrg * "(11) Typically, OpenGL specifies that if an error is generated by a 3754848b8605Smrg * command, that command has no effect. This is somewhat 3755848b8605Smrg * unfortunate for multi-bind commands, because it would require a 3756848b8605Smrg * first pass to scan the entire list of bound objects for errors 3757848b8605Smrg * and then a second pass to actually perform the bindings. 3758848b8605Smrg * Should we have different error semantics? 3759848b8605Smrg * 3760848b8605Smrg * RESOLVED: Yes. In this specification, when the parameters for 3761848b8605Smrg * one of the <count> binding points are invalid, that binding point 3762848b8605Smrg * is not updated and an error will be generated. However, other 3763848b8605Smrg * binding points in the same command will be updated if their 3764848b8605Smrg * parameters are valid and no other error occurs." 3765848b8605Smrg */ 3766848b8605Smrg 3767b8e80941Smrg _mesa_HashLockMutex(ctx->Shared->BufferObjects); 3768848b8605Smrg 3769b8e80941Smrg for (int i = 0; i < count; i++) { 3770b8e80941Smrg struct gl_buffer_binding *binding = 3771b8e80941Smrg &ctx->UniformBufferBindings[first + i]; 3772b8e80941Smrg GLintptr offset = 0; 3773b8e80941Smrg GLsizeiptr size = 0; 3774848b8605Smrg 3775b8e80941Smrg if (range) { 3776b8e80941Smrg if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes)) 3777b8e80941Smrg continue; 3778848b8605Smrg 3779b8e80941Smrg /* The ARB_multi_bind spec says: 3780b8e80941Smrg * 3781b8e80941Smrg * "An INVALID_VALUE error is generated by BindBuffersRange if any 3782b8e80941Smrg * pair of values in <offsets> and <sizes> does not respectively 3783b8e80941Smrg * satisfy the constraints described for those parameters for the 3784b8e80941Smrg * specified target, as described in section 6.7.1 (per binding)." 3785b8e80941Smrg * 3786b8e80941Smrg * Section 6.7.1 refers to table 6.5, which says: 3787b8e80941Smrg * 3788b8e80941Smrg * "┌───────────────────────────────────────────────────────────────┐ 3789b8e80941Smrg * │ Uniform buffer array bindings (see sec. 7.6) │ 3790b8e80941Smrg * ├─────────────────────┬─────────────────────────────────────────┤ 3791b8e80941Smrg * │ ... │ ... │ 3792b8e80941Smrg * │ offset restriction │ multiple of value of UNIFORM_BUFFER_- │ 3793b8e80941Smrg * │ │ OFFSET_ALIGNMENT │ 3794b8e80941Smrg * │ ... │ ... │ 3795b8e80941Smrg * │ size restriction │ none │ 3796b8e80941Smrg * └─────────────────────┴─────────────────────────────────────────┘" 3797b8e80941Smrg */ 3798b8e80941Smrg if (offsets[i] & (ctx->Const.UniformBufferOffsetAlignment - 1)) { 3799b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3800b8e80941Smrg "glBindBuffersRange(offsets[%u]=%" PRId64 3801b8e80941Smrg " is misaligned; it must be a multiple of the value of " 3802b8e80941Smrg "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT=%u when " 3803b8e80941Smrg "target=GL_UNIFORM_BUFFER)", 3804b8e80941Smrg i, (int64_t) offsets[i], 3805b8e80941Smrg ctx->Const.UniformBufferOffsetAlignment); 3806b8e80941Smrg continue; 3807b8e80941Smrg } 3808b8e80941Smrg 3809b8e80941Smrg offset = offsets[i]; 3810b8e80941Smrg size = sizes[i]; 3811848b8605Smrg } 3812b8e80941Smrg 3813b8e80941Smrg set_buffer_multi_binding(ctx, buffers, i, caller, 3814b8e80941Smrg binding, offset, size, range, 3815b8e80941Smrg USAGE_UNIFORM_BUFFER); 3816848b8605Smrg } 3817848b8605Smrg 3818b8e80941Smrg _mesa_HashUnlockMutex(ctx->Shared->BufferObjects); 3819848b8605Smrg} 3820848b8605Smrg 3821848b8605Smrgstatic void 3822b8e80941Smrgbind_shader_storage_buffers(struct gl_context *ctx, GLuint first, 3823b8e80941Smrg GLsizei count, const GLuint *buffers, 3824b8e80941Smrg bool range, 3825b8e80941Smrg const GLintptr *offsets, 3826b8e80941Smrg const GLsizeiptr *sizes, 3827b8e80941Smrg const char *caller) 3828848b8605Smrg{ 3829b8e80941Smrg if (!error_check_bind_shader_storage_buffers(ctx, first, count, caller)) 3830848b8605Smrg return; 3831848b8605Smrg 3832848b8605Smrg /* Assume that at least one binding will be changed */ 3833848b8605Smrg FLUSH_VERTICES(ctx, 0); 3834b8e80941Smrg ctx->NewDriverState |= ctx->DriverFlags.NewShaderStorageBuffer; 3835848b8605Smrg 3836848b8605Smrg if (!buffers) { 3837848b8605Smrg /* The ARB_multi_bind spec says: 3838848b8605Smrg * 3839848b8605Smrg * "If <buffers> is NULL, all bindings from <first> through 3840848b8605Smrg * <first>+<count>-1 are reset to their unbound (zero) state. 3841848b8605Smrg * In this case, the offsets and sizes associated with the 3842848b8605Smrg * binding points are set to default values, ignoring 3843848b8605Smrg * <offsets> and <sizes>." 3844848b8605Smrg */ 3845b8e80941Smrg unbind_shader_storage_buffers(ctx, first, count); 3846848b8605Smrg return; 3847848b8605Smrg } 3848848b8605Smrg 3849848b8605Smrg /* Note that the error semantics for multi-bind commands differ from 3850848b8605Smrg * those of other GL commands. 3851848b8605Smrg * 3852848b8605Smrg * The Issues section in the ARB_multi_bind spec says: 3853848b8605Smrg * 3854848b8605Smrg * "(11) Typically, OpenGL specifies that if an error is generated by a 3855848b8605Smrg * command, that command has no effect. This is somewhat 3856848b8605Smrg * unfortunate for multi-bind commands, because it would require a 3857848b8605Smrg * first pass to scan the entire list of bound objects for errors 3858848b8605Smrg * and then a second pass to actually perform the bindings. 3859848b8605Smrg * Should we have different error semantics? 3860848b8605Smrg * 3861848b8605Smrg * RESOLVED: Yes. In this specification, when the parameters for 3862848b8605Smrg * one of the <count> binding points are invalid, that binding point 3863848b8605Smrg * is not updated and an error will be generated. However, other 3864848b8605Smrg * binding points in the same command will be updated if their 3865848b8605Smrg * parameters are valid and no other error occurs." 3866848b8605Smrg */ 3867848b8605Smrg 3868b8e80941Smrg _mesa_HashLockMutex(ctx->Shared->BufferObjects); 3869848b8605Smrg 3870b8e80941Smrg for (int i = 0; i < count; i++) { 3871b8e80941Smrg struct gl_buffer_binding *binding = 3872b8e80941Smrg &ctx->ShaderStorageBufferBindings[first + i]; 3873b8e80941Smrg GLintptr offset = 0; 3874b8e80941Smrg GLsizeiptr size = 0; 3875b8e80941Smrg 3876b8e80941Smrg if (range) { 3877b8e80941Smrg if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes)) 3878b8e80941Smrg continue; 3879b8e80941Smrg 3880b8e80941Smrg /* The ARB_multi_bind spec says: 3881b8e80941Smrg * 3882b8e80941Smrg * "An INVALID_VALUE error is generated by BindBuffersRange if any 3883b8e80941Smrg * pair of values in <offsets> and <sizes> does not respectively 3884b8e80941Smrg * satisfy the constraints described for those parameters for the 3885b8e80941Smrg * specified target, as described in section 6.7.1 (per binding)." 3886b8e80941Smrg * 3887b8e80941Smrg * Section 6.7.1 refers to table 6.5, which says: 3888b8e80941Smrg * 3889b8e80941Smrg * "┌───────────────────────────────────────────────────────────────┐ 3890b8e80941Smrg * │ Shader storage buffer array bindings (see sec. 7.8) │ 3891b8e80941Smrg * ├─────────────────────┬─────────────────────────────────────────┤ 3892b8e80941Smrg * │ ... │ ... │ 3893b8e80941Smrg * │ offset restriction │ multiple of value of SHADER_STORAGE_- │ 3894b8e80941Smrg * │ │ BUFFER_OFFSET_ALIGNMENT │ 3895b8e80941Smrg * │ ... │ ... │ 3896b8e80941Smrg * │ size restriction │ none │ 3897b8e80941Smrg * └─────────────────────┴─────────────────────────────────────────┘" 3898b8e80941Smrg */ 3899b8e80941Smrg if (offsets[i] & (ctx->Const.ShaderStorageBufferOffsetAlignment - 1)) { 3900b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, 3901b8e80941Smrg "glBindBuffersRange(offsets[%u]=%" PRId64 3902b8e80941Smrg " is misaligned; it must be a multiple of the value of " 3903b8e80941Smrg "GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT=%u when " 3904b8e80941Smrg "target=GL_SHADER_STORAGE_BUFFER)", 3905b8e80941Smrg i, (int64_t) offsets[i], 3906b8e80941Smrg ctx->Const.ShaderStorageBufferOffsetAlignment); 3907b8e80941Smrg continue; 3908b8e80941Smrg } 3909848b8605Smrg 3910b8e80941Smrg offset = offsets[i]; 3911b8e80941Smrg size = sizes[i]; 3912848b8605Smrg } 3913848b8605Smrg 3914b8e80941Smrg set_buffer_multi_binding(ctx, buffers, i, caller, 3915b8e80941Smrg binding, offset, size, range, 3916b8e80941Smrg USAGE_SHADER_STORAGE_BUFFER); 3917848b8605Smrg } 3918848b8605Smrg 3919b8e80941Smrg _mesa_HashUnlockMutex(ctx->Shared->BufferObjects); 3920848b8605Smrg} 3921848b8605Smrg 3922848b8605Smrgstatic bool 3923848b8605Smrgerror_check_bind_xfb_buffers(struct gl_context *ctx, 3924848b8605Smrg struct gl_transform_feedback_object *tfObj, 3925848b8605Smrg GLuint first, GLsizei count, const char *caller) 3926848b8605Smrg{ 3927848b8605Smrg if (!ctx->Extensions.EXT_transform_feedback) { 3928848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, 3929848b8605Smrg "%s(target=GL_TRANSFORM_FEEDBACK_BUFFER)", caller); 3930848b8605Smrg return false; 3931848b8605Smrg } 3932848b8605Smrg 3933848b8605Smrg /* Page 398 of the PDF of the OpenGL 4.4 (Core Profile) spec says: 3934848b8605Smrg * 3935848b8605Smrg * "An INVALID_OPERATION error is generated : 3936848b8605Smrg * 3937848b8605Smrg * ... 3938848b8605Smrg * • by BindBufferRange or BindBufferBase if target is TRANSFORM_- 3939b8e80941Smrg * FEEDBACK_BUFFER and transform feedback is currently active." 3940b8e80941Smrg * 3941b8e80941Smrg * We assume that this is also meant to apply to BindBuffersRange 3942b8e80941Smrg * and BindBuffersBase. 3943848b8605Smrg */ 3944b8e80941Smrg if (tfObj->Active) { 3945b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3946b8e80941Smrg "%s(Changing transform feedback buffers while " 3947b8e80941Smrg "transform feedback is active)", caller); 3948b8e80941Smrg return false; 3949b8e80941Smrg } 3950848b8605Smrg 3951b8e80941Smrg /* The ARB_multi_bind_spec says: 3952b8e80941Smrg * 3953b8e80941Smrg * "An INVALID_OPERATION error is generated if <first> + <count> is 3954b8e80941Smrg * greater than the number of target-specific indexed binding points, 3955b8e80941Smrg * as described in section 6.7.1." 3956b8e80941Smrg */ 3957b8e80941Smrg if (first + count > ctx->Const.MaxTransformFeedbackBuffers) { 3958b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 3959b8e80941Smrg "%s(first=%u + count=%d > the value of " 3960b8e80941Smrg "GL_MAX_TRANSFORM_FEEDBACK_BUFFERS=%u)", 3961b8e80941Smrg caller, first, count, 3962b8e80941Smrg ctx->Const.MaxTransformFeedbackBuffers); 3963b8e80941Smrg return false; 3964b8e80941Smrg } 3965848b8605Smrg 3966b8e80941Smrg return true; 3967b8e80941Smrg} 3968848b8605Smrg 3969b8e80941Smrg/** 3970b8e80941Smrg * Unbind all transform feedback buffers in the range 3971b8e80941Smrg * <first> through <first>+<count>-1 3972b8e80941Smrg */ 3973b8e80941Smrgstatic void 3974b8e80941Smrgunbind_xfb_buffers(struct gl_context *ctx, 3975b8e80941Smrg struct gl_transform_feedback_object *tfObj, 3976b8e80941Smrg GLuint first, GLsizei count) 3977b8e80941Smrg{ 3978b8e80941Smrg struct gl_buffer_object * const bufObj = ctx->Shared->NullBufferObj; 3979848b8605Smrg 3980b8e80941Smrg for (int i = 0; i < count; i++) 3981b8e80941Smrg _mesa_set_transform_feedback_binding(ctx, tfObj, first + i, 3982b8e80941Smrg bufObj, 0, 0); 3983848b8605Smrg} 3984848b8605Smrg 3985848b8605Smrgstatic void 3986b8e80941Smrgbind_xfb_buffers(struct gl_context *ctx, 3987b8e80941Smrg GLuint first, GLsizei count, 3988b8e80941Smrg const GLuint *buffers, 3989b8e80941Smrg bool range, 3990b8e80941Smrg const GLintptr *offsets, 3991b8e80941Smrg const GLsizeiptr *sizes, 3992b8e80941Smrg const char *caller) 3993848b8605Smrg{ 3994848b8605Smrg struct gl_transform_feedback_object *tfObj = 3995848b8605Smrg ctx->TransformFeedback.CurrentObject; 3996848b8605Smrg 3997b8e80941Smrg if (!error_check_bind_xfb_buffers(ctx, tfObj, first, count, caller)) 3998848b8605Smrg return; 3999848b8605Smrg 4000848b8605Smrg /* Assume that at least one binding will be changed */ 4001848b8605Smrg FLUSH_VERTICES(ctx, 0); 4002848b8605Smrg ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback; 4003848b8605Smrg 4004848b8605Smrg if (!buffers) { 4005848b8605Smrg /* The ARB_multi_bind spec says: 4006848b8605Smrg * 4007848b8605Smrg * "If <buffers> is NULL, all bindings from <first> through 4008848b8605Smrg * <first>+<count>-1 are reset to their unbound (zero) state. 4009848b8605Smrg * In this case, the offsets and sizes associated with the 4010848b8605Smrg * binding points are set to default values, ignoring 4011848b8605Smrg * <offsets> and <sizes>." 4012848b8605Smrg */ 4013848b8605Smrg unbind_xfb_buffers(ctx, tfObj, first, count); 4014848b8605Smrg return; 4015848b8605Smrg } 4016848b8605Smrg 4017848b8605Smrg /* Note that the error semantics for multi-bind commands differ from 4018848b8605Smrg * those of other GL commands. 4019848b8605Smrg * 4020848b8605Smrg * The Issues section in the ARB_multi_bind spec says: 4021848b8605Smrg * 4022848b8605Smrg * "(11) Typically, OpenGL specifies that if an error is generated by a 4023848b8605Smrg * command, that command has no effect. This is somewhat 4024848b8605Smrg * unfortunate for multi-bind commands, because it would require a 4025848b8605Smrg * first pass to scan the entire list of bound objects for errors 4026848b8605Smrg * and then a second pass to actually perform the bindings. 4027848b8605Smrg * Should we have different error semantics? 4028848b8605Smrg * 4029848b8605Smrg * RESOLVED: Yes. In this specification, when the parameters for 4030848b8605Smrg * one of the <count> binding points are invalid, that binding point 4031848b8605Smrg * is not updated and an error will be generated. However, other 4032848b8605Smrg * binding points in the same command will be updated if their 4033848b8605Smrg * parameters are valid and no other error occurs." 4034848b8605Smrg */ 4035848b8605Smrg 4036b8e80941Smrg _mesa_HashLockMutex(ctx->Shared->BufferObjects); 4037848b8605Smrg 4038b8e80941Smrg for (int i = 0; i < count; i++) { 4039848b8605Smrg const GLuint index = first + i; 4040848b8605Smrg struct gl_buffer_object * const boundBufObj = tfObj->Buffers[index]; 4041848b8605Smrg struct gl_buffer_object *bufObj; 4042b8e80941Smrg GLintptr offset = 0; 4043b8e80941Smrg GLsizeiptr size = 0; 4044848b8605Smrg 4045b8e80941Smrg if (range) { 4046b8e80941Smrg if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes)) 4047b8e80941Smrg continue; 4048848b8605Smrg 4049b8e80941Smrg /* The ARB_multi_bind spec says: 4050b8e80941Smrg * 4051b8e80941Smrg * "An INVALID_VALUE error is generated by BindBuffersRange if any 4052b8e80941Smrg * pair of values in <offsets> and <sizes> does not respectively 4053b8e80941Smrg * satisfy the constraints described for those parameters for the 4054b8e80941Smrg * specified target, as described in section 6.7.1 (per binding)." 4055b8e80941Smrg * 4056b8e80941Smrg * Section 6.7.1 refers to table 6.5, which says: 4057b8e80941Smrg * 4058b8e80941Smrg * "┌───────────────────────────────────────────────────────────────┐ 4059b8e80941Smrg * │ Transform feedback array bindings (see sec. 13.2.2) │ 4060b8e80941Smrg * ├───────────────────────┬───────────────────────────────────────┤ 4061b8e80941Smrg * │ ... │ ... │ 4062b8e80941Smrg * │ offset restriction │ multiple of 4 │ 4063b8e80941Smrg * │ ... │ ... │ 4064b8e80941Smrg * │ size restriction │ multiple of 4 │ 4065b8e80941Smrg * └───────────────────────┴───────────────────────────────────────┘" 4066b8e80941Smrg */ 4067b8e80941Smrg if (offsets[i] & 0x3) { 4068b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, 4069b8e80941Smrg "glBindBuffersRange(offsets[%u]=%" PRId64 4070b8e80941Smrg " is misaligned; it must be a multiple of 4 when " 4071b8e80941Smrg "target=GL_TRANSFORM_FEEDBACK_BUFFER)", 4072b8e80941Smrg i, (int64_t) offsets[i]); 4073b8e80941Smrg continue; 4074b8e80941Smrg } 4075848b8605Smrg 4076b8e80941Smrg if (sizes[i] & 0x3) { 4077b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, 4078b8e80941Smrg "glBindBuffersRange(sizes[%u]=%" PRId64 4079b8e80941Smrg " is misaligned; it must be a multiple of 4 when " 4080b8e80941Smrg "target=GL_TRANSFORM_FEEDBACK_BUFFER)", 4081b8e80941Smrg i, (int64_t) sizes[i]); 4082b8e80941Smrg continue; 4083b8e80941Smrg } 4084b8e80941Smrg 4085b8e80941Smrg offset = offsets[i]; 4086b8e80941Smrg size = sizes[i]; 4087848b8605Smrg } 4088848b8605Smrg 4089848b8605Smrg if (boundBufObj && boundBufObj->Name == buffers[i]) 4090848b8605Smrg bufObj = boundBufObj; 4091848b8605Smrg else 4092b8e80941Smrg bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, caller); 4093848b8605Smrg 4094848b8605Smrg if (bufObj) 4095848b8605Smrg _mesa_set_transform_feedback_binding(ctx, tfObj, index, bufObj, 4096b8e80941Smrg offset, size); 4097848b8605Smrg } 4098848b8605Smrg 4099b8e80941Smrg _mesa_HashUnlockMutex(ctx->Shared->BufferObjects); 4100848b8605Smrg} 4101848b8605Smrg 4102848b8605Smrgstatic bool 4103848b8605Smrgerror_check_bind_atomic_buffers(struct gl_context *ctx, 4104848b8605Smrg GLuint first, GLsizei count, 4105848b8605Smrg const char *caller) 4106848b8605Smrg{ 4107848b8605Smrg if (!ctx->Extensions.ARB_shader_atomic_counters) { 4108848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, 4109848b8605Smrg "%s(target=GL_ATOMIC_COUNTER_BUFFER)", caller); 4110848b8605Smrg return false; 4111848b8605Smrg } 4112848b8605Smrg 4113848b8605Smrg /* The ARB_multi_bind_spec says: 4114848b8605Smrg * 4115848b8605Smrg * "An INVALID_OPERATION error is generated if <first> + <count> is 4116848b8605Smrg * greater than the number of target-specific indexed binding points, 4117848b8605Smrg * as described in section 6.7.1." 4118848b8605Smrg */ 4119848b8605Smrg if (first + count > ctx->Const.MaxAtomicBufferBindings) { 4120848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 4121848b8605Smrg "%s(first=%u + count=%d > the value of " 4122848b8605Smrg "GL_MAX_ATOMIC_BUFFER_BINDINGS=%u)", 4123848b8605Smrg caller, first, count, ctx->Const.MaxAtomicBufferBindings); 4124848b8605Smrg return false; 4125848b8605Smrg } 4126848b8605Smrg 4127848b8605Smrg return true; 4128848b8605Smrg} 4129848b8605Smrg 4130848b8605Smrg/** 4131848b8605Smrg * Unbind all atomic counter buffers in the range 4132848b8605Smrg * <first> through <first>+<count>-1 4133848b8605Smrg */ 4134848b8605Smrgstatic void 4135848b8605Smrgunbind_atomic_buffers(struct gl_context *ctx, GLuint first, GLsizei count) 4136848b8605Smrg{ 4137848b8605Smrg struct gl_buffer_object * const bufObj = ctx->Shared->NullBufferObj; 4138848b8605Smrg 4139b8e80941Smrg for (int i = 0; i < count; i++) 4140b8e80941Smrg set_buffer_binding(ctx, &ctx->AtomicBufferBindings[first + i], 4141b8e80941Smrg bufObj, -1, -1, GL_TRUE, 0); 4142848b8605Smrg} 4143848b8605Smrg 4144848b8605Smrgstatic void 4145b8e80941Smrgbind_atomic_buffers(struct gl_context *ctx, 4146b8e80941Smrg GLuint first, 4147b8e80941Smrg GLsizei count, 4148b8e80941Smrg const GLuint *buffers, 4149b8e80941Smrg bool range, 4150b8e80941Smrg const GLintptr *offsets, 4151b8e80941Smrg const GLsizeiptr *sizes, 4152b8e80941Smrg const char *caller) 4153848b8605Smrg{ 4154b8e80941Smrg if (!error_check_bind_atomic_buffers(ctx, first, count, caller)) 4155848b8605Smrg return; 4156848b8605Smrg 4157848b8605Smrg /* Assume that at least one binding will be changed */ 4158848b8605Smrg FLUSH_VERTICES(ctx, 0); 4159848b8605Smrg ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer; 4160848b8605Smrg 4161848b8605Smrg if (!buffers) { 4162848b8605Smrg /* The ARB_multi_bind spec says: 4163848b8605Smrg * 4164848b8605Smrg * "If <buffers> is NULL, all bindings from <first> through 4165848b8605Smrg * <first>+<count>-1 are reset to their unbound (zero) state. 4166848b8605Smrg * In this case, the offsets and sizes associated with the 4167848b8605Smrg * binding points are set to default values, ignoring 4168848b8605Smrg * <offsets> and <sizes>." 4169848b8605Smrg */ 4170848b8605Smrg unbind_atomic_buffers(ctx, first, count); 4171848b8605Smrg return; 4172848b8605Smrg } 4173848b8605Smrg 4174848b8605Smrg /* Note that the error semantics for multi-bind commands differ from 4175848b8605Smrg * those of other GL commands. 4176848b8605Smrg * 4177848b8605Smrg * The Issues section in the ARB_multi_bind spec says: 4178848b8605Smrg * 4179848b8605Smrg * "(11) Typically, OpenGL specifies that if an error is generated by a 4180848b8605Smrg * command, that command has no effect. This is somewhat 4181848b8605Smrg * unfortunate for multi-bind commands, because it would require a 4182848b8605Smrg * first pass to scan the entire list of bound objects for errors 4183848b8605Smrg * and then a second pass to actually perform the bindings. 4184848b8605Smrg * Should we have different error semantics? 4185848b8605Smrg * 4186848b8605Smrg * RESOLVED: Yes. In this specification, when the parameters for 4187848b8605Smrg * one of the <count> binding points are invalid, that binding point 4188848b8605Smrg * is not updated and an error will be generated. However, other 4189848b8605Smrg * binding points in the same command will be updated if their 4190848b8605Smrg * parameters are valid and no other error occurs." 4191848b8605Smrg */ 4192848b8605Smrg 4193b8e80941Smrg _mesa_HashLockMutex(ctx->Shared->BufferObjects); 4194848b8605Smrg 4195b8e80941Smrg for (int i = 0; i < count; i++) { 4196b8e80941Smrg struct gl_buffer_binding *binding = 4197848b8605Smrg &ctx->AtomicBufferBindings[first + i]; 4198b8e80941Smrg GLintptr offset = 0; 4199b8e80941Smrg GLsizeiptr size = 0; 4200848b8605Smrg 4201b8e80941Smrg if (range) { 4202b8e80941Smrg if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes)) 4203b8e80941Smrg continue; 4204848b8605Smrg 4205b8e80941Smrg /* The ARB_multi_bind spec says: 4206b8e80941Smrg * 4207b8e80941Smrg * "An INVALID_VALUE error is generated by BindBuffersRange if any 4208b8e80941Smrg * pair of values in <offsets> and <sizes> does not respectively 4209b8e80941Smrg * satisfy the constraints described for those parameters for the 4210b8e80941Smrg * specified target, as described in section 6.7.1 (per binding)." 4211b8e80941Smrg * 4212b8e80941Smrg * Section 6.7.1 refers to table 6.5, which says: 4213b8e80941Smrg * 4214b8e80941Smrg * "┌───────────────────────────────────────────────────────────────┐ 4215b8e80941Smrg * │ Atomic counter array bindings (see sec. 7.7.2) │ 4216b8e80941Smrg * ├───────────────────────┬───────────────────────────────────────┤ 4217b8e80941Smrg * │ ... │ ... │ 4218b8e80941Smrg * │ offset restriction │ multiple of 4 │ 4219b8e80941Smrg * │ ... │ ... │ 4220b8e80941Smrg * │ size restriction │ none │ 4221b8e80941Smrg * └───────────────────────┴───────────────────────────────────────┘" 4222b8e80941Smrg */ 4223b8e80941Smrg if (offsets[i] & (ATOMIC_COUNTER_SIZE - 1)) { 4224b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, 4225b8e80941Smrg "glBindBuffersRange(offsets[%u]=%" PRId64 4226b8e80941Smrg " is misaligned; it must be a multiple of %d when " 4227b8e80941Smrg "target=GL_ATOMIC_COUNTER_BUFFER)", 4228b8e80941Smrg i, (int64_t) offsets[i], ATOMIC_COUNTER_SIZE); 4229b8e80941Smrg continue; 4230b8e80941Smrg } 4231848b8605Smrg 4232b8e80941Smrg offset = offsets[i]; 4233b8e80941Smrg size = sizes[i]; 4234b8e80941Smrg } 4235848b8605Smrg 4236b8e80941Smrg set_buffer_multi_binding(ctx, buffers, i, caller, 4237b8e80941Smrg binding, offset, size, range, 4238b8e80941Smrg USAGE_ATOMIC_COUNTER_BUFFER); 4239848b8605Smrg } 4240848b8605Smrg 4241b8e80941Smrg _mesa_HashUnlockMutex(ctx->Shared->BufferObjects); 4242848b8605Smrg} 4243848b8605Smrg 4244b8e80941Smrgstatic ALWAYS_INLINE void 4245b8e80941Smrgbind_buffer_range(GLenum target, GLuint index, GLuint buffer, GLintptr offset, 4246b8e80941Smrg GLsizeiptr size, bool no_error) 4247848b8605Smrg{ 4248848b8605Smrg GET_CURRENT_CONTEXT(ctx); 4249848b8605Smrg struct gl_buffer_object *bufObj; 4250848b8605Smrg 4251b8e80941Smrg if (MESA_VERBOSE & VERBOSE_API) { 4252b8e80941Smrg _mesa_debug(ctx, "glBindBufferRange(%s, %u, %u, %lu, %lu)\n", 4253b8e80941Smrg _mesa_enum_to_string(target), index, buffer, 4254b8e80941Smrg (unsigned long) offset, (unsigned long) size); 4255b8e80941Smrg } 4256b8e80941Smrg 4257848b8605Smrg if (buffer == 0) { 4258848b8605Smrg bufObj = ctx->Shared->NullBufferObj; 4259848b8605Smrg } else { 4260848b8605Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 4261b8e80941Smrg if (!_mesa_handle_bind_buffer_gen(ctx, buffer, 4262b8e80941Smrg &bufObj, "glBindBufferRange")) 4263b8e80941Smrg return; 4264848b8605Smrg 4265b8e80941Smrg if (!no_error && !bufObj) { 4266b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 4267b8e80941Smrg "glBindBufferRange(invalid buffer=%u)", buffer); 4268b8e80941Smrg return; 4269b8e80941Smrg } 4270848b8605Smrg } 4271848b8605Smrg 4272b8e80941Smrg if (no_error) { 4273b8e80941Smrg switch (target) { 4274b8e80941Smrg case GL_TRANSFORM_FEEDBACK_BUFFER: 4275b8e80941Smrg _mesa_bind_buffer_range_xfb(ctx, ctx->TransformFeedback.CurrentObject, 4276b8e80941Smrg index, bufObj, offset, size); 4277848b8605Smrg return; 4278b8e80941Smrg case GL_UNIFORM_BUFFER: 4279b8e80941Smrg bind_buffer_range_uniform_buffer(ctx, index, bufObj, offset, size); 4280b8e80941Smrg return; 4281b8e80941Smrg case GL_SHADER_STORAGE_BUFFER: 4282b8e80941Smrg bind_buffer_range_shader_storage_buffer(ctx, index, bufObj, offset, 4283b8e80941Smrg size); 4284b8e80941Smrg return; 4285b8e80941Smrg case GL_ATOMIC_COUNTER_BUFFER: 4286b8e80941Smrg bind_buffer_range_atomic_buffer(ctx, index, bufObj, offset, size); 4287b8e80941Smrg return; 4288b8e80941Smrg default: 4289b8e80941Smrg unreachable("invalid BindBufferRange target with KHR_no_error"); 4290b8e80941Smrg } 4291b8e80941Smrg } else { 4292b8e80941Smrg if (buffer != 0) { 4293b8e80941Smrg if (size <= 0) { 4294b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(size=%d)", 4295b8e80941Smrg (int) size); 4296b8e80941Smrg return; 4297b8e80941Smrg } 4298848b8605Smrg } 4299848b8605Smrg 4300b8e80941Smrg switch (target) { 4301b8e80941Smrg case GL_TRANSFORM_FEEDBACK_BUFFER: 4302b8e80941Smrg if (!_mesa_validate_buffer_range_xfb(ctx, 4303b8e80941Smrg ctx->TransformFeedback.CurrentObject, 4304b8e80941Smrg index, bufObj, offset, size, 4305b8e80941Smrg false)) 4306b8e80941Smrg return; 4307b8e80941Smrg 4308b8e80941Smrg _mesa_bind_buffer_range_xfb(ctx, ctx->TransformFeedback.CurrentObject, 4309b8e80941Smrg index, bufObj, offset, size); 4310b8e80941Smrg return; 4311b8e80941Smrg case GL_UNIFORM_BUFFER: 4312b8e80941Smrg bind_buffer_range_uniform_buffer_err(ctx, index, bufObj, offset, 4313b8e80941Smrg size); 4314b8e80941Smrg return; 4315b8e80941Smrg case GL_SHADER_STORAGE_BUFFER: 4316b8e80941Smrg bind_buffer_range_shader_storage_buffer_err(ctx, index, bufObj, 4317b8e80941Smrg offset, size); 4318b8e80941Smrg return; 4319b8e80941Smrg case GL_ATOMIC_COUNTER_BUFFER: 4320b8e80941Smrg bind_buffer_range_atomic_buffer_err(ctx, index, bufObj, 4321b8e80941Smrg offset, size); 4322b8e80941Smrg return; 4323b8e80941Smrg default: 4324b8e80941Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferRange(target)"); 4325b8e80941Smrg return; 4326b8e80941Smrg } 4327848b8605Smrg } 4328848b8605Smrg} 4329848b8605Smrg 4330b8e80941Smrgvoid GLAPIENTRY 4331b8e80941Smrg_mesa_BindBufferRange_no_error(GLenum target, GLuint index, GLuint buffer, 4332b8e80941Smrg GLintptr offset, GLsizeiptr size) 4333b8e80941Smrg{ 4334b8e80941Smrg bind_buffer_range(target, index, buffer, offset, size, true); 4335b8e80941Smrg} 4336b8e80941Smrg 4337b8e80941Smrgvoid GLAPIENTRY 4338b8e80941Smrg_mesa_BindBufferRange(GLenum target, GLuint index, 4339b8e80941Smrg GLuint buffer, GLintptr offset, GLsizeiptr size) 4340b8e80941Smrg{ 4341b8e80941Smrg bind_buffer_range(target, index, buffer, offset, size, false); 4342b8e80941Smrg} 4343b8e80941Smrg 4344848b8605Smrgvoid GLAPIENTRY 4345848b8605Smrg_mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer) 4346848b8605Smrg{ 4347848b8605Smrg GET_CURRENT_CONTEXT(ctx); 4348848b8605Smrg struct gl_buffer_object *bufObj; 4349848b8605Smrg 4350b8e80941Smrg if (MESA_VERBOSE & VERBOSE_API) { 4351b8e80941Smrg _mesa_debug(ctx, "glBindBufferBase(%s, %u, %u)\n", 4352b8e80941Smrg _mesa_enum_to_string(target), index, buffer); 4353b8e80941Smrg } 4354b8e80941Smrg 4355848b8605Smrg if (buffer == 0) { 4356848b8605Smrg bufObj = ctx->Shared->NullBufferObj; 4357848b8605Smrg } else { 4358848b8605Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 4359b8e80941Smrg if (!_mesa_handle_bind_buffer_gen(ctx, buffer, 4360b8e80941Smrg &bufObj, "glBindBufferBase")) 4361b8e80941Smrg return; 4362848b8605Smrg 4363b8e80941Smrg if (!bufObj) { 4364b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 4365b8e80941Smrg "glBindBufferBase(invalid buffer=%u)", buffer); 4366b8e80941Smrg return; 4367b8e80941Smrg } 4368848b8605Smrg } 4369848b8605Smrg 4370848b8605Smrg /* Note that there's some oddness in the GL 3.1-GL 3.3 specifications with 4371848b8605Smrg * regards to BindBufferBase. It says (GL 3.1 core spec, page 63): 4372848b8605Smrg * 4373848b8605Smrg * "BindBufferBase is equivalent to calling BindBufferRange with offset 4374848b8605Smrg * zero and size equal to the size of buffer." 4375848b8605Smrg * 4376848b8605Smrg * but it says for glGetIntegeri_v (GL 3.1 core spec, page 230): 4377848b8605Smrg * 4378848b8605Smrg * "If the parameter (starting offset or size) was not specified when the 4379848b8605Smrg * buffer object was bound, zero is returned." 4380848b8605Smrg * 4381848b8605Smrg * What happens if the size of the buffer changes? Does the size of the 4382848b8605Smrg * buffer at the moment glBindBufferBase was called still play a role, like 4383848b8605Smrg * the first quote would imply, or is the size meaningless in the 4384848b8605Smrg * glBindBufferBase case like the second quote would suggest? The GL 4.1 4385848b8605Smrg * core spec page 45 says: 4386848b8605Smrg * 4387848b8605Smrg * "It is equivalent to calling BindBufferRange with offset zero, while 4388848b8605Smrg * size is determined by the size of the bound buffer at the time the 4389848b8605Smrg * binding is used." 4390848b8605Smrg * 4391848b8605Smrg * My interpretation is that the GL 4.1 spec was a clarification of the 4392848b8605Smrg * behavior, not a change. In particular, this choice will only make 4393848b8605Smrg * rendering work in cases where it would have had undefined results. 4394848b8605Smrg */ 4395848b8605Smrg 4396848b8605Smrg switch (target) { 4397848b8605Smrg case GL_TRANSFORM_FEEDBACK_BUFFER: 4398b8e80941Smrg _mesa_bind_buffer_base_transform_feedback(ctx, 4399b8e80941Smrg ctx->TransformFeedback.CurrentObject, 4400b8e80941Smrg index, bufObj, false); 4401848b8605Smrg return; 4402848b8605Smrg case GL_UNIFORM_BUFFER: 4403848b8605Smrg bind_buffer_base_uniform_buffer(ctx, index, bufObj); 4404848b8605Smrg return; 4405b8e80941Smrg case GL_SHADER_STORAGE_BUFFER: 4406b8e80941Smrg bind_buffer_base_shader_storage_buffer(ctx, index, bufObj); 4407b8e80941Smrg return; 4408848b8605Smrg case GL_ATOMIC_COUNTER_BUFFER: 4409b8e80941Smrg bind_buffer_base_atomic_buffer(ctx, index, bufObj); 4410848b8605Smrg return; 4411848b8605Smrg default: 4412848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)"); 4413848b8605Smrg return; 4414848b8605Smrg } 4415848b8605Smrg} 4416848b8605Smrg 4417848b8605Smrgvoid GLAPIENTRY 4418848b8605Smrg_mesa_BindBuffersRange(GLenum target, GLuint first, GLsizei count, 4419848b8605Smrg const GLuint *buffers, 4420848b8605Smrg const GLintptr *offsets, const GLsizeiptr *sizes) 4421848b8605Smrg{ 4422848b8605Smrg GET_CURRENT_CONTEXT(ctx); 4423848b8605Smrg 4424b8e80941Smrg if (MESA_VERBOSE & VERBOSE_API) { 4425b8e80941Smrg _mesa_debug(ctx, "glBindBuffersRange(%s, %u, %d, %p, %p, %p)\n", 4426b8e80941Smrg _mesa_enum_to_string(target), first, count, 4427b8e80941Smrg buffers, offsets, sizes); 4428b8e80941Smrg } 4429b8e80941Smrg 4430848b8605Smrg switch (target) { 4431848b8605Smrg case GL_TRANSFORM_FEEDBACK_BUFFER: 4432b8e80941Smrg bind_xfb_buffers(ctx, first, count, buffers, true, offsets, sizes, 4433b8e80941Smrg "glBindBuffersRange"); 4434848b8605Smrg return; 4435848b8605Smrg case GL_UNIFORM_BUFFER: 4436b8e80941Smrg bind_uniform_buffers(ctx, first, count, buffers, true, offsets, sizes, 4437b8e80941Smrg "glBindBuffersRange"); 4438b8e80941Smrg return; 4439b8e80941Smrg case GL_SHADER_STORAGE_BUFFER: 4440b8e80941Smrg bind_shader_storage_buffers(ctx, first, count, buffers, true, offsets, sizes, 4441b8e80941Smrg "glBindBuffersRange"); 4442848b8605Smrg return; 4443848b8605Smrg case GL_ATOMIC_COUNTER_BUFFER: 4444b8e80941Smrg bind_atomic_buffers(ctx, first, count, buffers, true, offsets, sizes, 4445b8e80941Smrg "glBindBuffersRange"); 4446848b8605Smrg return; 4447848b8605Smrg default: 4448848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindBuffersRange(target=%s)", 4449b8e80941Smrg _mesa_enum_to_string(target)); 4450848b8605Smrg break; 4451848b8605Smrg } 4452848b8605Smrg} 4453848b8605Smrg 4454848b8605Smrgvoid GLAPIENTRY 4455848b8605Smrg_mesa_BindBuffersBase(GLenum target, GLuint first, GLsizei count, 4456848b8605Smrg const GLuint *buffers) 4457848b8605Smrg{ 4458848b8605Smrg GET_CURRENT_CONTEXT(ctx); 4459848b8605Smrg 4460b8e80941Smrg if (MESA_VERBOSE & VERBOSE_API) { 4461b8e80941Smrg _mesa_debug(ctx, "glBindBuffersBase(%s, %u, %d, %p)\n", 4462b8e80941Smrg _mesa_enum_to_string(target), first, count, buffers); 4463b8e80941Smrg } 4464b8e80941Smrg 4465848b8605Smrg switch (target) { 4466848b8605Smrg case GL_TRANSFORM_FEEDBACK_BUFFER: 4467b8e80941Smrg bind_xfb_buffers(ctx, first, count, buffers, false, NULL, NULL, 4468b8e80941Smrg "glBindBuffersBase"); 4469848b8605Smrg return; 4470848b8605Smrg case GL_UNIFORM_BUFFER: 4471b8e80941Smrg bind_uniform_buffers(ctx, first, count, buffers, false, NULL, NULL, 4472b8e80941Smrg "glBindBuffersBase"); 4473b8e80941Smrg return; 4474b8e80941Smrg case GL_SHADER_STORAGE_BUFFER: 4475b8e80941Smrg bind_shader_storage_buffers(ctx, first, count, buffers, false, NULL, NULL, 4476b8e80941Smrg "glBindBuffersBase"); 4477848b8605Smrg return; 4478848b8605Smrg case GL_ATOMIC_COUNTER_BUFFER: 4479b8e80941Smrg bind_atomic_buffers(ctx, first, count, buffers, false, NULL, NULL, 4480b8e80941Smrg "glBindBuffersBase"); 4481848b8605Smrg return; 4482848b8605Smrg default: 4483848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindBuffersBase(target=%s)", 4484b8e80941Smrg _mesa_enum_to_string(target)); 4485848b8605Smrg break; 4486848b8605Smrg } 4487848b8605Smrg} 4488848b8605Smrg 4489b8e80941Smrgstatic ALWAYS_INLINE void 4490b8e80941Smrginvalidate_buffer_subdata(struct gl_context *ctx, 4491b8e80941Smrg struct gl_buffer_object *bufObj, GLintptr offset, 4492b8e80941Smrg GLsizeiptr length) 4493b8e80941Smrg{ 4494b8e80941Smrg if (ctx->Driver.InvalidateBufferSubData) 4495b8e80941Smrg ctx->Driver.InvalidateBufferSubData(ctx, bufObj, offset, length); 4496b8e80941Smrg} 4497b8e80941Smrg 4498b8e80941Smrgvoid GLAPIENTRY 4499b8e80941Smrg_mesa_InvalidateBufferSubData_no_error(GLuint buffer, GLintptr offset, 4500b8e80941Smrg GLsizeiptr length) 4501b8e80941Smrg{ 4502b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 4503b8e80941Smrg 4504b8e80941Smrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 4505b8e80941Smrg invalidate_buffer_subdata(ctx, bufObj, offset, length); 4506b8e80941Smrg} 4507b8e80941Smrg 4508848b8605Smrgvoid GLAPIENTRY 4509848b8605Smrg_mesa_InvalidateBufferSubData(GLuint buffer, GLintptr offset, 4510848b8605Smrg GLsizeiptr length) 4511848b8605Smrg{ 4512848b8605Smrg GET_CURRENT_CONTEXT(ctx); 4513848b8605Smrg struct gl_buffer_object *bufObj; 4514848b8605Smrg const GLintptr end = offset + length; 4515848b8605Smrg 4516b8e80941Smrg /* Section 6.5 (Invalidating Buffer Data) of the OpenGL 4.5 (Compatibility 4517b8e80941Smrg * Profile) spec says: 4518b8e80941Smrg * 4519b8e80941Smrg * "An INVALID_VALUE error is generated if buffer is zero or is not the 4520b8e80941Smrg * name of an existing buffer object." 4521b8e80941Smrg */ 4522848b8605Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 4523b8e80941Smrg if (!bufObj || bufObj == &DummyBufferObject) { 4524848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 4525b8e80941Smrg "glInvalidateBufferSubData(name = %u) invalid object", 4526848b8605Smrg buffer); 4527848b8605Smrg return; 4528848b8605Smrg } 4529848b8605Smrg 4530848b8605Smrg /* The GL_ARB_invalidate_subdata spec says: 4531848b8605Smrg * 4532848b8605Smrg * "An INVALID_VALUE error is generated if <offset> or <length> is 4533848b8605Smrg * negative, or if <offset> + <length> is greater than the value of 4534848b8605Smrg * BUFFER_SIZE." 4535848b8605Smrg */ 4536b8e80941Smrg if (offset < 0 || length < 0 || end > bufObj->Size) { 4537848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 4538848b8605Smrg "glInvalidateBufferSubData(invalid offset or length)"); 4539848b8605Smrg return; 4540848b8605Smrg } 4541848b8605Smrg 4542848b8605Smrg /* The OpenGL 4.4 (Core Profile) spec says: 4543848b8605Smrg * 4544848b8605Smrg * "An INVALID_OPERATION error is generated if buffer is currently 4545848b8605Smrg * mapped by MapBuffer or if the invalidate range intersects the range 4546848b8605Smrg * currently mapped by MapBufferRange, unless it was mapped 4547848b8605Smrg * with MAP_PERSISTENT_BIT set in the MapBufferRange access flags." 4548848b8605Smrg */ 4549848b8605Smrg if (!(bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_PERSISTENT_BIT) && 4550848b8605Smrg bufferobj_range_mapped(bufObj, offset, length)) { 4551848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 4552848b8605Smrg "glInvalidateBufferSubData(intersection with mapped " 4553848b8605Smrg "range)"); 4554848b8605Smrg return; 4555848b8605Smrg } 4556848b8605Smrg 4557b8e80941Smrg invalidate_buffer_subdata(ctx, bufObj, offset, length); 4558b8e80941Smrg} 4559b8e80941Smrg 4560b8e80941Smrgvoid GLAPIENTRY 4561b8e80941Smrg_mesa_InvalidateBufferData_no_error(GLuint buffer) 4562b8e80941Smrg{ 4563b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 4564b8e80941Smrg 4565b8e80941Smrg struct gl_buffer_object *bufObj =_mesa_lookup_bufferobj(ctx, buffer); 4566b8e80941Smrg invalidate_buffer_subdata(ctx, bufObj, 0, bufObj->Size); 4567848b8605Smrg} 4568848b8605Smrg 4569848b8605Smrgvoid GLAPIENTRY 4570848b8605Smrg_mesa_InvalidateBufferData(GLuint buffer) 4571848b8605Smrg{ 4572848b8605Smrg GET_CURRENT_CONTEXT(ctx); 4573848b8605Smrg struct gl_buffer_object *bufObj; 4574848b8605Smrg 4575b8e80941Smrg /* Section 6.5 (Invalidating Buffer Data) of the OpenGL 4.5 (Compatibility 4576b8e80941Smrg * Profile) spec says: 4577b8e80941Smrg * 4578b8e80941Smrg * "An INVALID_VALUE error is generated if buffer is zero or is not the 4579b8e80941Smrg * name of an existing buffer object." 4580b8e80941Smrg */ 4581848b8605Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 4582b8e80941Smrg if (!bufObj || bufObj == &DummyBufferObject) { 4583848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 4584b8e80941Smrg "glInvalidateBufferData(name = %u) invalid object", 4585848b8605Smrg buffer); 4586848b8605Smrg return; 4587848b8605Smrg } 4588848b8605Smrg 4589848b8605Smrg /* The OpenGL 4.4 (Core Profile) spec says: 4590848b8605Smrg * 4591848b8605Smrg * "An INVALID_OPERATION error is generated if buffer is currently 4592848b8605Smrg * mapped by MapBuffer or if the invalidate range intersects the range 4593848b8605Smrg * currently mapped by MapBufferRange, unless it was mapped 4594848b8605Smrg * with MAP_PERSISTENT_BIT set in the MapBufferRange access flags." 4595848b8605Smrg */ 4596848b8605Smrg if (_mesa_check_disallowed_mapping(bufObj)) { 4597848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 4598848b8605Smrg "glInvalidateBufferData(intersection with mapped " 4599848b8605Smrg "range)"); 4600848b8605Smrg return; 4601848b8605Smrg } 4602848b8605Smrg 4603b8e80941Smrg invalidate_buffer_subdata(ctx, bufObj, 0, bufObj->Size); 4604b8e80941Smrg} 4605b8e80941Smrg 4606b8e80941Smrgstatic void 4607b8e80941Smrgbuffer_page_commitment(struct gl_context *ctx, 4608b8e80941Smrg struct gl_buffer_object *bufferObj, 4609b8e80941Smrg GLintptr offset, GLsizeiptr size, 4610b8e80941Smrg GLboolean commit, const char *func) 4611b8e80941Smrg{ 4612b8e80941Smrg if (!(bufferObj->StorageFlags & GL_SPARSE_STORAGE_BIT_ARB)) { 4613b8e80941Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(not a sparse buffer object)", 4614b8e80941Smrg func); 4615b8e80941Smrg return; 4616b8e80941Smrg } 4617b8e80941Smrg 4618b8e80941Smrg if (size < 0 || size > bufferObj->Size || 4619b8e80941Smrg offset < 0 || offset > bufferObj->Size - size) { 4620b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(out of bounds)", 4621b8e80941Smrg func); 4622b8e80941Smrg return; 4623b8e80941Smrg } 4624b8e80941Smrg 4625b8e80941Smrg /* The GL_ARB_sparse_buffer extension specification says: 4626b8e80941Smrg * 4627b8e80941Smrg * "INVALID_VALUE is generated by BufferPageCommitmentARB if <offset> is 4628b8e80941Smrg * not an integer multiple of SPARSE_BUFFER_PAGE_SIZE_ARB, or if <size> 4629b8e80941Smrg * is not an integer multiple of SPARSE_BUFFER_PAGE_SIZE_ARB and does 4630b8e80941Smrg * not extend to the end of the buffer's data store." 4631848b8605Smrg */ 4632b8e80941Smrg if (offset % ctx->Const.SparseBufferPageSize != 0) { 4633b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset not aligned to page size)", 4634b8e80941Smrg func); 4635b8e80941Smrg return; 4636b8e80941Smrg } 4637b8e80941Smrg 4638b8e80941Smrg if (size % ctx->Const.SparseBufferPageSize != 0 && 4639b8e80941Smrg offset + size != bufferObj->Size) { 4640b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(size not aligned to page size)", 4641b8e80941Smrg func); 4642b8e80941Smrg return; 4643b8e80941Smrg } 4644b8e80941Smrg 4645b8e80941Smrg ctx->Driver.BufferPageCommitment(ctx, bufferObj, offset, size, commit); 4646b8e80941Smrg} 4647b8e80941Smrg 4648b8e80941Smrgvoid GLAPIENTRY 4649b8e80941Smrg_mesa_BufferPageCommitmentARB(GLenum target, GLintptr offset, GLsizeiptr size, 4650b8e80941Smrg GLboolean commit) 4651b8e80941Smrg{ 4652b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 4653b8e80941Smrg struct gl_buffer_object *bufferObj; 4654b8e80941Smrg 4655b8e80941Smrg bufferObj = get_buffer(ctx, "glBufferPageCommitmentARB", target, 4656b8e80941Smrg GL_INVALID_ENUM); 4657b8e80941Smrg if (!bufferObj) 4658b8e80941Smrg return; 4659b8e80941Smrg 4660b8e80941Smrg buffer_page_commitment(ctx, bufferObj, offset, size, commit, 4661b8e80941Smrg "glBufferPageCommitmentARB"); 4662b8e80941Smrg} 4663b8e80941Smrg 4664b8e80941Smrgvoid GLAPIENTRY 4665b8e80941Smrg_mesa_NamedBufferPageCommitmentARB(GLuint buffer, GLintptr offset, 4666b8e80941Smrg GLsizeiptr size, GLboolean commit) 4667b8e80941Smrg{ 4668b8e80941Smrg GET_CURRENT_CONTEXT(ctx); 4669b8e80941Smrg struct gl_buffer_object *bufferObj; 4670b8e80941Smrg 4671b8e80941Smrg bufferObj = _mesa_lookup_bufferobj(ctx, buffer); 4672b8e80941Smrg if (!bufferObj || bufferObj == &DummyBufferObject) { 4673b8e80941Smrg /* Note: the extension spec is not clear about the excpected error value. */ 4674b8e80941Smrg _mesa_error(ctx, GL_INVALID_VALUE, 4675b8e80941Smrg "glNamedBufferPageCommitmentARB(name = %u) invalid object", 4676b8e80941Smrg buffer); 4677b8e80941Smrg return; 4678b8e80941Smrg } 4679b8e80941Smrg 4680b8e80941Smrg buffer_page_commitment(ctx, bufferObj, offset, size, commit, 4681b8e80941Smrg "glNamedBufferPageCommitmentARB"); 4682848b8605Smrg} 4683