17117f1b4Smrg/* 27117f1b4Smrg * Mesa 3-D graphics library 37117f1b4Smrg * 4c1f859d4Smrg * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 54a49301eSmrg * Copyright (C) 2009 VMware, Inc. All Rights Reserved. 67117f1b4Smrg * 77117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 87117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 97117f1b4Smrg * to deal in the Software without restriction, including without limitation 107117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 117117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 127117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 137117f1b4Smrg * 147117f1b4Smrg * The above copyright notice and this permission notice shall be included 157117f1b4Smrg * in all copies or substantial portions of the Software. 167117f1b4Smrg * 177117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 187117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 197117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 247117f1b4Smrg */ 257117f1b4Smrg 267117f1b4Smrg 277117f1b4Smrg/** 287117f1b4Smrg * \file bufferobj.c 294a49301eSmrg * \brief Functions for the GL_ARB_vertex/pixel_buffer_object extensions. 307117f1b4Smrg * \author Brian Paul, Ian Romanick 317117f1b4Smrg */ 327117f1b4Smrg 33af69d88dSmrg#include <stdbool.h> 34af69d88dSmrg#include <inttypes.h> /* for PRId64 macro */ 3501e04c3fSmrg#include "util/debug.h" 367117f1b4Smrg#include "glheader.h" 373464ebd5Sriastradh#include "enums.h" 387117f1b4Smrg#include "hash.h" 397117f1b4Smrg#include "context.h" 407117f1b4Smrg#include "bufferobj.h" 4101e04c3fSmrg#include "externalobjects.h" 423464ebd5Sriastradh#include "mtypes.h" 43af69d88dSmrg#include "teximage.h" 44af69d88dSmrg#include "glformats.h" 45af69d88dSmrg#include "texstore.h" 46af69d88dSmrg#include "transformfeedback.h" 4701e04c3fSmrg#include "varray.h" 4801e04c3fSmrg#include "util/u_atomic.h" 497ec681f3Smrg#include "util/u_memory.h" 507ec681f3Smrg#include "util/set.h" 517117f1b4Smrg 527117f1b4Smrg 534a49301eSmrg/* Debug flags */ 544a49301eSmrg/*#define VBO_DEBUG*/ 554a49301eSmrg/*#define BOUNDS_CHECK*/ 564a49301eSmrg 574a49301eSmrg 5801e04c3fSmrg/** 5901e04c3fSmrg * We count the number of buffer modification calls to check for 6001e04c3fSmrg * inefficient buffer use. This is the number of such calls before we 6101e04c3fSmrg * issue a warning. 6201e04c3fSmrg */ 6301e04c3fSmrg#define BUFFER_WARNING_CALL_COUNT 4 6401e04c3fSmrg 6501e04c3fSmrg 6601e04c3fSmrg/** 6701e04c3fSmrg * Helper to warn of possible performance issues, such as frequently 6801e04c3fSmrg * updating a buffer created with GL_STATIC_DRAW. Called via the macro 6901e04c3fSmrg * below. 7001e04c3fSmrg */ 7101e04c3fSmrgstatic void 7201e04c3fSmrgbuffer_usage_warning(struct gl_context *ctx, GLuint *id, const char *fmt, ...) 7301e04c3fSmrg{ 7401e04c3fSmrg va_list args; 7501e04c3fSmrg 7601e04c3fSmrg va_start(args, fmt); 77a8bb7a65Smaya _mesa_gl_vdebugf(ctx, id, 78a8bb7a65Smaya MESA_DEBUG_SOURCE_API, 79a8bb7a65Smaya MESA_DEBUG_TYPE_PERFORMANCE, 80a8bb7a65Smaya MESA_DEBUG_SEVERITY_MEDIUM, 81a8bb7a65Smaya fmt, args); 8201e04c3fSmrg va_end(args); 8301e04c3fSmrg} 8401e04c3fSmrg 8501e04c3fSmrg#define BUFFER_USAGE_WARNING(CTX, FMT, ...) \ 8601e04c3fSmrg do { \ 8701e04c3fSmrg static GLuint id = 0; \ 8801e04c3fSmrg buffer_usage_warning(CTX, &id, FMT, ##__VA_ARGS__); \ 8901e04c3fSmrg } while (0) 9001e04c3fSmrg 9101e04c3fSmrg 923464ebd5Sriastradh/** 933464ebd5Sriastradh * Used as a placeholder for buffer objects between glGenBuffers() and 943464ebd5Sriastradh * glBindBuffer() so that glIsBuffer() can work correctly. 953464ebd5Sriastradh */ 967ec681f3Smrgstatic struct gl_buffer_object DummyBufferObject = { 977ec681f3Smrg .MinMaxCacheMutex = _SIMPLE_MTX_INITIALIZER_NP, 987ec681f3Smrg .RefCount = 1000*1000*1000, /* never delete */ 997ec681f3Smrg}; 1003464ebd5Sriastradh 1013464ebd5Sriastradh 1024a49301eSmrg/** 1034a49301eSmrg * Return pointer to address of a buffer object target. 1044a49301eSmrg * \param ctx the GL context 1054a49301eSmrg * \param target the buffer object target to be retrieved. 1064a49301eSmrg * \return pointer to pointer to the buffer object bound to \c target in the 1074a49301eSmrg * specified context or \c NULL if \c target is invalid. 1084a49301eSmrg */ 109af69d88dSmrgstatic inline struct gl_buffer_object ** 1103464ebd5Sriastradhget_buffer_target(struct gl_context *ctx, GLenum target) 1114a49301eSmrg{ 1127ec681f3Smrg /* Other targets are only supported in desktop OpenGL and OpenGL ES 3.0. */ 1137ec681f3Smrg if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx)) { 1147ec681f3Smrg switch (target) { 1157ec681f3Smrg case GL_ARRAY_BUFFER: 1167ec681f3Smrg case GL_ELEMENT_ARRAY_BUFFER: 1177ec681f3Smrg break; 1187ec681f3Smrg case GL_PIXEL_PACK_BUFFER: 1197ec681f3Smrg case GL_PIXEL_UNPACK_BUFFER: 1207ec681f3Smrg if (!ctx->Extensions.EXT_pixel_buffer_object) 1217ec681f3Smrg return NULL; 1227ec681f3Smrg break; 1237ec681f3Smrg default: 1247ec681f3Smrg return NULL; 1257ec681f3Smrg } 1267ec681f3Smrg } 127af69d88dSmrg 1284a49301eSmrg switch (target) { 1294a49301eSmrg case GL_ARRAY_BUFFER_ARB: 130a8bb7a65Smaya if (ctx->Array.ArrayBufferObj) 131a8bb7a65Smaya ctx->Array.ArrayBufferObj->UsageHistory |= USAGE_ARRAY_BUFFER; 1324a49301eSmrg return &ctx->Array.ArrayBufferObj; 1334a49301eSmrg case GL_ELEMENT_ARRAY_BUFFER_ARB: 134a8bb7a65Smaya if (ctx->Array.VAO->IndexBufferObj) 135a8bb7a65Smaya ctx->Array.VAO->IndexBufferObj->UsageHistory 136a8bb7a65Smaya |= USAGE_ELEMENT_ARRAY_BUFFER; 137af69d88dSmrg return &ctx->Array.VAO->IndexBufferObj; 1384a49301eSmrg case GL_PIXEL_PACK_BUFFER_EXT: 1394a49301eSmrg return &ctx->Pack.BufferObj; 1404a49301eSmrg case GL_PIXEL_UNPACK_BUFFER_EXT: 1414a49301eSmrg return &ctx->Unpack.BufferObj; 1424a49301eSmrg case GL_COPY_READ_BUFFER: 1433464ebd5Sriastradh return &ctx->CopyReadBuffer; 1443464ebd5Sriastradh case GL_COPY_WRITE_BUFFER: 1453464ebd5Sriastradh return &ctx->CopyWriteBuffer; 14601e04c3fSmrg case GL_QUERY_BUFFER: 14701e04c3fSmrg if (_mesa_has_ARB_query_buffer_object(ctx)) 14801e04c3fSmrg return &ctx->QueryBuffer; 14901e04c3fSmrg break; 150af69d88dSmrg case GL_DRAW_INDIRECT_BUFFER: 15101e04c3fSmrg if ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_draw_indirect) || 15201e04c3fSmrg _mesa_is_gles31(ctx)) { 153af69d88dSmrg return &ctx->DrawIndirectBuffer; 154af69d88dSmrg } 155af69d88dSmrg break; 15601e04c3fSmrg case GL_PARAMETER_BUFFER_ARB: 15701e04c3fSmrg if (_mesa_has_ARB_indirect_parameters(ctx)) { 15801e04c3fSmrg return &ctx->ParameterBuffer; 15901e04c3fSmrg } 16001e04c3fSmrg break; 16101e04c3fSmrg case GL_DISPATCH_INDIRECT_BUFFER: 16201e04c3fSmrg if (_mesa_has_compute_shaders(ctx)) { 16301e04c3fSmrg return &ctx->DispatchIndirectBuffer; 16401e04c3fSmrg } 16501e04c3fSmrg break; 1663464ebd5Sriastradh case GL_TRANSFORM_FEEDBACK_BUFFER: 1673464ebd5Sriastradh if (ctx->Extensions.EXT_transform_feedback) { 1683464ebd5Sriastradh return &ctx->TransformFeedback.CurrentBuffer; 1694a49301eSmrg } 1704a49301eSmrg break; 1713464ebd5Sriastradh case GL_TEXTURE_BUFFER: 17201e04c3fSmrg if (_mesa_has_ARB_texture_buffer_object(ctx) || 17301e04c3fSmrg _mesa_has_OES_texture_buffer(ctx)) { 1743464ebd5Sriastradh return &ctx->Texture.BufferObject; 1754a49301eSmrg } 1764a49301eSmrg break; 177af69d88dSmrg case GL_UNIFORM_BUFFER: 178af69d88dSmrg if (ctx->Extensions.ARB_uniform_buffer_object) { 179af69d88dSmrg return &ctx->UniformBuffer; 180af69d88dSmrg } 181af69d88dSmrg break; 18201e04c3fSmrg case GL_SHADER_STORAGE_BUFFER: 1837ec681f3Smrg if (ctx->Extensions.ARB_shader_storage_buffer_object || _mesa_is_gles31(ctx)) { 18401e04c3fSmrg return &ctx->ShaderStorageBuffer; 18501e04c3fSmrg } 18601e04c3fSmrg break; 187af69d88dSmrg case GL_ATOMIC_COUNTER_BUFFER: 1887ec681f3Smrg if (ctx->Extensions.ARB_shader_atomic_counters || _mesa_is_gles31(ctx)) { 189af69d88dSmrg return &ctx->AtomicBuffer; 190af69d88dSmrg } 191af69d88dSmrg break; 19201e04c3fSmrg case GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD: 19301e04c3fSmrg if (ctx->Extensions.AMD_pinned_memory) { 19401e04c3fSmrg return &ctx->ExternalVirtualMemoryBuffer; 19501e04c3fSmrg } 19601e04c3fSmrg break; 1974a49301eSmrg default: 1984a49301eSmrg return NULL; 1994a49301eSmrg } 2004a49301eSmrg return NULL; 2014a49301eSmrg} 2024a49301eSmrg 2034a49301eSmrg 2047117f1b4Smrg/** 2057117f1b4Smrg * Get the buffer object bound to the specified target in a GL context. 2064a49301eSmrg * \param ctx the GL context 2074a49301eSmrg * \param target the buffer object target to be retrieved. 208af69d88dSmrg * \param error the GL error to record if target is illegal. 2094a49301eSmrg * \return pointer to the buffer object bound to \c target in the 2107117f1b4Smrg * specified context or \c NULL if \c target is invalid. 2117117f1b4Smrg */ 212af69d88dSmrgstatic inline struct gl_buffer_object * 213af69d88dSmrgget_buffer(struct gl_context *ctx, const char *func, GLenum target, 214af69d88dSmrg GLenum error) 2157117f1b4Smrg{ 2164a49301eSmrg struct gl_buffer_object **bufObj = get_buffer_target(ctx, target); 217af69d88dSmrg 218af69d88dSmrg if (!bufObj) { 219af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func); 220af69d88dSmrg return NULL; 221af69d88dSmrg } 222af69d88dSmrg 2237ec681f3Smrg if (!*bufObj) { 224af69d88dSmrg _mesa_error(ctx, error, "%s(no buffer bound)", func); 225af69d88dSmrg return NULL; 226af69d88dSmrg } 227af69d88dSmrg 228af69d88dSmrg return *bufObj; 2294a49301eSmrg} 2307117f1b4Smrg 2317117f1b4Smrg 2324a49301eSmrg/** 2334a49301eSmrg * Convert a GLbitfield describing the mapped buffer access flags 2344a49301eSmrg * into one of GL_READ_WRITE, GL_READ_ONLY, or GL_WRITE_ONLY. 2354a49301eSmrg */ 2364a49301eSmrgstatic GLenum 237af69d88dSmrgsimplified_access_mode(struct gl_context *ctx, GLbitfield access) 2384a49301eSmrg{ 2394a49301eSmrg const GLbitfield rwFlags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; 2404a49301eSmrg if ((access & rwFlags) == rwFlags) 2414a49301eSmrg return GL_READ_WRITE; 2424a49301eSmrg if ((access & GL_MAP_READ_BIT) == GL_MAP_READ_BIT) 2434a49301eSmrg return GL_READ_ONLY; 2444a49301eSmrg if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT) 2454a49301eSmrg return GL_WRITE_ONLY; 246af69d88dSmrg 247af69d88dSmrg /* Otherwise, AccessFlags is zero (the default state). 248af69d88dSmrg * 249af69d88dSmrg * Table 2.6 on page 31 (page 44 of the PDF) of the OpenGL 1.5 spec says: 250af69d88dSmrg * 251af69d88dSmrg * Name Type Initial Value Legal Values 252af69d88dSmrg * ... ... ... ... 253af69d88dSmrg * BUFFER_ACCESS enum READ_WRITE READ_ONLY, WRITE_ONLY 254af69d88dSmrg * READ_WRITE 255af69d88dSmrg * 256af69d88dSmrg * However, table 6.8 in the GL_OES_mapbuffer extension says: 257af69d88dSmrg * 258af69d88dSmrg * Get Value Type Get Command Value Description 259af69d88dSmrg * --------- ---- ----------- ----- ----------- 260af69d88dSmrg * BUFFER_ACCESS_OES Z1 GetBufferParameteriv WRITE_ONLY_OES buffer map flag 261af69d88dSmrg * 262af69d88dSmrg * The difference is because GL_OES_mapbuffer only supports mapping buffers 263af69d88dSmrg * write-only. 264af69d88dSmrg */ 265af69d88dSmrg assert(access == 0); 266af69d88dSmrg 267af69d88dSmrg return _mesa_is_gles(ctx) ? GL_WRITE_ONLY : GL_READ_WRITE; 268af69d88dSmrg} 269af69d88dSmrg 270af69d88dSmrg 271af69d88dSmrg/** 272af69d88dSmrg * Test if the buffer is mapped, and if so, if the mapped range overlaps the 273af69d88dSmrg * given range. 274af69d88dSmrg * The regions do not overlap if and only if the end of the given 275af69d88dSmrg * region is before the mapped region or the start of the given region 276af69d88dSmrg * is after the mapped region. 277af69d88dSmrg * 278af69d88dSmrg * \param obj Buffer object target on which to operate. 279af69d88dSmrg * \param offset Offset of the first byte of the subdata range. 280af69d88dSmrg * \param size Size, in bytes, of the subdata range. 281af69d88dSmrg * \return true if ranges overlap, false otherwise 282af69d88dSmrg * 283af69d88dSmrg */ 284af69d88dSmrgstatic bool 285af69d88dSmrgbufferobj_range_mapped(const struct gl_buffer_object *obj, 286af69d88dSmrg GLintptr offset, GLsizeiptr size) 287af69d88dSmrg{ 288af69d88dSmrg if (_mesa_bufferobj_mapped(obj, MAP_USER)) { 289af69d88dSmrg const GLintptr end = offset + size; 290af69d88dSmrg const GLintptr mapEnd = obj->Mappings[MAP_USER].Offset + 291af69d88dSmrg obj->Mappings[MAP_USER].Length; 292af69d88dSmrg 293af69d88dSmrg if (!(end <= obj->Mappings[MAP_USER].Offset || offset >= mapEnd)) { 294af69d88dSmrg return true; 295af69d88dSmrg } 296af69d88dSmrg } 297af69d88dSmrg return false; 2987117f1b4Smrg} 2997117f1b4Smrg 3007117f1b4Smrg 3017117f1b4Smrg/** 3027117f1b4Smrg * Tests the subdata range parameters and sets the GL error code for 303af69d88dSmrg * \c glBufferSubDataARB, \c glGetBufferSubDataARB and 304af69d88dSmrg * \c glClearBufferSubData. 3057117f1b4Smrg * 3067117f1b4Smrg * \param ctx GL context. 30701e04c3fSmrg * \param bufObj The buffer object. 3087117f1b4Smrg * \param offset Offset of the first byte of the subdata range. 3097117f1b4Smrg * \param size Size, in bytes, of the subdata range. 310af69d88dSmrg * \param mappedRange If true, checks if an overlapping range is mapped. 311af69d88dSmrg * If false, checks if buffer is mapped. 3127117f1b4Smrg * \param caller Name of calling function for recording errors. 31301e04c3fSmrg * \return false if error, true otherwise 3147117f1b4Smrg * 315af69d88dSmrg * \sa glBufferSubDataARB, glGetBufferSubDataARB, glClearBufferSubData 3167117f1b4Smrg */ 31701e04c3fSmrgstatic bool 31801e04c3fSmrgbuffer_object_subdata_range_good(struct gl_context *ctx, 31901e04c3fSmrg const struct gl_buffer_object *bufObj, 32001e04c3fSmrg GLintptr offset, GLsizeiptr size, 32101e04c3fSmrg bool mappedRange, const char *caller) 3227117f1b4Smrg{ 3237117f1b4Smrg if (size < 0) { 3247117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", caller); 32501e04c3fSmrg return false; 3267117f1b4Smrg } 3277117f1b4Smrg 3287117f1b4Smrg if (offset < 0) { 3297117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset < 0)", caller); 33001e04c3fSmrg return false; 3317117f1b4Smrg } 3327117f1b4Smrg 3337117f1b4Smrg if (offset + size > bufObj->Size) { 3347117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, 335af69d88dSmrg "%s(offset %lu + size %lu > buffer size %lu)", caller, 336af69d88dSmrg (unsigned long) offset, 337af69d88dSmrg (unsigned long) size, 338af69d88dSmrg (unsigned long) bufObj->Size); 33901e04c3fSmrg return false; 3407117f1b4Smrg } 341af69d88dSmrg 342af69d88dSmrg if (bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_PERSISTENT_BIT) 34301e04c3fSmrg return true; 344af69d88dSmrg 345af69d88dSmrg if (mappedRange) { 346af69d88dSmrg if (bufferobj_range_mapped(bufObj, offset, size)) { 34701e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 34801e04c3fSmrg "%s(range is mapped without persistent bit)", 34901e04c3fSmrg caller); 35001e04c3fSmrg return false; 351af69d88dSmrg } 352af69d88dSmrg } 353af69d88dSmrg else { 354af69d88dSmrg if (_mesa_bufferobj_mapped(bufObj, MAP_USER)) { 35501e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 35601e04c3fSmrg "%s(buffer is mapped without persistent bit)", 35701e04c3fSmrg caller); 35801e04c3fSmrg return false; 359af69d88dSmrg } 3607117f1b4Smrg } 3617117f1b4Smrg 36201e04c3fSmrg return true; 3637117f1b4Smrg} 3647117f1b4Smrg 3657117f1b4Smrg 366af69d88dSmrg/** 367af69d88dSmrg * Test the format and type parameters and set the GL error code for 368a8bb7a65Smaya * \c glClearBufferData, \c glClearNamedBufferData, \c glClearBufferSubData 369a8bb7a65Smaya * and \c glClearNamedBufferSubData. 370af69d88dSmrg * 371af69d88dSmrg * \param ctx GL context. 372af69d88dSmrg * \param internalformat Format to which the data is to be converted. 373af69d88dSmrg * \param format Format of the supplied data. 374af69d88dSmrg * \param type Type of the supplied data. 375af69d88dSmrg * \param caller Name of calling function for recording errors. 376af69d88dSmrg * \return If internalformat, format and type are legal the mesa_format 377af69d88dSmrg * corresponding to internalformat, otherwise MESA_FORMAT_NONE. 378af69d88dSmrg * 379a8bb7a65Smaya * \sa glClearBufferData, glClearNamedBufferData, glClearBufferSubData and 380a8bb7a65Smaya * glClearNamedBufferSubData. 381af69d88dSmrg */ 382af69d88dSmrgstatic mesa_format 383af69d88dSmrgvalidate_clear_buffer_format(struct gl_context *ctx, 384af69d88dSmrg GLenum internalformat, 385af69d88dSmrg GLenum format, GLenum type, 386af69d88dSmrg const char *caller) 387af69d88dSmrg{ 388af69d88dSmrg mesa_format mesaFormat; 389af69d88dSmrg GLenum errorFormatType; 390af69d88dSmrg 391af69d88dSmrg mesaFormat = _mesa_validate_texbuffer_format(ctx, internalformat); 392af69d88dSmrg if (mesaFormat == MESA_FORMAT_NONE) { 393af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, 394af69d88dSmrg "%s(invalid internalformat)", caller); 395af69d88dSmrg return MESA_FORMAT_NONE; 396af69d88dSmrg } 397af69d88dSmrg 398af69d88dSmrg /* NOTE: not mentioned in ARB_clear_buffer_object but according to 399af69d88dSmrg * EXT_texture_integer there is no conversion between integer and 400af69d88dSmrg * non-integer formats 401af69d88dSmrg */ 402af69d88dSmrg if (_mesa_is_enum_format_signed_int(format) != 403af69d88dSmrg _mesa_is_format_integer_color(mesaFormat)) { 404af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 405af69d88dSmrg "%s(integer vs non-integer)", caller); 406af69d88dSmrg return MESA_FORMAT_NONE; 407af69d88dSmrg } 408af69d88dSmrg 409af69d88dSmrg if (!_mesa_is_color_format(format)) { 410a8bb7a65Smaya _mesa_error(ctx, GL_INVALID_VALUE, 411af69d88dSmrg "%s(format is not a color format)", caller); 412af69d88dSmrg return MESA_FORMAT_NONE; 413af69d88dSmrg } 414af69d88dSmrg 415af69d88dSmrg errorFormatType = _mesa_error_check_format_and_type(ctx, format, type); 416af69d88dSmrg if (errorFormatType != GL_NO_ERROR) { 417a8bb7a65Smaya _mesa_error(ctx, GL_INVALID_VALUE, 418af69d88dSmrg "%s(invalid format or type)", caller); 419af69d88dSmrg return MESA_FORMAT_NONE; 420af69d88dSmrg } 421af69d88dSmrg 422af69d88dSmrg return mesaFormat; 423af69d88dSmrg} 424af69d88dSmrg 425af69d88dSmrg 426af69d88dSmrg/** 427af69d88dSmrg * Convert user-specified clear value to the specified internal format. 428af69d88dSmrg * 429af69d88dSmrg * \param ctx GL context. 430af69d88dSmrg * \param internalformat Format to which the data is converted. 431af69d88dSmrg * \param clearValue Points to the converted clear value. 432af69d88dSmrg * \param format Format of the supplied data. 433af69d88dSmrg * \param type Type of the supplied data. 434af69d88dSmrg * \param data Data which is to be converted to internalformat. 435af69d88dSmrg * \param caller Name of calling function for recording errors. 436af69d88dSmrg * \return true if data could be converted, false otherwise. 437af69d88dSmrg * 438af69d88dSmrg * \sa glClearBufferData, glClearBufferSubData 439af69d88dSmrg */ 440af69d88dSmrgstatic bool 441af69d88dSmrgconvert_clear_buffer_data(struct gl_context *ctx, 442af69d88dSmrg mesa_format internalformat, 443af69d88dSmrg GLubyte *clearValue, GLenum format, GLenum type, 444af69d88dSmrg const GLvoid *data, const char *caller) 445af69d88dSmrg{ 446af69d88dSmrg GLenum internalformatBase = _mesa_get_format_base_format(internalformat); 447af69d88dSmrg 448af69d88dSmrg if (_mesa_texstore(ctx, 1, internalformatBase, internalformat, 449af69d88dSmrg 0, &clearValue, 1, 1, 1, 450af69d88dSmrg format, type, data, &ctx->Unpack)) { 451af69d88dSmrg return true; 452af69d88dSmrg } 453af69d88dSmrg else { 454af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller); 455af69d88dSmrg return false; 456af69d88dSmrg } 457af69d88dSmrg} 458af69d88dSmrg 459af69d88dSmrg 4607117f1b4Smrg/** 4617117f1b4Smrg * Allocate and initialize a new buffer object. 46201e04c3fSmrg * 4634a49301eSmrg * Default callback for the \c dd_function_table::NewBufferObject() hook. 4647117f1b4Smrg */ 4654a49301eSmrgstatic struct gl_buffer_object * 46601e04c3fSmrg_mesa_new_buffer_object(struct gl_context *ctx, GLuint name) 4677117f1b4Smrg{ 46801e04c3fSmrg struct gl_buffer_object *obj = MALLOC_STRUCT(gl_buffer_object); 46901e04c3fSmrg if (!obj) 47001e04c3fSmrg return NULL; 4717117f1b4Smrg 47201e04c3fSmrg _mesa_initialize_buffer_object(ctx, obj, name); 4737117f1b4Smrg return obj; 4747117f1b4Smrg} 4757117f1b4Smrg 4767117f1b4Smrg 4777117f1b4Smrg/** 4787117f1b4Smrg * Delete a buffer object. 47901e04c3fSmrg * 4804a49301eSmrg * Default callback for the \c dd_function_table::DeleteBuffer() hook. 4817117f1b4Smrg */ 48201e04c3fSmrgvoid 4833464ebd5Sriastradh_mesa_delete_buffer_object(struct gl_context *ctx, 4843464ebd5Sriastradh struct gl_buffer_object *bufObj) 4857117f1b4Smrg{ 4867117f1b4Smrg (void) ctx; 4877117f1b4Smrg 48801e04c3fSmrg vbo_delete_minmax_cache(bufObj); 4897ec681f3Smrg align_free(bufObj->Data); 490c1f859d4Smrg 491c1f859d4Smrg /* assign strange values here to help w/ debugging */ 492c1f859d4Smrg bufObj->RefCount = -1000; 493c1f859d4Smrg bufObj->Name = ~0; 494c1f859d4Smrg 49501e04c3fSmrg simple_mtx_destroy(&bufObj->MinMaxCacheMutex); 496af69d88dSmrg free(bufObj->Label); 497cdc920a0Smrg free(bufObj); 4987117f1b4Smrg} 4997117f1b4Smrg 5007117f1b4Smrg 501c1f859d4Smrg 502c1f859d4Smrg/** 503c1f859d4Smrg * Set ptr to bufObj w/ reference counting. 504af69d88dSmrg * This is normally only called from the _mesa_reference_buffer_object() macro 505af69d88dSmrg * when there's a real pointer change. 506c1f859d4Smrg */ 5077117f1b4Smrgvoid 508af69d88dSmrg_mesa_reference_buffer_object_(struct gl_context *ctx, 509af69d88dSmrg struct gl_buffer_object **ptr, 5107ec681f3Smrg struct gl_buffer_object *bufObj, 5117ec681f3Smrg bool shared_binding) 5127117f1b4Smrg{ 513c1f859d4Smrg if (*ptr) { 5144a49301eSmrg /* Unreference the old buffer */ 515c1f859d4Smrg struct gl_buffer_object *oldObj = *ptr; 516c1f859d4Smrg 5177ec681f3Smrg assert(oldObj->RefCount >= 1); 5187ec681f3Smrg 5197ec681f3Smrg /* Count references only if the context doesn't own the buffer or if 5207ec681f3Smrg * ptr is a binding point shared by multiple contexts (such as a texture 5217ec681f3Smrg * buffer object being a buffer bound within a texture object). 5227ec681f3Smrg */ 5237ec681f3Smrg if (shared_binding || ctx != oldObj->Ctx) { 5247ec681f3Smrg if (p_atomic_dec_zero(&oldObj->RefCount)) { 5257ec681f3Smrg assert(ctx->Driver.DeleteBuffer); 5267ec681f3Smrg ctx->Driver.DeleteBuffer(ctx, oldObj); 5277ec681f3Smrg } 5287ec681f3Smrg } else if (ctx == oldObj->Ctx) { 5297ec681f3Smrg /* Update the private ref count. */ 5307ec681f3Smrg assert(oldObj->CtxRefCount >= 1); 5317ec681f3Smrg oldObj->CtxRefCount--; 5327117f1b4Smrg } 533c1f859d4Smrg 534c1f859d4Smrg *ptr = NULL; 535c1f859d4Smrg } 53601e04c3fSmrg assert(!*ptr); 537c1f859d4Smrg 538c1f859d4Smrg if (bufObj) { 5394a49301eSmrg /* reference new buffer */ 5407ec681f3Smrg if (shared_binding || ctx != bufObj->Ctx) 5417ec681f3Smrg p_atomic_inc(&bufObj->RefCount); 5427ec681f3Smrg else if (ctx == bufObj->Ctx) 5437ec681f3Smrg bufObj->CtxRefCount++; 5447ec681f3Smrg 54501e04c3fSmrg *ptr = bufObj; 54601e04c3fSmrg } 54701e04c3fSmrg} 54801e04c3fSmrg 54901e04c3fSmrg 55001e04c3fSmrg/** 55101e04c3fSmrg * Get the value of MESA_NO_MINMAX_CACHE. 55201e04c3fSmrg */ 55301e04c3fSmrgstatic bool 55401e04c3fSmrgget_no_minmax_cache() 55501e04c3fSmrg{ 55601e04c3fSmrg static bool read = false; 55701e04c3fSmrg static bool disable = false; 55801e04c3fSmrg 55901e04c3fSmrg if (!read) { 56001e04c3fSmrg disable = env_var_as_boolean("MESA_NO_MINMAX_CACHE", false); 56101e04c3fSmrg read = true; 5627117f1b4Smrg } 56301e04c3fSmrg 56401e04c3fSmrg return disable; 5657117f1b4Smrg} 5667117f1b4Smrg 5677117f1b4Smrg 5687117f1b4Smrg/** 5697117f1b4Smrg * Initialize a buffer object to default values. 5707117f1b4Smrg */ 5717117f1b4Smrgvoid 57201e04c3fSmrg_mesa_initialize_buffer_object(struct gl_context *ctx, 57301e04c3fSmrg struct gl_buffer_object *obj, 57401e04c3fSmrg GLuint name) 5757117f1b4Smrg{ 576cdc920a0Smrg memset(obj, 0, sizeof(struct gl_buffer_object)); 5777117f1b4Smrg obj->RefCount = 1; 5787117f1b4Smrg obj->Name = name; 5797117f1b4Smrg obj->Usage = GL_STATIC_DRAW_ARB; 58001e04c3fSmrg 58101e04c3fSmrg simple_mtx_init(&obj->MinMaxCacheMutex, mtx_plain); 58201e04c3fSmrg if (get_no_minmax_cache()) 58301e04c3fSmrg obj->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE; 584af69d88dSmrg} 585af69d88dSmrg 586af69d88dSmrg 587af69d88dSmrg 588af69d88dSmrg/** 589af69d88dSmrg * Callback called from _mesa_HashWalk() 590af69d88dSmrg */ 591af69d88dSmrgstatic void 5927ec681f3Smrgcount_buffer_size(void *data, void *userData) 593af69d88dSmrg{ 594af69d88dSmrg const struct gl_buffer_object *bufObj = 595af69d88dSmrg (const struct gl_buffer_object *) data; 596af69d88dSmrg GLuint *total = (GLuint *) userData; 597af69d88dSmrg 598af69d88dSmrg *total = *total + bufObj->Size; 599af69d88dSmrg} 600af69d88dSmrg 601af69d88dSmrg 602af69d88dSmrg/** 603af69d88dSmrg * Compute total size (in bytes) of all buffer objects for the given context. 604af69d88dSmrg * For debugging purposes. 605af69d88dSmrg */ 606af69d88dSmrgGLuint 607af69d88dSmrg_mesa_total_buffer_object_memory(struct gl_context *ctx) 608af69d88dSmrg{ 609af69d88dSmrg GLuint total = 0; 610af69d88dSmrg 6117ec681f3Smrg _mesa_HashWalkMaybeLocked(ctx->Shared->BufferObjects, count_buffer_size, 6127ec681f3Smrg &total, ctx->BufferObjectsLocked); 613af69d88dSmrg 614af69d88dSmrg return total; 6157117f1b4Smrg} 6167117f1b4Smrg 6177117f1b4Smrg 6187117f1b4Smrg/** 6197117f1b4Smrg * Allocate space for and store data in a buffer object. Any data that was 6207117f1b4Smrg * previously stored in the buffer object is lost. If \c data is \c NULL, 6217117f1b4Smrg * memory will be allocated, but no copy will occur. 6227117f1b4Smrg * 6234a49301eSmrg * This is the default callback for \c dd_function_table::BufferData() 6244a49301eSmrg * Note that all GL error checking will have been done already. 6257117f1b4Smrg * 6267117f1b4Smrg * \param ctx GL context. 6277117f1b4Smrg * \param target Buffer object target on which to operate. 6287117f1b4Smrg * \param size Size, in bytes, of the new data store. 6297117f1b4Smrg * \param data Pointer to the data to store in the buffer object. This 6307117f1b4Smrg * pointer may be \c NULL. 6317117f1b4Smrg * \param usage Hints about how the data will be used. 6327117f1b4Smrg * \param bufObj Object to be used. 6337117f1b4Smrg * 6344a49301eSmrg * \return GL_TRUE for success, GL_FALSE for failure 6357117f1b4Smrg * \sa glBufferDataARB, dd_function_table::BufferData. 6367117f1b4Smrg */ 6374a49301eSmrgstatic GLboolean 63801e04c3fSmrgbuffer_data_fallback(struct gl_context *ctx, GLenum target, GLsizeiptrARB size, 63901e04c3fSmrg const GLvoid *data, GLenum usage, GLenum storageFlags, 64001e04c3fSmrg struct gl_buffer_object *bufObj) 6417117f1b4Smrg{ 6427117f1b4Smrg void * new_data; 6437117f1b4Smrg 644af69d88dSmrg (void) target; 645af69d88dSmrg 6467ec681f3Smrg align_free( bufObj->Data ); 6477117f1b4Smrg 6487ec681f3Smrg new_data = align_malloc( size, ctx->Const.MinMapBufferAlignment ); 6497117f1b4Smrg if (new_data) { 6507117f1b4Smrg bufObj->Data = (GLubyte *) new_data; 6517117f1b4Smrg bufObj->Size = size; 6527117f1b4Smrg bufObj->Usage = usage; 653af69d88dSmrg bufObj->StorageFlags = storageFlags; 6547117f1b4Smrg 6557117f1b4Smrg if (data) { 656cdc920a0Smrg memcpy( bufObj->Data, data, size ); 6577117f1b4Smrg } 6584a49301eSmrg 6594a49301eSmrg return GL_TRUE; 6604a49301eSmrg } 6614a49301eSmrg else { 6624a49301eSmrg return GL_FALSE; 6637117f1b4Smrg } 6647117f1b4Smrg} 6657117f1b4Smrg 6667117f1b4Smrg 6677117f1b4Smrg/** 6687117f1b4Smrg * Replace data in a subrange of buffer object. If the data range 6697117f1b4Smrg * specified by \c size + \c offset extends beyond the end of the buffer or 6707117f1b4Smrg * if \c data is \c NULL, no copy is performed. 6717117f1b4Smrg * 6724a49301eSmrg * This is the default callback for \c dd_function_table::BufferSubData() 6734a49301eSmrg * Note that all GL error checking will have been done already. 6747117f1b4Smrg * 6757117f1b4Smrg * \param ctx GL context. 6767117f1b4Smrg * \param offset Offset of the first byte to be modified. 6777117f1b4Smrg * \param size Size, in bytes, of the data range. 6787117f1b4Smrg * \param data Pointer to the data to store in the buffer object. 6797117f1b4Smrg * \param bufObj Object to be used. 6807117f1b4Smrg * 6817117f1b4Smrg * \sa glBufferSubDataARB, dd_function_table::BufferSubData. 6827117f1b4Smrg */ 6834a49301eSmrgstatic void 68401e04c3fSmrgbuffer_sub_data_fallback(struct gl_context *ctx, GLintptrARB offset, 68501e04c3fSmrg GLsizeiptrARB size, const GLvoid *data, 68601e04c3fSmrg struct gl_buffer_object *bufObj) 6877117f1b4Smrg{ 688af69d88dSmrg (void) ctx; 6897117f1b4Smrg 6907117f1b4Smrg /* this should have been caught in _mesa_BufferSubData() */ 69101e04c3fSmrg assert(size + offset <= bufObj->Size); 6927117f1b4Smrg 6937117f1b4Smrg if (bufObj->Data) { 694cdc920a0Smrg memcpy( (GLubyte *) bufObj->Data + offset, data, size ); 6957117f1b4Smrg } 6967117f1b4Smrg} 6977117f1b4Smrg 6987117f1b4Smrg 6997117f1b4Smrg/** 7007117f1b4Smrg * Retrieve data from a subrange of buffer object. If the data range 7017117f1b4Smrg * specified by \c size + \c offset extends beyond the end of the buffer or 7027117f1b4Smrg * if \c data is \c NULL, no copy is performed. 7037117f1b4Smrg * 7044a49301eSmrg * This is the default callback for \c dd_function_table::GetBufferSubData() 7054a49301eSmrg * Note that all GL error checking will have been done already. 7067117f1b4Smrg * 7077117f1b4Smrg * \param ctx GL context. 7087117f1b4Smrg * \param target Buffer object target on which to operate. 7094a49301eSmrg * \param offset Offset of the first byte to be fetched. 7107117f1b4Smrg * \param size Size, in bytes, of the data range. 7114a49301eSmrg * \param data Destination for data 7127117f1b4Smrg * \param bufObj Object to be used. 7137117f1b4Smrg * 7147117f1b4Smrg * \sa glBufferGetSubDataARB, dd_function_table::GetBufferSubData. 7157117f1b4Smrg */ 7164a49301eSmrgstatic void 71701e04c3fSmrgbuffer_get_subdata(struct gl_context *ctx, GLintptrARB offset, 71801e04c3fSmrg GLsizeiptrARB size, GLvoid *data, 71901e04c3fSmrg struct gl_buffer_object *bufObj ) 7207117f1b4Smrg{ 721af69d88dSmrg (void) ctx; 7227117f1b4Smrg 7237117f1b4Smrg if (bufObj->Data && ((GLsizeiptrARB) (size + offset) <= bufObj->Size)) { 724cdc920a0Smrg memcpy( data, (GLubyte *) bufObj->Data + offset, size ); 7257117f1b4Smrg } 7267117f1b4Smrg} 7277117f1b4Smrg 7287117f1b4Smrg 7297117f1b4Smrg/** 730af69d88dSmrg * Clear a subrange of the buffer object with copies of the supplied data. 731af69d88dSmrg * If data is NULL the buffer is filled with zeros. 7327117f1b4Smrg * 733af69d88dSmrg * This is the default callback for \c dd_function_table::ClearBufferSubData() 734af69d88dSmrg * Note that all GL error checking will have been done already. 7357117f1b4Smrg * 736af69d88dSmrg * \param ctx GL context. 737af69d88dSmrg * \param offset Offset of the first byte to be cleared. 738af69d88dSmrg * \param size Size, in bytes, of the to be cleared range. 739af69d88dSmrg * \param clearValue Source of the data. 740af69d88dSmrg * \param clearValueSize Size, in bytes, of the supplied data. 741af69d88dSmrg * \param bufObj Object to be cleared. 7427117f1b4Smrg * 743af69d88dSmrg * \sa glClearBufferSubData, glClearBufferData and 744af69d88dSmrg * dd_function_table::ClearBufferSubData. 7457117f1b4Smrg */ 746af69d88dSmrgvoid 74701e04c3fSmrg_mesa_ClearBufferSubData_sw(struct gl_context *ctx, 74801e04c3fSmrg GLintptr offset, GLsizeiptr size, 74901e04c3fSmrg const GLvoid *clearValue, 75001e04c3fSmrg GLsizeiptr clearValueSize, 75101e04c3fSmrg struct gl_buffer_object *bufObj) 7527117f1b4Smrg{ 753af69d88dSmrg GLsizeiptr i; 754af69d88dSmrg GLubyte *dest; 755af69d88dSmrg 75601e04c3fSmrg assert(ctx->Driver.MapBufferRange); 757af69d88dSmrg dest = ctx->Driver.MapBufferRange(ctx, offset, size, 758af69d88dSmrg GL_MAP_WRITE_BIT | 759af69d88dSmrg GL_MAP_INVALIDATE_RANGE_BIT, 760af69d88dSmrg bufObj, MAP_INTERNAL); 761af69d88dSmrg 762af69d88dSmrg if (!dest) { 763af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClearBuffer[Sub]Data"); 764af69d88dSmrg return; 7657117f1b4Smrg } 766af69d88dSmrg 767af69d88dSmrg if (clearValue == NULL) { 768af69d88dSmrg /* Clear with zeros, per the spec */ 769af69d88dSmrg memset(dest, 0, size); 770af69d88dSmrg ctx->Driver.UnmapBuffer(ctx, bufObj, MAP_INTERNAL); 771af69d88dSmrg return; 772af69d88dSmrg } 773af69d88dSmrg 774af69d88dSmrg for (i = 0; i < size/clearValueSize; ++i) { 775af69d88dSmrg memcpy(dest, clearValue, clearValueSize); 776af69d88dSmrg dest += clearValueSize; 777af69d88dSmrg } 778af69d88dSmrg 779af69d88dSmrg ctx->Driver.UnmapBuffer(ctx, bufObj, MAP_INTERNAL); 7807117f1b4Smrg} 7817117f1b4Smrg 7827117f1b4Smrg 7837117f1b4Smrg/** 7844a49301eSmrg * Default fallback for \c dd_function_table::MapBufferRange(). 7854a49301eSmrg * Called via glMapBufferRange(). 7864a49301eSmrg */ 7874a49301eSmrgstatic void * 78801e04c3fSmrgmap_buffer_range_fallback(struct gl_context *ctx, GLintptr offset, 78901e04c3fSmrg GLsizeiptr length, GLbitfield access, 79001e04c3fSmrg struct gl_buffer_object *bufObj, 79101e04c3fSmrg gl_map_buffer_index index) 7924a49301eSmrg{ 7934a49301eSmrg (void) ctx; 794af69d88dSmrg assert(!_mesa_bufferobj_mapped(bufObj, index)); 7954a49301eSmrg /* Just return a direct pointer to the data */ 796af69d88dSmrg bufObj->Mappings[index].Pointer = bufObj->Data + offset; 797af69d88dSmrg bufObj->Mappings[index].Length = length; 798af69d88dSmrg bufObj->Mappings[index].Offset = offset; 799af69d88dSmrg bufObj->Mappings[index].AccessFlags = access; 800af69d88dSmrg return bufObj->Mappings[index].Pointer; 8014a49301eSmrg} 8024a49301eSmrg 8034a49301eSmrg 8044a49301eSmrg/** 8054a49301eSmrg * Default fallback for \c dd_function_table::FlushMappedBufferRange(). 8064a49301eSmrg * Called via glFlushMappedBufferRange(). 8074a49301eSmrg */ 8084a49301eSmrgstatic void 80901e04c3fSmrgflush_mapped_buffer_range_fallback(struct gl_context *ctx, 81001e04c3fSmrg GLintptr offset, GLsizeiptr length, 81101e04c3fSmrg struct gl_buffer_object *obj, 81201e04c3fSmrg gl_map_buffer_index index) 8134a49301eSmrg{ 8144a49301eSmrg (void) ctx; 8154a49301eSmrg (void) offset; 8164a49301eSmrg (void) length; 8174a49301eSmrg (void) obj; 81801e04c3fSmrg (void) index; 8194a49301eSmrg /* no-op */ 8204a49301eSmrg} 8214a49301eSmrg 8224a49301eSmrg 8234a49301eSmrg/** 82401e04c3fSmrg * Default callback for \c dd_function_table::UnmapBuffer(). 8257117f1b4Smrg * 8267117f1b4Smrg * The input parameters will have been already tested for errors. 8277117f1b4Smrg * 8287117f1b4Smrg * \sa glUnmapBufferARB, dd_function_table::UnmapBuffer 8297117f1b4Smrg */ 8304a49301eSmrgstatic GLboolean 83101e04c3fSmrgunmap_buffer_fallback(struct gl_context *ctx, struct gl_buffer_object *bufObj, 83201e04c3fSmrg gl_map_buffer_index index) 8337117f1b4Smrg{ 8347117f1b4Smrg (void) ctx; 8357117f1b4Smrg /* XXX we might assert here that bufObj->Pointer is non-null */ 836af69d88dSmrg bufObj->Mappings[index].Pointer = NULL; 837af69d88dSmrg bufObj->Mappings[index].Length = 0; 838af69d88dSmrg bufObj->Mappings[index].Offset = 0; 839af69d88dSmrg bufObj->Mappings[index].AccessFlags = 0x0; 8407117f1b4Smrg return GL_TRUE; 8417117f1b4Smrg} 8427117f1b4Smrg 8437117f1b4Smrg 8444a49301eSmrg/** 8454a49301eSmrg * Default fallback for \c dd_function_table::CopyBufferSubData(). 846af69d88dSmrg * Called via glCopyBufferSubData(). 8474a49301eSmrg */ 8484a49301eSmrgstatic void 84901e04c3fSmrgcopy_buffer_sub_data_fallback(struct gl_context *ctx, 85001e04c3fSmrg struct gl_buffer_object *src, 85101e04c3fSmrg struct gl_buffer_object *dst, 85201e04c3fSmrg GLintptr readOffset, GLintptr writeOffset, 85301e04c3fSmrg GLsizeiptr size) 8544a49301eSmrg{ 8554a49301eSmrg GLubyte *srcPtr, *dstPtr; 8564a49301eSmrg 857af69d88dSmrg if (src == dst) { 858af69d88dSmrg srcPtr = dstPtr = ctx->Driver.MapBufferRange(ctx, 0, src->Size, 859af69d88dSmrg GL_MAP_READ_BIT | 860af69d88dSmrg GL_MAP_WRITE_BIT, src, 861af69d88dSmrg MAP_INTERNAL); 862af69d88dSmrg 863af69d88dSmrg if (!srcPtr) 864af69d88dSmrg return; 865af69d88dSmrg 866af69d88dSmrg srcPtr += readOffset; 867af69d88dSmrg dstPtr += writeOffset; 868af69d88dSmrg } else { 869af69d88dSmrg srcPtr = ctx->Driver.MapBufferRange(ctx, readOffset, size, 870af69d88dSmrg GL_MAP_READ_BIT, src, 871af69d88dSmrg MAP_INTERNAL); 872af69d88dSmrg dstPtr = ctx->Driver.MapBufferRange(ctx, writeOffset, size, 873af69d88dSmrg (GL_MAP_WRITE_BIT | 874af69d88dSmrg GL_MAP_INVALIDATE_RANGE_BIT), dst, 875af69d88dSmrg MAP_INTERNAL); 876af69d88dSmrg } 877af69d88dSmrg 878af69d88dSmrg /* Note: the src and dst regions will never overlap. Trying to do so 879af69d88dSmrg * would generate GL_INVALID_VALUE earlier. 880af69d88dSmrg */ 8814a49301eSmrg if (srcPtr && dstPtr) 882af69d88dSmrg memcpy(dstPtr, srcPtr, size); 8834a49301eSmrg 884af69d88dSmrg ctx->Driver.UnmapBuffer(ctx, src, MAP_INTERNAL); 885af69d88dSmrg if (dst != src) 886af69d88dSmrg ctx->Driver.UnmapBuffer(ctx, dst, MAP_INTERNAL); 8874a49301eSmrg} 8884a49301eSmrg 8894a49301eSmrg 8904a49301eSmrg 8917117f1b4Smrg/** 8927117f1b4Smrg * Initialize the state associated with buffer objects 8937117f1b4Smrg */ 8947117f1b4Smrgvoid 8953464ebd5Sriastradh_mesa_init_buffer_objects( struct gl_context *ctx ) 8967117f1b4Smrg{ 897af69d88dSmrg GLuint i; 898af69d88dSmrg 899af69d88dSmrg for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) { 900af69d88dSmrg _mesa_reference_buffer_object(ctx, 901af69d88dSmrg &ctx->UniformBufferBindings[i].BufferObject, 9027ec681f3Smrg NULL); 903af69d88dSmrg ctx->UniformBufferBindings[i].Offset = -1; 904af69d88dSmrg ctx->UniformBufferBindings[i].Size = -1; 905af69d88dSmrg } 906af69d88dSmrg 90701e04c3fSmrg for (i = 0; i < MAX_COMBINED_SHADER_STORAGE_BUFFERS; i++) { 90801e04c3fSmrg _mesa_reference_buffer_object(ctx, 90901e04c3fSmrg &ctx->ShaderStorageBufferBindings[i].BufferObject, 9107ec681f3Smrg NULL); 91101e04c3fSmrg ctx->ShaderStorageBufferBindings[i].Offset = -1; 91201e04c3fSmrg ctx->ShaderStorageBufferBindings[i].Size = -1; 91301e04c3fSmrg } 91401e04c3fSmrg 915af69d88dSmrg for (i = 0; i < MAX_COMBINED_ATOMIC_BUFFERS; i++) { 916af69d88dSmrg _mesa_reference_buffer_object(ctx, 917af69d88dSmrg &ctx->AtomicBufferBindings[i].BufferObject, 9187ec681f3Smrg NULL); 91901e04c3fSmrg ctx->AtomicBufferBindings[i].Offset = 0; 92001e04c3fSmrg ctx->AtomicBufferBindings[i].Size = 0; 921af69d88dSmrg } 9224a49301eSmrg} 9234a49301eSmrg 9247ec681f3Smrg/** 9257ec681f3Smrg * Detach the context from the buffer to re-enable buffer reference counting 9267ec681f3Smrg * for this context. 9277ec681f3Smrg */ 9287ec681f3Smrgstatic void 9297ec681f3Smrgdetach_ctx_from_buffer(struct gl_context *ctx, struct gl_buffer_object *buf) 9307ec681f3Smrg{ 9317ec681f3Smrg assert(buf->Ctx == ctx); 9327ec681f3Smrg 9337ec681f3Smrg /* Move private non-atomic context references to the global ref count. */ 9347ec681f3Smrg p_atomic_add(&buf->RefCount, buf->CtxRefCount); 9357ec681f3Smrg buf->CtxRefCount = 0; 9367ec681f3Smrg buf->Ctx = NULL; 9377ec681f3Smrg 9387ec681f3Smrg /* Remove the context reference where the context holds one 9397ec681f3Smrg * reference for the lifetime of the buffer ID to skip refcount 9407ec681f3Smrg * atomics instead of each binding point holding the reference. 9417ec681f3Smrg */ 9427ec681f3Smrg _mesa_reference_buffer_object(ctx, &buf, NULL); 9437ec681f3Smrg} 9447ec681f3Smrg 9457ec681f3Smrg/** 9467ec681f3Smrg * Zombie buffers are buffers that were created by one context and deleted 9477ec681f3Smrg * by another context. The creating context holds a global reference for each 9487ec681f3Smrg * buffer it created that can't be unreferenced when another context deletes 9497ec681f3Smrg * it. Such a buffer becomes a zombie, which means that it's no longer usable 9507ec681f3Smrg * by OpenGL, but the creating context still holds its global reference of 9517ec681f3Smrg * the buffer. Only the creating context can remove the reference, which is 9527ec681f3Smrg * what this function does. 9537ec681f3Smrg * 9547ec681f3Smrg * For all zombie buffers, decrement the reference count if the current 9557ec681f3Smrg * context owns the buffer. 9567ec681f3Smrg */ 9577ec681f3Smrgstatic void 9587ec681f3Smrgunreference_zombie_buffers_for_ctx(struct gl_context *ctx) 9597ec681f3Smrg{ 9607ec681f3Smrg /* It's assumed that the mutex of Shared->BufferObjects is locked. */ 9617ec681f3Smrg set_foreach(ctx->Shared->ZombieBufferObjects, entry) { 9627ec681f3Smrg struct gl_buffer_object *buf = (struct gl_buffer_object *)entry->key; 9637ec681f3Smrg 9647ec681f3Smrg if (buf->Ctx == ctx) { 9657ec681f3Smrg _mesa_set_remove(ctx->Shared->ZombieBufferObjects, entry); 9667ec681f3Smrg detach_ctx_from_buffer(ctx, buf); 9677ec681f3Smrg } 9687ec681f3Smrg } 9697ec681f3Smrg} 9707ec681f3Smrg 9717ec681f3Smrg/** 9727ec681f3Smrg * When a context creates buffers, it holds a global buffer reference count 9737ec681f3Smrg * for each buffer and doesn't update their RefCount. When the context is 9747ec681f3Smrg * destroyed before the buffers are destroyed, the context must remove 9757ec681f3Smrg * its global reference from the buffers, so that the buffers can live 9767ec681f3Smrg * on their own. 9777ec681f3Smrg * 9787ec681f3Smrg * At this point, the buffers shouldn't be bound in any bounding point owned 9797ec681f3Smrg * by the context. (it would crash if they did) 9807ec681f3Smrg */ 9817ec681f3Smrgstatic void 9827ec681f3Smrgdetach_unrefcounted_buffer_from_ctx(void *data, void *userData) 9837ec681f3Smrg{ 9847ec681f3Smrg struct gl_context *ctx = (struct gl_context *)userData; 9857ec681f3Smrg struct gl_buffer_object *buf = (struct gl_buffer_object *)data; 9867ec681f3Smrg 9877ec681f3Smrg if (buf->Ctx == ctx) { 9887ec681f3Smrg /* Detach the current context from live objects. There should be no 9897ec681f3Smrg * bound buffer in the context at this point, therefore we can just 9907ec681f3Smrg * unreference the global reference. Other contexts and texture objects 9917ec681f3Smrg * might still be using the buffer. 9927ec681f3Smrg */ 9937ec681f3Smrg assert(buf->CtxRefCount == 0); 9947ec681f3Smrg buf->Ctx = NULL; 9957ec681f3Smrg _mesa_reference_buffer_object(ctx, &buf, NULL); 9967ec681f3Smrg } 9977ec681f3Smrg} 9987117f1b4Smrg 9994a49301eSmrgvoid 10003464ebd5Sriastradh_mesa_free_buffer_objects( struct gl_context *ctx ) 10014a49301eSmrg{ 1002af69d88dSmrg GLuint i; 1003af69d88dSmrg 10044a49301eSmrg _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL); 10054a49301eSmrg 10064a49301eSmrg _mesa_reference_buffer_object(ctx, &ctx->CopyReadBuffer, NULL); 10074a49301eSmrg _mesa_reference_buffer_object(ctx, &ctx->CopyWriteBuffer, NULL); 1008af69d88dSmrg 1009af69d88dSmrg _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, NULL); 1010af69d88dSmrg 101101e04c3fSmrg _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer, NULL); 101201e04c3fSmrg 1013af69d88dSmrg _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, NULL); 1014af69d88dSmrg 1015af69d88dSmrg _mesa_reference_buffer_object(ctx, &ctx->DrawIndirectBuffer, NULL); 1016af69d88dSmrg 101701e04c3fSmrg _mesa_reference_buffer_object(ctx, &ctx->ParameterBuffer, NULL); 101801e04c3fSmrg 101901e04c3fSmrg _mesa_reference_buffer_object(ctx, &ctx->DispatchIndirectBuffer, NULL); 102001e04c3fSmrg 102101e04c3fSmrg _mesa_reference_buffer_object(ctx, &ctx->QueryBuffer, NULL); 102201e04c3fSmrg 1023af69d88dSmrg for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) { 1024af69d88dSmrg _mesa_reference_buffer_object(ctx, 1025af69d88dSmrg &ctx->UniformBufferBindings[i].BufferObject, 1026af69d88dSmrg NULL); 1027af69d88dSmrg } 1028af69d88dSmrg 102901e04c3fSmrg for (i = 0; i < MAX_COMBINED_SHADER_STORAGE_BUFFERS; i++) { 103001e04c3fSmrg _mesa_reference_buffer_object(ctx, 103101e04c3fSmrg &ctx->ShaderStorageBufferBindings[i].BufferObject, 103201e04c3fSmrg NULL); 103301e04c3fSmrg } 103401e04c3fSmrg 1035af69d88dSmrg for (i = 0; i < MAX_COMBINED_ATOMIC_BUFFERS; i++) { 1036af69d88dSmrg _mesa_reference_buffer_object(ctx, 1037af69d88dSmrg &ctx->AtomicBufferBindings[i].BufferObject, 1038af69d88dSmrg NULL); 1039af69d88dSmrg } 1040af69d88dSmrg 10417ec681f3Smrg _mesa_HashLockMutex(ctx->Shared->BufferObjects); 10427ec681f3Smrg unreference_zombie_buffers_for_ctx(ctx); 10437ec681f3Smrg _mesa_HashWalkLocked(ctx->Shared->BufferObjects, 10447ec681f3Smrg detach_unrefcounted_buffer_from_ctx, ctx); 10457ec681f3Smrg _mesa_HashUnlockMutex(ctx->Shared->BufferObjects); 10467ec681f3Smrg} 10477ec681f3Smrg 10487ec681f3Smrg/** 10497ec681f3Smrg * Create a buffer object that will be backed by an OpenGL buffer ID 10507ec681f3Smrg * where the creating context will hold one global buffer reference instead 10517ec681f3Smrg * of updating buffer RefCount for every binding point. 10527ec681f3Smrg * 10537ec681f3Smrg * This shouldn't be used for internal buffers. 10547ec681f3Smrg */ 10557ec681f3Smrgstatic struct gl_buffer_object * 10567ec681f3Smrgnew_gl_buffer_object(struct gl_context *ctx, GLuint id) 10577ec681f3Smrg{ 10587ec681f3Smrg struct gl_buffer_object *buf = ctx->Driver.NewBufferObject(ctx, id); 10597ec681f3Smrg 10607ec681f3Smrg buf->Ctx = ctx; 10617ec681f3Smrg buf->RefCount++; /* global buffer reference held by the context */ 10627ec681f3Smrg return buf; 10637117f1b4Smrg} 10647117f1b4Smrg 1065af69d88dSmrgbool 1066af69d88dSmrg_mesa_handle_bind_buffer_gen(struct gl_context *ctx, 1067af69d88dSmrg GLuint buffer, 1068af69d88dSmrg struct gl_buffer_object **buf_handle, 1069af69d88dSmrg const char *caller) 1070af69d88dSmrg{ 1071af69d88dSmrg struct gl_buffer_object *buf = *buf_handle; 1072af69d88dSmrg 107301e04c3fSmrg if (!buf && (ctx->API == API_OPENGL_CORE)) { 1074af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", caller); 1075af69d88dSmrg return false; 1076af69d88dSmrg } 1077af69d88dSmrg 1078af69d88dSmrg if (!buf || buf == &DummyBufferObject) { 1079af69d88dSmrg /* If this is a new buffer object id, or one which was generated but 1080af69d88dSmrg * never used before, allocate a buffer object now. 1081af69d88dSmrg */ 10827ec681f3Smrg *buf_handle = new_gl_buffer_object(ctx, buffer); 10837ec681f3Smrg if (!*buf_handle) { 1084af69d88dSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller); 1085af69d88dSmrg return false; 1086af69d88dSmrg } 10877ec681f3Smrg _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects, 10887ec681f3Smrg ctx->BufferObjectsLocked); 10897ec681f3Smrg _mesa_HashInsertLocked(ctx->Shared->BufferObjects, buffer, 10907ec681f3Smrg *buf_handle, buf != NULL); 10917ec681f3Smrg /* If one context only creates buffers and another context only deletes 10927ec681f3Smrg * buffers, buffers don't get released because it only produces zombie 10937ec681f3Smrg * buffers. Only the context that has created the buffers can release 10947ec681f3Smrg * them. Thus, when we create buffers, we prune the list of zombie 10957ec681f3Smrg * buffers. 10967ec681f3Smrg */ 10977ec681f3Smrg unreference_zombie_buffers_for_ctx(ctx); 10987ec681f3Smrg _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects, 10997ec681f3Smrg ctx->BufferObjectsLocked); 1100af69d88dSmrg } 1101af69d88dSmrg 1102af69d88dSmrg return true; 1103af69d88dSmrg} 11044a49301eSmrg 1105c1f859d4Smrg/** 1106c1f859d4Smrg * Bind the specified target to buffer for the specified context. 11074a49301eSmrg * Called by glBindBuffer() and other functions. 1108c1f859d4Smrg */ 1109c1f859d4Smrgstatic void 111001e04c3fSmrgbind_buffer_object(struct gl_context *ctx, 111101e04c3fSmrg struct gl_buffer_object **bindTarget, GLuint buffer) 1112c1f859d4Smrg{ 1113c1f859d4Smrg struct gl_buffer_object *oldBufObj; 1114c1f859d4Smrg struct gl_buffer_object *newBufObj = NULL; 1115c1f859d4Smrg 111601e04c3fSmrg assert(bindTarget); 1117c1f859d4Smrg 1118c1f859d4Smrg /* Get pointer to old buffer object (to be unbound) */ 11194a49301eSmrg oldBufObj = *bindTarget; 11207ec681f3Smrg if ((oldBufObj && oldBufObj->Name == buffer && !oldBufObj->DeletePending) || 11217ec681f3Smrg (!oldBufObj && buffer == 0)) 1122c1f859d4Smrg return; /* rebinding the same buffer object- no change */ 1123c1f859d4Smrg 1124c1f859d4Smrg /* 1125c1f859d4Smrg * Get pointer to new buffer object (newBufObj) 1126c1f859d4Smrg */ 11277ec681f3Smrg if (buffer != 0) { 1128c1f859d4Smrg /* non-default buffer object */ 1129c1f859d4Smrg newBufObj = _mesa_lookup_bufferobj(ctx, buffer); 113001e04c3fSmrg if (!_mesa_handle_bind_buffer_gen(ctx, buffer, 1131af69d88dSmrg &newBufObj, "glBindBuffer")) 1132af69d88dSmrg return; 113301e04c3fSmrg 11347ec681f3Smrg /* record usage history */ 11357ec681f3Smrg if (bindTarget == &ctx->Pack.BufferObj) 11367ec681f3Smrg newBufObj->UsageHistory |= USAGE_PIXEL_PACK_BUFFER; 113701e04c3fSmrg } 113801e04c3fSmrg 1139c1f859d4Smrg /* bind new buffer */ 1140c1f859d4Smrg _mesa_reference_buffer_object(ctx, bindTarget, newBufObj); 1141c1f859d4Smrg} 1142c1f859d4Smrg 1143c1f859d4Smrg 1144c1f859d4Smrg/** 1145c1f859d4Smrg * Update the default buffer objects in the given context to reference those 114601e04c3fSmrg * specified in the shared state and release those referencing the old 1147c1f859d4Smrg * shared state. 1148c1f859d4Smrg */ 1149c1f859d4Smrgvoid 11503464ebd5Sriastradh_mesa_update_default_objects_buffer_objects(struct gl_context *ctx) 1151c1f859d4Smrg{ 11527ec681f3Smrg /* Bind 0 to remove references to those in the shared context hash table. */ 115301e04c3fSmrg bind_buffer_object(ctx, &ctx->Array.ArrayBufferObj, 0); 115401e04c3fSmrg bind_buffer_object(ctx, &ctx->Array.VAO->IndexBufferObj, 0); 115501e04c3fSmrg bind_buffer_object(ctx, &ctx->Pack.BufferObj, 0); 115601e04c3fSmrg bind_buffer_object(ctx, &ctx->Unpack.BufferObj, 0); 1157c1f859d4Smrg} 1158c1f859d4Smrg 11597117f1b4Smrg 1160c1f859d4Smrg 11617117f1b4Smrg/** 11627117f1b4Smrg * Return the gl_buffer_object for the given ID. 11637117f1b4Smrg * Always return NULL for ID 0. 11647117f1b4Smrg */ 11657117f1b4Smrgstruct gl_buffer_object * 11663464ebd5Sriastradh_mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer) 11677117f1b4Smrg{ 11687117f1b4Smrg if (buffer == 0) 11697117f1b4Smrg return NULL; 11707117f1b4Smrg else 11717117f1b4Smrg return (struct gl_buffer_object *) 11727ec681f3Smrg _mesa_HashLookupMaybeLocked(ctx->Shared->BufferObjects, buffer, 11737ec681f3Smrg ctx->BufferObjectsLocked); 11747117f1b4Smrg} 11757117f1b4Smrg 11767117f1b4Smrg 1177af69d88dSmrgstruct gl_buffer_object * 1178af69d88dSmrg_mesa_lookup_bufferobj_locked(struct gl_context *ctx, GLuint buffer) 1179af69d88dSmrg{ 118001e04c3fSmrg if (buffer == 0) 118101e04c3fSmrg return NULL; 118201e04c3fSmrg else 118301e04c3fSmrg return (struct gl_buffer_object *) 118401e04c3fSmrg _mesa_HashLookupLocked(ctx->Shared->BufferObjects, buffer); 1185af69d88dSmrg} 1186af69d88dSmrg 118701e04c3fSmrg/** 118801e04c3fSmrg * A convenience function for direct state access functions that throws 118901e04c3fSmrg * GL_INVALID_OPERATION if buffer is not the name of an existing 119001e04c3fSmrg * buffer object. 119101e04c3fSmrg */ 119201e04c3fSmrgstruct gl_buffer_object * 119301e04c3fSmrg_mesa_lookup_bufferobj_err(struct gl_context *ctx, GLuint buffer, 119401e04c3fSmrg const char *caller) 1195af69d88dSmrg{ 119601e04c3fSmrg struct gl_buffer_object *bufObj; 1197af69d88dSmrg 119801e04c3fSmrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 119901e04c3fSmrg if (!bufObj || bufObj == &DummyBufferObject) { 120001e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 120101e04c3fSmrg "%s(non-existent buffer object %u)", caller, buffer); 120201e04c3fSmrg return NULL; 120301e04c3fSmrg } 1204af69d88dSmrg 120501e04c3fSmrg return bufObj; 1206af69d88dSmrg} 1207af69d88dSmrg 1208af69d88dSmrg 1209af69d88dSmrg/** 1210af69d88dSmrg * Look up a buffer object for a multi-bind function. 1211af69d88dSmrg * 1212af69d88dSmrg * Unlike _mesa_lookup_bufferobj(), this function also takes care 1213af69d88dSmrg * of generating an error if the buffer ID is not zero or the name 1214af69d88dSmrg * of an existing buffer object. 1215af69d88dSmrg * 1216af69d88dSmrg * If the buffer ID refers to an existing buffer object, a pointer 12177ec681f3Smrg * to the buffer object is returned. If the ID is zero, NULL is returned. 12187ec681f3Smrg * If the ID is not zero and does not refer to a valid buffer object, this 12197ec681f3Smrg * function returns NULL. 1220af69d88dSmrg * 1221af69d88dSmrg * This function assumes that the caller has already locked the 122201e04c3fSmrg * hash table mutex by calling 122301e04c3fSmrg * _mesa_HashLockMutex(ctx->Shared->BufferObjects). 1224af69d88dSmrg */ 1225af69d88dSmrgstruct gl_buffer_object * 1226af69d88dSmrg_mesa_multi_bind_lookup_bufferobj(struct gl_context *ctx, 1227af69d88dSmrg const GLuint *buffers, 12287ec681f3Smrg GLuint index, const char *caller, 12297ec681f3Smrg bool *error) 1230af69d88dSmrg{ 12317ec681f3Smrg struct gl_buffer_object *bufObj = NULL; 12327ec681f3Smrg 12337ec681f3Smrg *error = false; 1234af69d88dSmrg 1235af69d88dSmrg if (buffers[index] != 0) { 1236af69d88dSmrg bufObj = _mesa_lookup_bufferobj_locked(ctx, buffers[index]); 1237af69d88dSmrg 1238af69d88dSmrg /* The multi-bind functions don't create the buffer objects 1239af69d88dSmrg when they don't exist. */ 1240af69d88dSmrg if (bufObj == &DummyBufferObject) 1241af69d88dSmrg bufObj = NULL; 1242af69d88dSmrg 12437ec681f3Smrg if (!bufObj) { 12447ec681f3Smrg /* The ARB_multi_bind spec says: 12457ec681f3Smrg * 12467ec681f3Smrg * "An INVALID_OPERATION error is generated if any value 12477ec681f3Smrg * in <buffers> is not zero or the name of an existing 12487ec681f3Smrg * buffer object (per binding)." 12497ec681f3Smrg */ 12507ec681f3Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 12517ec681f3Smrg "%s(buffers[%u]=%u is not zero or the name " 12527ec681f3Smrg "of an existing buffer object)", 12537ec681f3Smrg caller, index, buffers[index]); 12547ec681f3Smrg *error = true; 12557ec681f3Smrg } 1256af69d88dSmrg } 1257af69d88dSmrg 1258af69d88dSmrg return bufObj; 1259af69d88dSmrg} 1260af69d88dSmrg 1261af69d88dSmrg 1262c1f859d4Smrg/** 1263c1f859d4Smrg * If *ptr points to obj, set ptr = the Null/default buffer object. 1264c1f859d4Smrg * This is a helper for buffer object deletion. 1265c1f859d4Smrg * The GL spec says that deleting a buffer object causes it to get 1266c1f859d4Smrg * unbound from all arrays in the current context. 1267c1f859d4Smrg */ 1268c1f859d4Smrgstatic void 12693464ebd5Sriastradhunbind(struct gl_context *ctx, 127001e04c3fSmrg struct gl_vertex_array_object *vao, unsigned index, 1271c1f859d4Smrg struct gl_buffer_object *obj) 1272c1f859d4Smrg{ 127301e04c3fSmrg if (vao->BufferBinding[index].BufferObj == obj) { 12747ec681f3Smrg _mesa_bind_vertex_buffer(ctx, vao, index, NULL, 127501e04c3fSmrg vao->BufferBinding[index].Offset, 12767ec681f3Smrg vao->BufferBinding[index].Stride, true, false); 1277c1f859d4Smrg } 1278c1f859d4Smrg} 1279c1f859d4Smrg 1280c1f859d4Smrg 12814a49301eSmrg/** 12824a49301eSmrg * Plug default/fallback buffer object functions into the device 12834a49301eSmrg * driver hooks. 12844a49301eSmrg */ 12854a49301eSmrgvoid 12864a49301eSmrg_mesa_init_buffer_object_functions(struct dd_function_table *driver) 12874a49301eSmrg{ 12884a49301eSmrg /* GL_ARB_vertex/pixel_buffer_object */ 12894a49301eSmrg driver->NewBufferObject = _mesa_new_buffer_object; 12904a49301eSmrg driver->DeleteBuffer = _mesa_delete_buffer_object; 129101e04c3fSmrg driver->BufferData = buffer_data_fallback; 129201e04c3fSmrg driver->BufferSubData = buffer_sub_data_fallback; 129301e04c3fSmrg driver->GetBufferSubData = buffer_get_subdata; 129401e04c3fSmrg driver->UnmapBuffer = unmap_buffer_fallback; 12954a49301eSmrg 1296af69d88dSmrg /* GL_ARB_clear_buffer_object */ 129701e04c3fSmrg driver->ClearBufferSubData = _mesa_ClearBufferSubData_sw; 1298af69d88dSmrg 12994a49301eSmrg /* GL_ARB_map_buffer_range */ 130001e04c3fSmrg driver->MapBufferRange = map_buffer_range_fallback; 130101e04c3fSmrg driver->FlushMappedBufferRange = flush_mapped_buffer_range_fallback; 13024a49301eSmrg 13034a49301eSmrg /* GL_ARB_copy_buffer */ 130401e04c3fSmrg driver->CopyBufferSubData = copy_buffer_sub_data_fallback; 13054a49301eSmrg} 13064a49301eSmrg 13074a49301eSmrg 1308af69d88dSmrgvoid 1309af69d88dSmrg_mesa_buffer_unmap_all_mappings(struct gl_context *ctx, 1310af69d88dSmrg struct gl_buffer_object *bufObj) 1311af69d88dSmrg{ 131201e04c3fSmrg for (int i = 0; i < MAP_COUNT; i++) { 1313af69d88dSmrg if (_mesa_bufferobj_mapped(bufObj, i)) { 1314af69d88dSmrg ctx->Driver.UnmapBuffer(ctx, bufObj, i); 131501e04c3fSmrg assert(bufObj->Mappings[i].Pointer == NULL); 1316af69d88dSmrg bufObj->Mappings[i].AccessFlags = 0; 1317af69d88dSmrg } 1318af69d88dSmrg } 1319af69d88dSmrg} 1320af69d88dSmrg 13217117f1b4Smrg 13227117f1b4Smrg/**********************************************************************/ 13237117f1b4Smrg/* API Functions */ 13247117f1b4Smrg/**********************************************************************/ 13257117f1b4Smrg 13267117f1b4Smrgvoid GLAPIENTRY 132701e04c3fSmrg_mesa_BindBuffer_no_error(GLenum target, GLuint buffer) 13287117f1b4Smrg{ 13297117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 13307117f1b4Smrg 133101e04c3fSmrg struct gl_buffer_object **bindTarget = get_buffer_target(ctx, target); 133201e04c3fSmrg bind_buffer_object(ctx, bindTarget, buffer); 13337117f1b4Smrg} 13347117f1b4Smrg 13357117f1b4Smrg 13367117f1b4Smrgvoid GLAPIENTRY 133701e04c3fSmrg_mesa_BindBuffer(GLenum target, GLuint buffer) 13387117f1b4Smrg{ 13397117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 13407117f1b4Smrg 134101e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) { 134201e04c3fSmrg _mesa_debug(ctx, "glBindBuffer(%s, %u)\n", 134301e04c3fSmrg _mesa_enum_to_string(target), buffer); 13447117f1b4Smrg } 13457117f1b4Smrg 134601e04c3fSmrg struct gl_buffer_object **bindTarget = get_buffer_target(ctx, target); 134701e04c3fSmrg if (!bindTarget) { 134801e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target %s)", 134901e04c3fSmrg _mesa_enum_to_string(target)); 135001e04c3fSmrg return; 13517117f1b4Smrg } 13527117f1b4Smrg 135301e04c3fSmrg bind_buffer_object(ctx, bindTarget, buffer); 13547117f1b4Smrg} 13557117f1b4Smrg 13567ec681f3Smrgvoid 13577ec681f3Smrg_mesa_InternalBindElementBuffer(struct gl_context *ctx, 13587ec681f3Smrg struct gl_buffer_object *buf) 13597ec681f3Smrg{ 13607ec681f3Smrg struct gl_buffer_object **bindTarget = 13617ec681f3Smrg get_buffer_target(ctx, GL_ELEMENT_ARRAY_BUFFER); 13627ec681f3Smrg 13637ec681f3Smrg /* Move the buffer reference from the parameter to the bind point. */ 13647ec681f3Smrg _mesa_reference_buffer_object(ctx, bindTarget, NULL); 13657ec681f3Smrg if (buf) 13667ec681f3Smrg *bindTarget = buf; 13677ec681f3Smrg} 13687ec681f3Smrg 13697117f1b4Smrg/** 137001e04c3fSmrg * Binds a buffer object to a binding point. 137101e04c3fSmrg * 137201e04c3fSmrg * The caller is responsible for validating the offset, 137301e04c3fSmrg * flushing the vertices and updating NewDriverState. 13747117f1b4Smrg */ 137501e04c3fSmrgstatic void 137601e04c3fSmrgset_buffer_binding(struct gl_context *ctx, 137701e04c3fSmrg struct gl_buffer_binding *binding, 137801e04c3fSmrg struct gl_buffer_object *bufObj, 137901e04c3fSmrg GLintptr offset, 138001e04c3fSmrg GLsizeiptr size, 138101e04c3fSmrg bool autoSize, gl_buffer_usage usage) 13827117f1b4Smrg{ 138301e04c3fSmrg _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj); 13847117f1b4Smrg 138501e04c3fSmrg binding->Offset = offset; 138601e04c3fSmrg binding->Size = size; 138701e04c3fSmrg binding->AutomaticSize = autoSize; 13883464ebd5Sriastradh 138901e04c3fSmrg /* If this is a real buffer object, mark it has having been used 139001e04c3fSmrg * at some point as an atomic counter buffer. 139101e04c3fSmrg */ 139201e04c3fSmrg if (size >= 0) 139301e04c3fSmrg bufObj->UsageHistory |= usage; 139401e04c3fSmrg} 139501e04c3fSmrg 139601e04c3fSmrgstatic void 139701e04c3fSmrgset_buffer_multi_binding(struct gl_context *ctx, 139801e04c3fSmrg const GLuint *buffers, 139901e04c3fSmrg int idx, 140001e04c3fSmrg const char *caller, 140101e04c3fSmrg struct gl_buffer_binding *binding, 140201e04c3fSmrg GLintptr offset, 140301e04c3fSmrg GLsizeiptr size, 140401e04c3fSmrg bool range, 140501e04c3fSmrg gl_buffer_usage usage) 140601e04c3fSmrg{ 140701e04c3fSmrg struct gl_buffer_object *bufObj; 14087ec681f3Smrg 140901e04c3fSmrg if (binding->BufferObject && binding->BufferObject->Name == buffers[idx]) 141001e04c3fSmrg bufObj = binding->BufferObject; 14117ec681f3Smrg else { 14127ec681f3Smrg bool error; 14137ec681f3Smrg bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, idx, caller, 14147ec681f3Smrg &error); 14157ec681f3Smrg if (error) 14167ec681f3Smrg return; 14177117f1b4Smrg } 14187ec681f3Smrg 14197ec681f3Smrg if (!bufObj) 14207ec681f3Smrg set_buffer_binding(ctx, binding, bufObj, -1, -1, !range, usage); 14217ec681f3Smrg else 14227ec681f3Smrg set_buffer_binding(ctx, binding, bufObj, offset, size, !range, usage); 142301e04c3fSmrg} 14247117f1b4Smrg 142501e04c3fSmrgstatic void 142601e04c3fSmrgbind_buffer(struct gl_context *ctx, 142701e04c3fSmrg struct gl_buffer_binding *binding, 142801e04c3fSmrg struct gl_buffer_object *bufObj, 142901e04c3fSmrg GLintptr offset, 143001e04c3fSmrg GLsizeiptr size, 143101e04c3fSmrg GLboolean autoSize, 143201e04c3fSmrg uint64_t driver_state, 143301e04c3fSmrg gl_buffer_usage usage) 143401e04c3fSmrg{ 143501e04c3fSmrg if (binding->BufferObject == bufObj && 143601e04c3fSmrg binding->Offset == offset && 143701e04c3fSmrg binding->Size == size && 143801e04c3fSmrg binding->AutomaticSize == autoSize) { 14397117f1b4Smrg return; 14407117f1b4Smrg } 14417117f1b4Smrg 14427ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 144301e04c3fSmrg ctx->NewDriverState |= driver_state; 14447117f1b4Smrg 144501e04c3fSmrg set_buffer_binding(ctx, binding, bufObj, offset, size, autoSize, usage); 14467117f1b4Smrg} 14477117f1b4Smrg 14487117f1b4Smrg/** 144901e04c3fSmrg * Binds a buffer object to a uniform buffer binding point. 145001e04c3fSmrg * 145101e04c3fSmrg * Unlike set_buffer_binding(), this function also flushes vertices 145201e04c3fSmrg * and updates NewDriverState. It also checks if the binding 145301e04c3fSmrg * has actually changed before updating it. 145401e04c3fSmrg */ 145501e04c3fSmrgstatic void 145601e04c3fSmrgbind_uniform_buffer(struct gl_context *ctx, 145701e04c3fSmrg GLuint index, 145801e04c3fSmrg struct gl_buffer_object *bufObj, 145901e04c3fSmrg GLintptr offset, 146001e04c3fSmrg GLsizeiptr size, 146101e04c3fSmrg GLboolean autoSize) 146201e04c3fSmrg{ 146301e04c3fSmrg bind_buffer(ctx, &ctx->UniformBufferBindings[index], 146401e04c3fSmrg bufObj, offset, size, autoSize, 146501e04c3fSmrg ctx->DriverFlags.NewUniformBuffer, 146601e04c3fSmrg USAGE_UNIFORM_BUFFER); 146701e04c3fSmrg} 146801e04c3fSmrg 146901e04c3fSmrg/** 147001e04c3fSmrg * Binds a buffer object to a shader storage buffer binding point. 147101e04c3fSmrg * 147201e04c3fSmrg * Unlike set_ssbo_binding(), this function also flushes vertices 147301e04c3fSmrg * and updates NewDriverState. It also checks if the binding 147401e04c3fSmrg * has actually changed before updating it. 147501e04c3fSmrg */ 147601e04c3fSmrgstatic void 147701e04c3fSmrgbind_shader_storage_buffer(struct gl_context *ctx, 147801e04c3fSmrg GLuint index, 147901e04c3fSmrg struct gl_buffer_object *bufObj, 148001e04c3fSmrg GLintptr offset, 148101e04c3fSmrg GLsizeiptr size, 148201e04c3fSmrg GLboolean autoSize) 148301e04c3fSmrg{ 148401e04c3fSmrg bind_buffer(ctx, &ctx->ShaderStorageBufferBindings[index], 148501e04c3fSmrg bufObj, offset, size, autoSize, 148601e04c3fSmrg ctx->DriverFlags.NewShaderStorageBuffer, 148701e04c3fSmrg USAGE_SHADER_STORAGE_BUFFER); 148801e04c3fSmrg} 148901e04c3fSmrg 149001e04c3fSmrg/** 149101e04c3fSmrg * Binds a buffer object to an atomic buffer binding point. 149201e04c3fSmrg * 149301e04c3fSmrg * Unlike set_atomic_binding(), this function also flushes vertices 149401e04c3fSmrg * and updates NewDriverState. It also checks if the binding 149501e04c3fSmrg * has actually changed before updating it. 149601e04c3fSmrg */ 149701e04c3fSmrgstatic void 149801e04c3fSmrgbind_atomic_buffer(struct gl_context *ctx, unsigned index, 149901e04c3fSmrg struct gl_buffer_object *bufObj, GLintptr offset, 150001e04c3fSmrg GLsizeiptr size, GLboolean autoSize) 150101e04c3fSmrg{ 150201e04c3fSmrg bind_buffer(ctx, &ctx->AtomicBufferBindings[index], 150301e04c3fSmrg bufObj, offset, size, autoSize, 150401e04c3fSmrg ctx->DriverFlags.NewAtomicBuffer, 150501e04c3fSmrg USAGE_ATOMIC_COUNTER_BUFFER); 150601e04c3fSmrg} 150701e04c3fSmrg 150801e04c3fSmrg/** 150901e04c3fSmrg * Bind a buffer object to a uniform block binding point. 151001e04c3fSmrg * As above, but offset = 0. 151101e04c3fSmrg */ 151201e04c3fSmrgstatic void 151301e04c3fSmrgbind_buffer_base_uniform_buffer(struct gl_context *ctx, 151401e04c3fSmrg GLuint index, 151501e04c3fSmrg struct gl_buffer_object *bufObj) 151601e04c3fSmrg{ 151701e04c3fSmrg if (index >= ctx->Const.MaxUniformBufferBindings) { 151801e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index); 151901e04c3fSmrg return; 152001e04c3fSmrg } 152101e04c3fSmrg 152201e04c3fSmrg _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj); 152301e04c3fSmrg 15247ec681f3Smrg if (!bufObj) 152501e04c3fSmrg bind_uniform_buffer(ctx, index, bufObj, -1, -1, GL_TRUE); 152601e04c3fSmrg else 152701e04c3fSmrg bind_uniform_buffer(ctx, index, bufObj, 0, 0, GL_TRUE); 152801e04c3fSmrg} 152901e04c3fSmrg 153001e04c3fSmrg/** 153101e04c3fSmrg * Bind a buffer object to a shader storage block binding point. 153201e04c3fSmrg * As above, but offset = 0. 153301e04c3fSmrg */ 153401e04c3fSmrgstatic void 153501e04c3fSmrgbind_buffer_base_shader_storage_buffer(struct gl_context *ctx, 153601e04c3fSmrg GLuint index, 153701e04c3fSmrg struct gl_buffer_object *bufObj) 153801e04c3fSmrg{ 153901e04c3fSmrg if (index >= ctx->Const.MaxShaderStorageBufferBindings) { 154001e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index); 154101e04c3fSmrg return; 154201e04c3fSmrg } 154301e04c3fSmrg 154401e04c3fSmrg _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer, bufObj); 154501e04c3fSmrg 15467ec681f3Smrg if (!bufObj) 154701e04c3fSmrg bind_shader_storage_buffer(ctx, index, bufObj, -1, -1, GL_TRUE); 154801e04c3fSmrg else 154901e04c3fSmrg bind_shader_storage_buffer(ctx, index, bufObj, 0, 0, GL_TRUE); 155001e04c3fSmrg} 155101e04c3fSmrg 155201e04c3fSmrg/** 155301e04c3fSmrg * Bind a buffer object to a shader storage block binding point. 155401e04c3fSmrg * As above, but offset = 0. 155501e04c3fSmrg */ 155601e04c3fSmrgstatic void 155701e04c3fSmrgbind_buffer_base_atomic_buffer(struct gl_context *ctx, 155801e04c3fSmrg GLuint index, 155901e04c3fSmrg struct gl_buffer_object *bufObj) 156001e04c3fSmrg{ 156101e04c3fSmrg if (index >= ctx->Const.MaxAtomicBufferBindings) { 156201e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index); 156301e04c3fSmrg return; 156401e04c3fSmrg } 156501e04c3fSmrg 156601e04c3fSmrg _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, bufObj); 156701e04c3fSmrg 15687ec681f3Smrg if (!bufObj) 156901e04c3fSmrg bind_atomic_buffer(ctx, index, bufObj, -1, -1, GL_TRUE); 157001e04c3fSmrg else 157101e04c3fSmrg bind_atomic_buffer(ctx, index, bufObj, 0, 0, GL_TRUE); 157201e04c3fSmrg} 157301e04c3fSmrg 157401e04c3fSmrg/** 157501e04c3fSmrg * Delete a set of buffer objects. 157601e04c3fSmrg * 157701e04c3fSmrg * \param n Number of buffer objects to delete. 157801e04c3fSmrg * \param ids Array of \c n buffer object IDs. 157901e04c3fSmrg */ 158001e04c3fSmrgstatic void 158101e04c3fSmrgdelete_buffers(struct gl_context *ctx, GLsizei n, const GLuint *ids) 158201e04c3fSmrg{ 15837ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 158401e04c3fSmrg 15857ec681f3Smrg _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects, 15867ec681f3Smrg ctx->BufferObjectsLocked); 15877ec681f3Smrg unreference_zombie_buffers_for_ctx(ctx); 158801e04c3fSmrg 158901e04c3fSmrg for (GLsizei i = 0; i < n; i++) { 159001e04c3fSmrg struct gl_buffer_object *bufObj = 159101e04c3fSmrg _mesa_lookup_bufferobj_locked(ctx, ids[i]); 159201e04c3fSmrg if (bufObj) { 159301e04c3fSmrg struct gl_vertex_array_object *vao = ctx->Array.VAO; 159401e04c3fSmrg GLuint j; 159501e04c3fSmrg 159601e04c3fSmrg assert(bufObj->Name == ids[i] || bufObj == &DummyBufferObject); 159701e04c3fSmrg 159801e04c3fSmrg _mesa_buffer_unmap_all_mappings(ctx, bufObj); 159901e04c3fSmrg 160001e04c3fSmrg /* unbind any vertex pointers bound to this buffer */ 160101e04c3fSmrg for (j = 0; j < ARRAY_SIZE(vao->BufferBinding); j++) { 160201e04c3fSmrg unbind(ctx, vao, j, bufObj); 160301e04c3fSmrg } 160401e04c3fSmrg 160501e04c3fSmrg if (ctx->Array.ArrayBufferObj == bufObj) { 160601e04c3fSmrg bind_buffer_object(ctx, &ctx->Array.ArrayBufferObj, 0); 160701e04c3fSmrg } 160801e04c3fSmrg if (vao->IndexBufferObj == bufObj) { 160901e04c3fSmrg bind_buffer_object(ctx, &vao->IndexBufferObj, 0); 161001e04c3fSmrg } 161101e04c3fSmrg 161201e04c3fSmrg /* unbind ARB_draw_indirect binding point */ 161301e04c3fSmrg if (ctx->DrawIndirectBuffer == bufObj) { 161401e04c3fSmrg bind_buffer_object(ctx, &ctx->DrawIndirectBuffer, 0); 161501e04c3fSmrg } 161601e04c3fSmrg 161701e04c3fSmrg /* unbind ARB_indirect_parameters binding point */ 161801e04c3fSmrg if (ctx->ParameterBuffer == bufObj) { 161901e04c3fSmrg bind_buffer_object(ctx, &ctx->ParameterBuffer, 0); 162001e04c3fSmrg } 162101e04c3fSmrg 162201e04c3fSmrg /* unbind ARB_compute_shader binding point */ 162301e04c3fSmrg if (ctx->DispatchIndirectBuffer == bufObj) { 162401e04c3fSmrg bind_buffer_object(ctx, &ctx->DispatchIndirectBuffer, 0); 162501e04c3fSmrg } 162601e04c3fSmrg 162701e04c3fSmrg /* unbind ARB_copy_buffer binding points */ 162801e04c3fSmrg if (ctx->CopyReadBuffer == bufObj) { 162901e04c3fSmrg bind_buffer_object(ctx, &ctx->CopyReadBuffer, 0); 163001e04c3fSmrg } 163101e04c3fSmrg if (ctx->CopyWriteBuffer == bufObj) { 163201e04c3fSmrg bind_buffer_object(ctx, &ctx->CopyWriteBuffer, 0); 163301e04c3fSmrg } 163401e04c3fSmrg 163501e04c3fSmrg /* unbind transform feedback binding points */ 163601e04c3fSmrg if (ctx->TransformFeedback.CurrentBuffer == bufObj) { 163701e04c3fSmrg bind_buffer_object(ctx, &ctx->TransformFeedback.CurrentBuffer, 0); 163801e04c3fSmrg } 163901e04c3fSmrg for (j = 0; j < MAX_FEEDBACK_BUFFERS; j++) { 164001e04c3fSmrg if (ctx->TransformFeedback.CurrentObject->Buffers[j] == bufObj) { 164101e04c3fSmrg _mesa_bind_buffer_base_transform_feedback(ctx, 164201e04c3fSmrg ctx->TransformFeedback.CurrentObject, 16437ec681f3Smrg j, NULL, false); 164401e04c3fSmrg } 164501e04c3fSmrg } 164601e04c3fSmrg 164701e04c3fSmrg /* unbind UBO binding points */ 164801e04c3fSmrg for (j = 0; j < ctx->Const.MaxUniformBufferBindings; j++) { 164901e04c3fSmrg if (ctx->UniformBufferBindings[j].BufferObject == bufObj) { 16507ec681f3Smrg bind_buffer_base_uniform_buffer(ctx, j, NULL); 165101e04c3fSmrg } 165201e04c3fSmrg } 165301e04c3fSmrg 165401e04c3fSmrg if (ctx->UniformBuffer == bufObj) { 165501e04c3fSmrg bind_buffer_object(ctx, &ctx->UniformBuffer, 0); 165601e04c3fSmrg } 165701e04c3fSmrg 165801e04c3fSmrg /* unbind SSBO binding points */ 165901e04c3fSmrg for (j = 0; j < ctx->Const.MaxShaderStorageBufferBindings; j++) { 166001e04c3fSmrg if (ctx->ShaderStorageBufferBindings[j].BufferObject == bufObj) { 16617ec681f3Smrg bind_buffer_base_shader_storage_buffer(ctx, j, NULL); 166201e04c3fSmrg } 166301e04c3fSmrg } 166401e04c3fSmrg 166501e04c3fSmrg if (ctx->ShaderStorageBuffer == bufObj) { 166601e04c3fSmrg bind_buffer_object(ctx, &ctx->ShaderStorageBuffer, 0); 166701e04c3fSmrg } 166801e04c3fSmrg 166901e04c3fSmrg /* unbind Atomci Buffer binding points */ 167001e04c3fSmrg for (j = 0; j < ctx->Const.MaxAtomicBufferBindings; j++) { 167101e04c3fSmrg if (ctx->AtomicBufferBindings[j].BufferObject == bufObj) { 16727ec681f3Smrg bind_buffer_base_atomic_buffer(ctx, j, NULL); 167301e04c3fSmrg } 167401e04c3fSmrg } 167501e04c3fSmrg 167601e04c3fSmrg if (ctx->AtomicBuffer == bufObj) { 167701e04c3fSmrg bind_buffer_object(ctx, &ctx->AtomicBuffer, 0); 167801e04c3fSmrg } 167901e04c3fSmrg 168001e04c3fSmrg /* unbind any pixel pack/unpack pointers bound to this buffer */ 168101e04c3fSmrg if (ctx->Pack.BufferObj == bufObj) { 168201e04c3fSmrg bind_buffer_object(ctx, &ctx->Pack.BufferObj, 0); 168301e04c3fSmrg } 168401e04c3fSmrg if (ctx->Unpack.BufferObj == bufObj) { 168501e04c3fSmrg bind_buffer_object(ctx, &ctx->Unpack.BufferObj, 0); 168601e04c3fSmrg } 168701e04c3fSmrg 168801e04c3fSmrg if (ctx->Texture.BufferObject == bufObj) { 168901e04c3fSmrg bind_buffer_object(ctx, &ctx->Texture.BufferObject, 0); 169001e04c3fSmrg } 169101e04c3fSmrg 169201e04c3fSmrg if (ctx->ExternalVirtualMemoryBuffer == bufObj) { 169301e04c3fSmrg bind_buffer_object(ctx, &ctx->ExternalVirtualMemoryBuffer, 0); 169401e04c3fSmrg } 169501e04c3fSmrg 169601e04c3fSmrg /* unbind query buffer binding point */ 169701e04c3fSmrg if (ctx->QueryBuffer == bufObj) { 169801e04c3fSmrg bind_buffer_object(ctx, &ctx->QueryBuffer, 0); 169901e04c3fSmrg } 170001e04c3fSmrg 170101e04c3fSmrg /* The ID is immediately freed for re-use */ 170201e04c3fSmrg _mesa_HashRemoveLocked(ctx->Shared->BufferObjects, ids[i]); 170301e04c3fSmrg /* Make sure we do not run into the classic ABA problem on bind. 170401e04c3fSmrg * We don't want to allow re-binding a buffer object that's been 170501e04c3fSmrg * "deleted" by glDeleteBuffers(). 170601e04c3fSmrg * 170701e04c3fSmrg * The explicit rebinding to the default object in the current context 170801e04c3fSmrg * prevents the above in the current context, but another context 170901e04c3fSmrg * sharing the same objects might suffer from this problem. 171001e04c3fSmrg * The alternative would be to do the hash lookup in any case on bind 171101e04c3fSmrg * which would introduce more runtime overhead than this. 171201e04c3fSmrg */ 171301e04c3fSmrg bufObj->DeletePending = GL_TRUE; 17147ec681f3Smrg 17157ec681f3Smrg /* The GLuint ID holds one reference and the context that created 17167ec681f3Smrg * the buffer holds the other one. 17177ec681f3Smrg */ 17187ec681f3Smrg assert(p_atomic_read(&bufObj->RefCount) >= (bufObj->Ctx ? 2 : 1)); 17197ec681f3Smrg 17207ec681f3Smrg if (bufObj->Ctx == ctx) { 17217ec681f3Smrg detach_ctx_from_buffer(ctx, bufObj); 17227ec681f3Smrg } else if (bufObj->Ctx) { 17237ec681f3Smrg /* Only the context holding it can release it. */ 17247ec681f3Smrg _mesa_set_add(ctx->Shared->ZombieBufferObjects, bufObj); 17257ec681f3Smrg } 17267ec681f3Smrg 172701e04c3fSmrg _mesa_reference_buffer_object(ctx, &bufObj, NULL); 172801e04c3fSmrg } 172901e04c3fSmrg } 173001e04c3fSmrg 17317ec681f3Smrg _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects, 17327ec681f3Smrg ctx->BufferObjectsLocked); 173301e04c3fSmrg} 173401e04c3fSmrg 173501e04c3fSmrg 173601e04c3fSmrgvoid GLAPIENTRY 173701e04c3fSmrg_mesa_DeleteBuffers_no_error(GLsizei n, const GLuint *ids) 173801e04c3fSmrg{ 173901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 174001e04c3fSmrg delete_buffers(ctx, n, ids); 174101e04c3fSmrg} 174201e04c3fSmrg 174301e04c3fSmrg 174401e04c3fSmrgvoid GLAPIENTRY 174501e04c3fSmrg_mesa_DeleteBuffers(GLsizei n, const GLuint *ids) 174601e04c3fSmrg{ 174701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 174801e04c3fSmrg 174901e04c3fSmrg if (n < 0) { 175001e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteBuffersARB(n)"); 175101e04c3fSmrg return; 175201e04c3fSmrg } 175301e04c3fSmrg 175401e04c3fSmrg delete_buffers(ctx, n, ids); 175501e04c3fSmrg} 175601e04c3fSmrg 175701e04c3fSmrg 175801e04c3fSmrg/** 175901e04c3fSmrg * This is the implementation for glGenBuffers and glCreateBuffers. It is not 176001e04c3fSmrg * exposed to the rest of Mesa to encourage the use of nameless buffers in 176101e04c3fSmrg * driver internals. 176201e04c3fSmrg */ 176301e04c3fSmrgstatic void 176401e04c3fSmrgcreate_buffers(struct gl_context *ctx, GLsizei n, GLuint *buffers, bool dsa) 176501e04c3fSmrg{ 176601e04c3fSmrg struct gl_buffer_object *buf; 176701e04c3fSmrg 176801e04c3fSmrg if (!buffers) 176901e04c3fSmrg return; 177001e04c3fSmrg 177101e04c3fSmrg /* 177201e04c3fSmrg * This must be atomic (generation and allocation of buffer object IDs) 177301e04c3fSmrg */ 17747ec681f3Smrg _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects, 17757ec681f3Smrg ctx->BufferObjectsLocked); 17767ec681f3Smrg /* If one context only creates buffers and another context only deletes 17777ec681f3Smrg * buffers, buffers don't get released because it only produces zombie 17787ec681f3Smrg * buffers. Only the context that has created the buffers can release 17797ec681f3Smrg * them. Thus, when we create buffers, we prune the list of zombie 17807ec681f3Smrg * buffers. 17817ec681f3Smrg */ 17827ec681f3Smrg unreference_zombie_buffers_for_ctx(ctx); 178301e04c3fSmrg 17847ec681f3Smrg _mesa_HashFindFreeKeys(ctx->Shared->BufferObjects, buffers, n); 178501e04c3fSmrg 178601e04c3fSmrg /* Insert the ID and pointer into the hash table. If non-DSA, insert a 178701e04c3fSmrg * DummyBufferObject. Otherwise, create a new buffer object and insert 178801e04c3fSmrg * it. 178901e04c3fSmrg */ 179001e04c3fSmrg for (int i = 0; i < n; i++) { 179101e04c3fSmrg if (dsa) { 179201e04c3fSmrg assert(ctx->Driver.NewBufferObject); 17937ec681f3Smrg buf = new_gl_buffer_object(ctx, buffers[i]); 179401e04c3fSmrg if (!buf) { 179501e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCreateBuffers"); 17967ec681f3Smrg _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects, 17977ec681f3Smrg ctx->BufferObjectsLocked); 179801e04c3fSmrg return; 179901e04c3fSmrg } 180001e04c3fSmrg } 180101e04c3fSmrg else 180201e04c3fSmrg buf = &DummyBufferObject; 180301e04c3fSmrg 18047ec681f3Smrg _mesa_HashInsertLocked(ctx->Shared->BufferObjects, buffers[i], buf, true); 180501e04c3fSmrg } 180601e04c3fSmrg 18077ec681f3Smrg _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects, 18087ec681f3Smrg ctx->BufferObjectsLocked); 180901e04c3fSmrg} 181001e04c3fSmrg 181101e04c3fSmrg 181201e04c3fSmrgstatic void 181301e04c3fSmrgcreate_buffers_err(struct gl_context *ctx, GLsizei n, GLuint *buffers, bool dsa) 181401e04c3fSmrg{ 181501e04c3fSmrg const char *func = dsa ? "glCreateBuffers" : "glGenBuffers"; 181601e04c3fSmrg 181701e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) 181801e04c3fSmrg _mesa_debug(ctx, "%s(%d)\n", func, n); 181901e04c3fSmrg 182001e04c3fSmrg if (n < 0) { 182101e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(n %d < 0)", func, n); 182201e04c3fSmrg return; 182301e04c3fSmrg } 182401e04c3fSmrg 182501e04c3fSmrg create_buffers(ctx, n, buffers, dsa); 182601e04c3fSmrg} 182701e04c3fSmrg 182801e04c3fSmrg/** 182901e04c3fSmrg * Generate a set of unique buffer object IDs and store them in \c buffers. 183001e04c3fSmrg * 183101e04c3fSmrg * \param n Number of IDs to generate. 183201e04c3fSmrg * \param buffers Array of \c n locations to store the IDs. 183301e04c3fSmrg */ 183401e04c3fSmrgvoid GLAPIENTRY 183501e04c3fSmrg_mesa_GenBuffers_no_error(GLsizei n, GLuint *buffers) 183601e04c3fSmrg{ 183701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 183801e04c3fSmrg create_buffers(ctx, n, buffers, false); 183901e04c3fSmrg} 184001e04c3fSmrg 184101e04c3fSmrg 184201e04c3fSmrgvoid GLAPIENTRY 184301e04c3fSmrg_mesa_GenBuffers(GLsizei n, GLuint *buffers) 184401e04c3fSmrg{ 184501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 184601e04c3fSmrg create_buffers_err(ctx, n, buffers, false); 184701e04c3fSmrg} 184801e04c3fSmrg 184901e04c3fSmrg/** 185001e04c3fSmrg * Create a set of buffer objects and store their unique IDs in \c buffers. 185101e04c3fSmrg * 185201e04c3fSmrg * \param n Number of IDs to generate. 185301e04c3fSmrg * \param buffers Array of \c n locations to store the IDs. 185401e04c3fSmrg */ 185501e04c3fSmrgvoid GLAPIENTRY 185601e04c3fSmrg_mesa_CreateBuffers_no_error(GLsizei n, GLuint *buffers) 185701e04c3fSmrg{ 185801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 185901e04c3fSmrg create_buffers(ctx, n, buffers, true); 186001e04c3fSmrg} 186101e04c3fSmrg 186201e04c3fSmrg 186301e04c3fSmrgvoid GLAPIENTRY 186401e04c3fSmrg_mesa_CreateBuffers(GLsizei n, GLuint *buffers) 186501e04c3fSmrg{ 186601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 186701e04c3fSmrg create_buffers_err(ctx, n, buffers, true); 186801e04c3fSmrg} 186901e04c3fSmrg 187001e04c3fSmrg 187101e04c3fSmrg/** 187201e04c3fSmrg * Determine if ID is the name of a buffer object. 187301e04c3fSmrg * 187401e04c3fSmrg * \param id ID of the potential buffer object. 187501e04c3fSmrg * \return \c GL_TRUE if \c id is the name of a buffer object, 187601e04c3fSmrg * \c GL_FALSE otherwise. 187701e04c3fSmrg */ 18787117f1b4SmrgGLboolean GLAPIENTRY 1879af69d88dSmrg_mesa_IsBuffer(GLuint id) 18807117f1b4Smrg{ 18817117f1b4Smrg struct gl_buffer_object *bufObj; 18827117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 18837117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 18847117f1b4Smrg 18857117f1b4Smrg bufObj = _mesa_lookup_bufferobj(ctx, id); 18867117f1b4Smrg 18873464ebd5Sriastradh return bufObj && bufObj != &DummyBufferObject; 18887117f1b4Smrg} 18897117f1b4Smrg 18907117f1b4Smrg 189101e04c3fSmrgstatic bool 189201e04c3fSmrgvalidate_buffer_storage(struct gl_context *ctx, 189301e04c3fSmrg struct gl_buffer_object *bufObj, GLsizeiptr size, 189401e04c3fSmrg GLbitfield flags, const char *func) 18957117f1b4Smrg{ 1896af69d88dSmrg if (size <= 0) { 189701e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(size <= 0)", func); 189801e04c3fSmrg return false; 1899af69d88dSmrg } 19003464ebd5Sriastradh 190101e04c3fSmrg GLbitfield valid_flags = GL_MAP_READ_BIT | 190201e04c3fSmrg GL_MAP_WRITE_BIT | 190301e04c3fSmrg GL_MAP_PERSISTENT_BIT | 190401e04c3fSmrg GL_MAP_COHERENT_BIT | 190501e04c3fSmrg GL_DYNAMIC_STORAGE_BIT | 190601e04c3fSmrg GL_CLIENT_STORAGE_BIT; 190701e04c3fSmrg 190801e04c3fSmrg if (ctx->Extensions.ARB_sparse_buffer) 190901e04c3fSmrg valid_flags |= GL_SPARSE_STORAGE_BIT_ARB; 191001e04c3fSmrg 191101e04c3fSmrg if (flags & ~valid_flags) { 191201e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid flag bits set)", func); 191301e04c3fSmrg return false; 191401e04c3fSmrg } 191501e04c3fSmrg 191601e04c3fSmrg /* The Errors section of the GL_ARB_sparse_buffer spec says: 191701e04c3fSmrg * 191801e04c3fSmrg * "INVALID_VALUE is generated by BufferStorage if <flags> contains 191901e04c3fSmrg * SPARSE_STORAGE_BIT_ARB and <flags> also contains any combination of 192001e04c3fSmrg * MAP_READ_BIT or MAP_WRITE_BIT." 192101e04c3fSmrg */ 192201e04c3fSmrg if (flags & GL_SPARSE_STORAGE_BIT_ARB && 192301e04c3fSmrg flags & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) { 192401e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(SPARSE_STORAGE and READ/WRITE)", func); 192501e04c3fSmrg return false; 19267117f1b4Smrg } 19277117f1b4Smrg 1928af69d88dSmrg if (flags & GL_MAP_PERSISTENT_BIT && 1929af69d88dSmrg !(flags & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT))) { 193001e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 193101e04c3fSmrg "%s(PERSISTENT and flags!=READ/WRITE)", func); 193201e04c3fSmrg return false; 1933af69d88dSmrg } 1934af69d88dSmrg 1935af69d88dSmrg if (flags & GL_MAP_COHERENT_BIT && !(flags & GL_MAP_PERSISTENT_BIT)) { 193601e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 193701e04c3fSmrg "%s(COHERENT and flags!=PERSISTENT)", func); 193801e04c3fSmrg return false; 1939af69d88dSmrg } 1940af69d88dSmrg 194101e04c3fSmrg if (bufObj->Immutable || bufObj->HandleAllocated) { 194201e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(immutable)", func); 194301e04c3fSmrg return false; 1944af69d88dSmrg } 1945af69d88dSmrg 194601e04c3fSmrg return true; 194701e04c3fSmrg} 194801e04c3fSmrg 194901e04c3fSmrg 195001e04c3fSmrgstatic void 195101e04c3fSmrgbuffer_storage(struct gl_context *ctx, struct gl_buffer_object *bufObj, 195201e04c3fSmrg struct gl_memory_object *memObj, GLenum target, 195301e04c3fSmrg GLsizeiptr size, const GLvoid *data, GLbitfield flags, 195401e04c3fSmrg GLuint64 offset, const char *func) 195501e04c3fSmrg{ 195601e04c3fSmrg GLboolean res; 195701e04c3fSmrg 1958af69d88dSmrg /* Unmap the existing buffer. We'll replace it now. Not an error. */ 1959af69d88dSmrg _mesa_buffer_unmap_all_mappings(ctx, bufObj); 1960af69d88dSmrg 19617ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 1962af69d88dSmrg 1963af69d88dSmrg bufObj->Written = GL_TRUE; 1964af69d88dSmrg bufObj->Immutable = GL_TRUE; 196501e04c3fSmrg bufObj->MinMaxCacheDirty = true; 196601e04c3fSmrg 196701e04c3fSmrg if (memObj) { 196801e04c3fSmrg assert(ctx->Driver.BufferDataMem); 196901e04c3fSmrg res = ctx->Driver.BufferDataMem(ctx, target, size, memObj, offset, 197001e04c3fSmrg GL_DYNAMIC_DRAW, bufObj); 197101e04c3fSmrg } 197201e04c3fSmrg else { 197301e04c3fSmrg assert(ctx->Driver.BufferData); 197401e04c3fSmrg res = ctx->Driver.BufferData(ctx, target, size, data, GL_DYNAMIC_DRAW, 197501e04c3fSmrg flags, bufObj); 197601e04c3fSmrg } 1977af69d88dSmrg 197801e04c3fSmrg if (!res) { 197901e04c3fSmrg if (target == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD) { 198001e04c3fSmrg /* Even though the interaction between AMD_pinned_memory and 198101e04c3fSmrg * glBufferStorage is not described in the spec, Graham Sellers 198201e04c3fSmrg * said that it should behave the same as glBufferData. 198301e04c3fSmrg */ 198401e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func); 198501e04c3fSmrg } 198601e04c3fSmrg else { 198701e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); 198801e04c3fSmrg } 1989af69d88dSmrg } 1990af69d88dSmrg} 1991af69d88dSmrg 1992af69d88dSmrg 199301e04c3fSmrgstatic ALWAYS_INLINE void 199401e04c3fSmrginlined_buffer_storage(GLenum target, GLuint buffer, GLsizeiptr size, 199501e04c3fSmrg const GLvoid *data, GLbitfield flags, 199601e04c3fSmrg GLuint memory, GLuint64 offset, 199701e04c3fSmrg bool dsa, bool mem, bool no_error, const char *func) 1998af69d88dSmrg{ 1999af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 2000af69d88dSmrg struct gl_buffer_object *bufObj; 200101e04c3fSmrg struct gl_memory_object *memObj = NULL; 2002af69d88dSmrg 200301e04c3fSmrg if (mem) { 200401e04c3fSmrg if (!no_error) { 200501e04c3fSmrg if (!ctx->Extensions.EXT_memory_object) { 200601e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func); 200701e04c3fSmrg return; 200801e04c3fSmrg } 2009af69d88dSmrg 201001e04c3fSmrg /* From the EXT_external_objects spec: 201101e04c3fSmrg * 201201e04c3fSmrg * "An INVALID_VALUE error is generated by BufferStorageMemEXT and 201301e04c3fSmrg * NamedBufferStorageMemEXT if <memory> is 0, or ..." 201401e04c3fSmrg */ 201501e04c3fSmrg if (memory == 0) { 201601e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(memory == 0)", func); 201701e04c3fSmrg } 201801e04c3fSmrg } 201901e04c3fSmrg 202001e04c3fSmrg memObj = _mesa_lookup_memory_object(ctx, memory); 202101e04c3fSmrg if (!memObj) 202201e04c3fSmrg return; 202301e04c3fSmrg 202401e04c3fSmrg /* From the EXT_external_objects spec: 202501e04c3fSmrg * 202601e04c3fSmrg * "An INVALID_OPERATION error is generated if <memory> names a 202701e04c3fSmrg * valid memory object which has no associated memory." 202801e04c3fSmrg */ 202901e04c3fSmrg if (!no_error && !memObj->Immutable) { 203001e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(no associated memory)", 203101e04c3fSmrg func); 203201e04c3fSmrg return; 203301e04c3fSmrg } 2034af69d88dSmrg } 2035af69d88dSmrg 203601e04c3fSmrg if (dsa) { 203701e04c3fSmrg if (no_error) { 203801e04c3fSmrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 203901e04c3fSmrg } else { 204001e04c3fSmrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, func); 204101e04c3fSmrg if (!bufObj) 204201e04c3fSmrg return; 204301e04c3fSmrg } 204401e04c3fSmrg } else { 204501e04c3fSmrg if (no_error) { 204601e04c3fSmrg struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target); 204701e04c3fSmrg bufObj = *bufObjPtr; 204801e04c3fSmrg } else { 204901e04c3fSmrg bufObj = get_buffer(ctx, func, target, GL_INVALID_OPERATION); 205001e04c3fSmrg if (!bufObj) 205101e04c3fSmrg return; 205201e04c3fSmrg } 205301e04c3fSmrg } 2054af69d88dSmrg 205501e04c3fSmrg if (no_error || validate_buffer_storage(ctx, bufObj, size, flags, func)) 205601e04c3fSmrg buffer_storage(ctx, bufObj, memObj, target, size, data, flags, offset, func); 205701e04c3fSmrg} 2058af69d88dSmrg 2059af69d88dSmrg 206001e04c3fSmrgvoid GLAPIENTRY 206101e04c3fSmrg_mesa_BufferStorage_no_error(GLenum target, GLsizeiptr size, 206201e04c3fSmrg const GLvoid *data, GLbitfield flags) 206301e04c3fSmrg{ 206401e04c3fSmrg inlined_buffer_storage(target, 0, size, data, flags, GL_NONE, 0, 206501e04c3fSmrg false, false, true, "glBufferStorage"); 206601e04c3fSmrg} 20677117f1b4Smrg 206801e04c3fSmrg 206901e04c3fSmrgvoid GLAPIENTRY 207001e04c3fSmrg_mesa_BufferStorage(GLenum target, GLsizeiptr size, const GLvoid *data, 207101e04c3fSmrg GLbitfield flags) 207201e04c3fSmrg{ 207301e04c3fSmrg inlined_buffer_storage(target, 0, size, data, flags, GL_NONE, 0, 207401e04c3fSmrg false, false, false, "glBufferStorage"); 207501e04c3fSmrg} 207601e04c3fSmrg 20777ec681f3Smrgvoid GLAPIENTRY 20787ec681f3Smrg_mesa_NamedBufferStorageEXT(GLuint buffer, GLsizeiptr size, 20797ec681f3Smrg const GLvoid *data, GLbitfield flags) 20807ec681f3Smrg{ 20817ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 20827ec681f3Smrg 20837ec681f3Smrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 20847ec681f3Smrg if (!_mesa_handle_bind_buffer_gen(ctx, buffer, 20857ec681f3Smrg &bufObj, "glNamedBufferStorageEXT")) 20867ec681f3Smrg return; 20877ec681f3Smrg 20887ec681f3Smrg inlined_buffer_storage(GL_NONE, buffer, size, data, flags, GL_NONE, 0, 20897ec681f3Smrg true, false, false, "glNamedBufferStorageEXT"); 20907ec681f3Smrg} 20917ec681f3Smrg 209201e04c3fSmrg 209301e04c3fSmrgvoid GLAPIENTRY 209401e04c3fSmrg_mesa_BufferStorageMemEXT(GLenum target, GLsizeiptr size, 209501e04c3fSmrg GLuint memory, GLuint64 offset) 209601e04c3fSmrg{ 209701e04c3fSmrg inlined_buffer_storage(target, 0, size, NULL, 0, memory, offset, 209801e04c3fSmrg false, true, false, "glBufferStorageMemEXT"); 209901e04c3fSmrg} 210001e04c3fSmrg 210101e04c3fSmrg 210201e04c3fSmrgvoid GLAPIENTRY 210301e04c3fSmrg_mesa_BufferStorageMemEXT_no_error(GLenum target, GLsizeiptr size, 210401e04c3fSmrg GLuint memory, GLuint64 offset) 210501e04c3fSmrg{ 210601e04c3fSmrg inlined_buffer_storage(target, 0, size, NULL, 0, memory, offset, 210701e04c3fSmrg false, true, true, "glBufferStorageMemEXT"); 210801e04c3fSmrg} 210901e04c3fSmrg 211001e04c3fSmrg 211101e04c3fSmrgvoid GLAPIENTRY 211201e04c3fSmrg_mesa_NamedBufferStorage_no_error(GLuint buffer, GLsizeiptr size, 211301e04c3fSmrg const GLvoid *data, GLbitfield flags) 211401e04c3fSmrg{ 211501e04c3fSmrg /* In direct state access, buffer objects have an unspecified target 211601e04c3fSmrg * since they are not required to be bound. 211701e04c3fSmrg */ 211801e04c3fSmrg inlined_buffer_storage(GL_NONE, buffer, size, data, flags, GL_NONE, 0, 211901e04c3fSmrg true, false, true, "glNamedBufferStorage"); 212001e04c3fSmrg} 212101e04c3fSmrg 212201e04c3fSmrg 212301e04c3fSmrgvoid GLAPIENTRY 212401e04c3fSmrg_mesa_NamedBufferStorage(GLuint buffer, GLsizeiptr size, const GLvoid *data, 212501e04c3fSmrg GLbitfield flags) 212601e04c3fSmrg{ 212701e04c3fSmrg /* In direct state access, buffer objects have an unspecified target 212801e04c3fSmrg * since they are not required to be bound. 212901e04c3fSmrg */ 213001e04c3fSmrg inlined_buffer_storage(GL_NONE, buffer, size, data, flags, GL_NONE, 0, 213101e04c3fSmrg true, false, false, "glNamedBufferStorage"); 213201e04c3fSmrg} 213301e04c3fSmrg 213401e04c3fSmrgvoid GLAPIENTRY 213501e04c3fSmrg_mesa_NamedBufferStorageMemEXT(GLuint buffer, GLsizeiptr size, 213601e04c3fSmrg GLuint memory, GLuint64 offset) 213701e04c3fSmrg{ 213801e04c3fSmrg inlined_buffer_storage(GL_NONE, buffer, size, GL_NONE, 0, memory, offset, 213901e04c3fSmrg true, true, false, "glNamedBufferStorageMemEXT"); 214001e04c3fSmrg} 214101e04c3fSmrg 214201e04c3fSmrg 214301e04c3fSmrgvoid GLAPIENTRY 214401e04c3fSmrg_mesa_NamedBufferStorageMemEXT_no_error(GLuint buffer, GLsizeiptr size, 214501e04c3fSmrg GLuint memory, GLuint64 offset) 214601e04c3fSmrg{ 214701e04c3fSmrg inlined_buffer_storage(GL_NONE, buffer, size, GL_NONE, 0, memory, offset, 214801e04c3fSmrg true, true, true, "glNamedBufferStorageMemEXT"); 214901e04c3fSmrg} 215001e04c3fSmrg 215101e04c3fSmrg 215201e04c3fSmrgstatic ALWAYS_INLINE void 215301e04c3fSmrgbuffer_data(struct gl_context *ctx, struct gl_buffer_object *bufObj, 215401e04c3fSmrg GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage, 215501e04c3fSmrg const char *func, bool no_error) 215601e04c3fSmrg{ 215701e04c3fSmrg bool valid_usage; 215801e04c3fSmrg 215901e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) { 216001e04c3fSmrg _mesa_debug(ctx, "%s(%s, %ld, %p, %s)\n", 216101e04c3fSmrg func, 216201e04c3fSmrg _mesa_enum_to_string(target), 216301e04c3fSmrg (long int) size, data, 216401e04c3fSmrg _mesa_enum_to_string(usage)); 21657117f1b4Smrg } 2166af69d88dSmrg 216701e04c3fSmrg if (!no_error) { 216801e04c3fSmrg if (size < 0) { 216901e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", func); 217001e04c3fSmrg return; 217101e04c3fSmrg } 2172af69d88dSmrg 217301e04c3fSmrg switch (usage) { 217401e04c3fSmrg case GL_STREAM_DRAW_ARB: 217501e04c3fSmrg valid_usage = (ctx->API != API_OPENGLES); 217601e04c3fSmrg break; 217701e04c3fSmrg case GL_STATIC_DRAW_ARB: 217801e04c3fSmrg case GL_DYNAMIC_DRAW_ARB: 217901e04c3fSmrg valid_usage = true; 218001e04c3fSmrg break; 218101e04c3fSmrg case GL_STREAM_READ_ARB: 218201e04c3fSmrg case GL_STREAM_COPY_ARB: 218301e04c3fSmrg case GL_STATIC_READ_ARB: 218401e04c3fSmrg case GL_STATIC_COPY_ARB: 218501e04c3fSmrg case GL_DYNAMIC_READ_ARB: 218601e04c3fSmrg case GL_DYNAMIC_COPY_ARB: 218701e04c3fSmrg valid_usage = _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx); 218801e04c3fSmrg break; 218901e04c3fSmrg default: 219001e04c3fSmrg valid_usage = false; 219101e04c3fSmrg break; 219201e04c3fSmrg } 219301e04c3fSmrg 219401e04c3fSmrg if (!valid_usage) { 219501e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid usage: %s)", func, 219601e04c3fSmrg _mesa_enum_to_string(usage)); 219701e04c3fSmrg return; 219801e04c3fSmrg } 219901e04c3fSmrg 220001e04c3fSmrg if (bufObj->Immutable || bufObj->HandleAllocated) { 220101e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(immutable)", func); 220201e04c3fSmrg return; 220301e04c3fSmrg } 22047117f1b4Smrg } 2205af69d88dSmrg 2206af69d88dSmrg /* Unmap the existing buffer. We'll replace it now. Not an error. */ 2207af69d88dSmrg _mesa_buffer_unmap_all_mappings(ctx, bufObj); 22087117f1b4Smrg 22097ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 22104a49301eSmrg 22114a49301eSmrg bufObj->Written = GL_TRUE; 221201e04c3fSmrg bufObj->MinMaxCacheDirty = true; 22137117f1b4Smrg 22144a49301eSmrg#ifdef VBO_DEBUG 2215cdc920a0Smrg printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n", 22164a49301eSmrg bufObj->Name, size, data, usage); 22174a49301eSmrg#endif 22184a49301eSmrg 22194a49301eSmrg#ifdef BOUNDS_CHECK 22204a49301eSmrg size += 100; 22214a49301eSmrg#endif 22224a49301eSmrg 222301e04c3fSmrg assert(ctx->Driver.BufferData); 2224af69d88dSmrg if (!ctx->Driver.BufferData(ctx, target, size, data, usage, 2225af69d88dSmrg GL_MAP_READ_BIT | 2226af69d88dSmrg GL_MAP_WRITE_BIT | 2227af69d88dSmrg GL_DYNAMIC_STORAGE_BIT, 2228af69d88dSmrg bufObj)) { 222901e04c3fSmrg if (target == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD) { 223001e04c3fSmrg if (!no_error) { 223101e04c3fSmrg /* From GL_AMD_pinned_memory: 223201e04c3fSmrg * 223301e04c3fSmrg * INVALID_OPERATION is generated by BufferData if <target> is 223401e04c3fSmrg * EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, and the store cannot be 223501e04c3fSmrg * mapped to the GPU address space. 223601e04c3fSmrg */ 223701e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func); 223801e04c3fSmrg } 223901e04c3fSmrg } else { 224001e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); 224101e04c3fSmrg } 224201e04c3fSmrg } 224301e04c3fSmrg} 224401e04c3fSmrg 224501e04c3fSmrgstatic void 224601e04c3fSmrgbuffer_data_error(struct gl_context *ctx, struct gl_buffer_object *bufObj, 224701e04c3fSmrg GLenum target, GLsizeiptr size, const GLvoid *data, 224801e04c3fSmrg GLenum usage, const char *func) 224901e04c3fSmrg{ 225001e04c3fSmrg buffer_data(ctx, bufObj, target, size, data, usage, func, false); 225101e04c3fSmrg} 225201e04c3fSmrg 225301e04c3fSmrgstatic void 225401e04c3fSmrgbuffer_data_no_error(struct gl_context *ctx, struct gl_buffer_object *bufObj, 225501e04c3fSmrg GLenum target, GLsizeiptr size, const GLvoid *data, 225601e04c3fSmrg GLenum usage, const char *func) 225701e04c3fSmrg{ 225801e04c3fSmrg buffer_data(ctx, bufObj, target, size, data, usage, func, true); 225901e04c3fSmrg} 226001e04c3fSmrg 226101e04c3fSmrgvoid 226201e04c3fSmrg_mesa_buffer_data(struct gl_context *ctx, struct gl_buffer_object *bufObj, 226301e04c3fSmrg GLenum target, GLsizeiptr size, const GLvoid *data, 226401e04c3fSmrg GLenum usage, const char *func) 226501e04c3fSmrg{ 226601e04c3fSmrg buffer_data_error(ctx, bufObj, target, size, data, usage, func); 226701e04c3fSmrg} 226801e04c3fSmrg 226901e04c3fSmrgvoid GLAPIENTRY 227001e04c3fSmrg_mesa_BufferData_no_error(GLenum target, GLsizeiptr size, const GLvoid *data, 227101e04c3fSmrg GLenum usage) 227201e04c3fSmrg{ 227301e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 227401e04c3fSmrg 227501e04c3fSmrg struct gl_buffer_object **bufObj = get_buffer_target(ctx, target); 227601e04c3fSmrg buffer_data_no_error(ctx, *bufObj, target, size, data, usage, 227701e04c3fSmrg "glBufferData"); 227801e04c3fSmrg} 227901e04c3fSmrg 228001e04c3fSmrgvoid GLAPIENTRY 228101e04c3fSmrg_mesa_BufferData(GLenum target, GLsizeiptr size, 228201e04c3fSmrg const GLvoid *data, GLenum usage) 228301e04c3fSmrg{ 228401e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 228501e04c3fSmrg struct gl_buffer_object *bufObj; 228601e04c3fSmrg 228701e04c3fSmrg bufObj = get_buffer(ctx, "glBufferData", target, GL_INVALID_OPERATION); 228801e04c3fSmrg if (!bufObj) 228901e04c3fSmrg return; 229001e04c3fSmrg 229101e04c3fSmrg _mesa_buffer_data(ctx, bufObj, target, size, data, usage, 229201e04c3fSmrg "glBufferData"); 229301e04c3fSmrg} 229401e04c3fSmrg 229501e04c3fSmrgvoid GLAPIENTRY 229601e04c3fSmrg_mesa_NamedBufferData_no_error(GLuint buffer, GLsizeiptr size, 229701e04c3fSmrg const GLvoid *data, GLenum usage) 229801e04c3fSmrg{ 229901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 230001e04c3fSmrg 230101e04c3fSmrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 230201e04c3fSmrg buffer_data_no_error(ctx, bufObj, GL_NONE, size, data, usage, 230301e04c3fSmrg "glNamedBufferData"); 230401e04c3fSmrg} 230501e04c3fSmrg 230601e04c3fSmrgvoid GLAPIENTRY 230701e04c3fSmrg_mesa_NamedBufferData(GLuint buffer, GLsizeiptr size, const GLvoid *data, 230801e04c3fSmrg GLenum usage) 230901e04c3fSmrg{ 231001e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 231101e04c3fSmrg struct gl_buffer_object *bufObj; 231201e04c3fSmrg 231301e04c3fSmrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glNamedBufferData"); 231401e04c3fSmrg if (!bufObj) 231501e04c3fSmrg return; 231601e04c3fSmrg 231701e04c3fSmrg /* In direct state access, buffer objects have an unspecified target since 231801e04c3fSmrg * they are not required to be bound. 231901e04c3fSmrg */ 232001e04c3fSmrg _mesa_buffer_data(ctx, bufObj, GL_NONE, size, data, usage, 232101e04c3fSmrg "glNamedBufferData"); 232201e04c3fSmrg} 232301e04c3fSmrg 23247ec681f3Smrgvoid GLAPIENTRY 23257ec681f3Smrg_mesa_NamedBufferDataEXT(GLuint buffer, GLsizeiptr size, const GLvoid *data, 23267ec681f3Smrg GLenum usage) 23277ec681f3Smrg{ 23287ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 23297ec681f3Smrg struct gl_buffer_object *bufObj; 23307ec681f3Smrg 23317ec681f3Smrg if (!buffer) { 23327ec681f3Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 23337ec681f3Smrg "glNamedBufferDataEXT(buffer=0)"); 23347ec681f3Smrg return; 23357ec681f3Smrg } 23367ec681f3Smrg 23377ec681f3Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 23387ec681f3Smrg if (!_mesa_handle_bind_buffer_gen(ctx, buffer, 23397ec681f3Smrg &bufObj, "glNamedBufferDataEXT")) 23407ec681f3Smrg return; 23417ec681f3Smrg 23427ec681f3Smrg _mesa_buffer_data(ctx, bufObj, GL_NONE, size, data, usage, 23437ec681f3Smrg "glNamedBufferDataEXT"); 23447ec681f3Smrg} 234501e04c3fSmrg 234601e04c3fSmrgstatic bool 234701e04c3fSmrgvalidate_buffer_sub_data(struct gl_context *ctx, 234801e04c3fSmrg struct gl_buffer_object *bufObj, 234901e04c3fSmrg GLintptr offset, GLsizeiptr size, 235001e04c3fSmrg const char *func) 235101e04c3fSmrg{ 235201e04c3fSmrg if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size, 235301e04c3fSmrg true, func)) { 235401e04c3fSmrg /* error already recorded */ 235501e04c3fSmrg return false; 235601e04c3fSmrg } 235701e04c3fSmrg 235801e04c3fSmrg if (bufObj->Immutable && 235901e04c3fSmrg !(bufObj->StorageFlags & GL_DYNAMIC_STORAGE_BIT)) { 236001e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s", func); 236101e04c3fSmrg return false; 236201e04c3fSmrg } 236301e04c3fSmrg 236401e04c3fSmrg if ((bufObj->Usage == GL_STATIC_DRAW || 236501e04c3fSmrg bufObj->Usage == GL_STATIC_COPY) && 236601e04c3fSmrg bufObj->NumSubDataCalls >= BUFFER_WARNING_CALL_COUNT - 1) { 236701e04c3fSmrg /* If the application declared the buffer as static draw/copy or stream 236801e04c3fSmrg * draw, it should not be frequently modified with glBufferSubData. 236901e04c3fSmrg */ 237001e04c3fSmrg BUFFER_USAGE_WARNING(ctx, 237101e04c3fSmrg "using %s(buffer %u, offset %u, size %u) to " 237201e04c3fSmrg "update a %s buffer", 237301e04c3fSmrg func, bufObj->Name, offset, size, 237401e04c3fSmrg _mesa_enum_to_string(bufObj->Usage)); 237501e04c3fSmrg } 237601e04c3fSmrg 237701e04c3fSmrg return true; 237801e04c3fSmrg} 237901e04c3fSmrg 238001e04c3fSmrg 238101e04c3fSmrg/** 238201e04c3fSmrg * Implementation for glBufferSubData and glNamedBufferSubData. 238301e04c3fSmrg * 238401e04c3fSmrg * \param ctx GL context. 238501e04c3fSmrg * \param bufObj The buffer object. 238601e04c3fSmrg * \param offset Offset of the first byte of the subdata range. 238701e04c3fSmrg * \param size Size, in bytes, of the subdata range. 238801e04c3fSmrg * \param data The data store. 238901e04c3fSmrg * \param func Name of calling function for recording errors. 239001e04c3fSmrg * 239101e04c3fSmrg */ 239201e04c3fSmrgvoid 239301e04c3fSmrg_mesa_buffer_sub_data(struct gl_context *ctx, struct gl_buffer_object *bufObj, 239401e04c3fSmrg GLintptr offset, GLsizeiptr size, const GLvoid *data) 239501e04c3fSmrg{ 239601e04c3fSmrg if (size == 0) 239701e04c3fSmrg return; 239801e04c3fSmrg 239901e04c3fSmrg bufObj->NumSubDataCalls++; 240001e04c3fSmrg bufObj->Written = GL_TRUE; 240101e04c3fSmrg bufObj->MinMaxCacheDirty = true; 240201e04c3fSmrg 240301e04c3fSmrg assert(ctx->Driver.BufferSubData); 240401e04c3fSmrg ctx->Driver.BufferSubData(ctx, offset, size, data, bufObj); 240501e04c3fSmrg} 240601e04c3fSmrg 240701e04c3fSmrg 240801e04c3fSmrgstatic ALWAYS_INLINE void 240901e04c3fSmrgbuffer_sub_data(GLenum target, GLuint buffer, GLintptr offset, 241001e04c3fSmrg GLsizeiptr size, const GLvoid *data, 241101e04c3fSmrg bool dsa, bool no_error, const char *func) 241201e04c3fSmrg{ 241301e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 241401e04c3fSmrg struct gl_buffer_object *bufObj; 241501e04c3fSmrg 241601e04c3fSmrg if (dsa) { 241701e04c3fSmrg if (no_error) { 241801e04c3fSmrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 241901e04c3fSmrg } else { 242001e04c3fSmrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, func); 242101e04c3fSmrg if (!bufObj) 242201e04c3fSmrg return; 242301e04c3fSmrg } 242401e04c3fSmrg } else { 242501e04c3fSmrg if (no_error) { 242601e04c3fSmrg struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target); 242701e04c3fSmrg bufObj = *bufObjPtr; 242801e04c3fSmrg } else { 242901e04c3fSmrg bufObj = get_buffer(ctx, func, target, GL_INVALID_OPERATION); 243001e04c3fSmrg if (!bufObj) 243101e04c3fSmrg return; 243201e04c3fSmrg } 24334a49301eSmrg } 243401e04c3fSmrg 243501e04c3fSmrg if (no_error || validate_buffer_sub_data(ctx, bufObj, offset, size, func)) 243601e04c3fSmrg _mesa_buffer_sub_data(ctx, bufObj, offset, size, data); 243701e04c3fSmrg} 243801e04c3fSmrg 243901e04c3fSmrg 244001e04c3fSmrgvoid GLAPIENTRY 244101e04c3fSmrg_mesa_BufferSubData_no_error(GLenum target, GLintptr offset, 244201e04c3fSmrg GLsizeiptr size, const GLvoid *data) 244301e04c3fSmrg{ 244401e04c3fSmrg buffer_sub_data(target, 0, offset, size, data, false, true, 244501e04c3fSmrg "glBufferSubData"); 244601e04c3fSmrg} 244701e04c3fSmrg 244801e04c3fSmrg 244901e04c3fSmrgvoid GLAPIENTRY 245001e04c3fSmrg_mesa_BufferSubData(GLenum target, GLintptr offset, 245101e04c3fSmrg GLsizeiptr size, const GLvoid *data) 245201e04c3fSmrg{ 245301e04c3fSmrg buffer_sub_data(target, 0, offset, size, data, false, false, 245401e04c3fSmrg "glBufferSubData"); 245501e04c3fSmrg} 245601e04c3fSmrg 245701e04c3fSmrgvoid GLAPIENTRY 245801e04c3fSmrg_mesa_NamedBufferSubData_no_error(GLuint buffer, GLintptr offset, 245901e04c3fSmrg GLsizeiptr size, const GLvoid *data) 246001e04c3fSmrg{ 246101e04c3fSmrg buffer_sub_data(0, buffer, offset, size, data, true, true, 246201e04c3fSmrg "glNamedBufferSubData"); 246301e04c3fSmrg} 246401e04c3fSmrg 246501e04c3fSmrgvoid GLAPIENTRY 246601e04c3fSmrg_mesa_NamedBufferSubData(GLuint buffer, GLintptr offset, 246701e04c3fSmrg GLsizeiptr size, const GLvoid *data) 246801e04c3fSmrg{ 246901e04c3fSmrg buffer_sub_data(0, buffer, offset, size, data, true, false, 247001e04c3fSmrg "glNamedBufferSubData"); 24717117f1b4Smrg} 24727117f1b4Smrg 24737ec681f3Smrgvoid GLAPIENTRY 24747ec681f3Smrg_mesa_NamedBufferSubDataEXT(GLuint buffer, GLintptr offset, 24757ec681f3Smrg GLsizeiptr size, const GLvoid *data) 24767ec681f3Smrg{ 24777ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 24787ec681f3Smrg struct gl_buffer_object *bufObj; 24797ec681f3Smrg 24807ec681f3Smrg if (!buffer) { 24817ec681f3Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 24827ec681f3Smrg "glNamedBufferSubDataEXT(buffer=0)"); 24837ec681f3Smrg return; 24847ec681f3Smrg } 24857ec681f3Smrg 24867ec681f3Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 24877ec681f3Smrg if (!_mesa_handle_bind_buffer_gen(ctx, buffer, 24887ec681f3Smrg &bufObj, "glNamedBufferSubDataEXT")) 24897ec681f3Smrg return; 24907ec681f3Smrg 24917ec681f3Smrg if (validate_buffer_sub_data(ctx, bufObj, offset, size, 24927ec681f3Smrg "glNamedBufferSubDataEXT")) { 24937ec681f3Smrg _mesa_buffer_sub_data(ctx, bufObj, offset, size, data); 24947ec681f3Smrg } 24957ec681f3Smrg} 24967ec681f3Smrg 24977117f1b4Smrg 24987117f1b4Smrgvoid GLAPIENTRY 249901e04c3fSmrg_mesa_GetBufferSubData(GLenum target, GLintptr offset, 250001e04c3fSmrg GLsizeiptr size, GLvoid *data) 25017117f1b4Smrg{ 25027117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 25037117f1b4Smrg struct gl_buffer_object *bufObj; 25047117f1b4Smrg 250501e04c3fSmrg bufObj = get_buffer(ctx, "glGetBufferSubData", target, 250601e04c3fSmrg GL_INVALID_OPERATION); 250701e04c3fSmrg if (!bufObj) 25087117f1b4Smrg return; 25097117f1b4Smrg 251001e04c3fSmrg if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size, false, 251101e04c3fSmrg "glGetBufferSubData")) { 2512af69d88dSmrg return; 2513af69d88dSmrg } 2514af69d88dSmrg 251501e04c3fSmrg assert(ctx->Driver.GetBufferSubData); 251601e04c3fSmrg ctx->Driver.GetBufferSubData(ctx, offset, size, data, bufObj); 25177117f1b4Smrg} 25187117f1b4Smrg 25197117f1b4Smrgvoid GLAPIENTRY 252001e04c3fSmrg_mesa_GetNamedBufferSubData(GLuint buffer, GLintptr offset, 252101e04c3fSmrg GLsizeiptr size, GLvoid *data) 25227117f1b4Smrg{ 25237117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 25247117f1b4Smrg struct gl_buffer_object *bufObj; 25257117f1b4Smrg 252601e04c3fSmrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, 252701e04c3fSmrg "glGetNamedBufferSubData"); 252801e04c3fSmrg if (!bufObj) 252901e04c3fSmrg return; 253001e04c3fSmrg 253101e04c3fSmrg if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size, false, 253201e04c3fSmrg "glGetNamedBufferSubData")) { 25337117f1b4Smrg return; 25347117f1b4Smrg } 25357117f1b4Smrg 253601e04c3fSmrg assert(ctx->Driver.GetBufferSubData); 253701e04c3fSmrg ctx->Driver.GetBufferSubData(ctx, offset, size, data, bufObj); 2538af69d88dSmrg} 2539af69d88dSmrg 2540af69d88dSmrg 25417ec681f3Smrgvoid GLAPIENTRY 25427ec681f3Smrg_mesa_GetNamedBufferSubDataEXT(GLuint buffer, GLintptr offset, 25437ec681f3Smrg GLsizeiptr size, GLvoid *data) 25447ec681f3Smrg{ 25457ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 25467ec681f3Smrg struct gl_buffer_object *bufObj; 25477ec681f3Smrg 25487ec681f3Smrg if (!buffer) { 25497ec681f3Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 25507ec681f3Smrg "glGetNamedBufferSubDataEXT(buffer=0)"); 25517ec681f3Smrg return; 25527ec681f3Smrg } 25537ec681f3Smrg 25547ec681f3Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 25557ec681f3Smrg if (!_mesa_handle_bind_buffer_gen(ctx, buffer, 25567ec681f3Smrg &bufObj, "glGetNamedBufferSubDataEXT")) 25577ec681f3Smrg return; 25587ec681f3Smrg 25597ec681f3Smrg if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size, false, 25607ec681f3Smrg "glGetNamedBufferSubDataEXT")) { 25617ec681f3Smrg return; 25627ec681f3Smrg } 25637ec681f3Smrg 25647ec681f3Smrg assert(ctx->Driver.GetBufferSubData); 25657ec681f3Smrg ctx->Driver.GetBufferSubData(ctx, offset, size, data, bufObj); 25667ec681f3Smrg} 25677ec681f3Smrg 256801e04c3fSmrg/** 256901e04c3fSmrg * \param subdata true if caller is *SubData, false if *Data 257001e04c3fSmrg */ 257101e04c3fSmrgstatic ALWAYS_INLINE void 257201e04c3fSmrgclear_buffer_sub_data(struct gl_context *ctx, struct gl_buffer_object *bufObj, 257301e04c3fSmrg GLenum internalformat, GLintptr offset, GLsizeiptr size, 257401e04c3fSmrg GLenum format, GLenum type, const GLvoid *data, 257501e04c3fSmrg const char *func, bool subdata, bool no_error) 2576af69d88dSmrg{ 2577af69d88dSmrg mesa_format mesaFormat; 2578af69d88dSmrg GLubyte clearValue[MAX_PIXEL_BYTES]; 2579af69d88dSmrg GLsizeiptr clearValueSize; 2580af69d88dSmrg 258101e04c3fSmrg /* This checks for disallowed mappings. */ 258201e04c3fSmrg if (!no_error && !buffer_object_subdata_range_good(ctx, bufObj, offset, size, 258301e04c3fSmrg subdata, func)) { 2584af69d88dSmrg return; 2585af69d88dSmrg } 2586af69d88dSmrg 258701e04c3fSmrg if (no_error) { 258801e04c3fSmrg mesaFormat = _mesa_get_texbuffer_format(ctx, internalformat); 258901e04c3fSmrg } else { 259001e04c3fSmrg mesaFormat = validate_clear_buffer_format(ctx, internalformat, 259101e04c3fSmrg format, type, func); 2592af69d88dSmrg } 2593af69d88dSmrg 259401e04c3fSmrg if (mesaFormat == MESA_FORMAT_NONE) 2595af69d88dSmrg return; 2596af69d88dSmrg 2597af69d88dSmrg clearValueSize = _mesa_get_format_bytes(mesaFormat); 259801e04c3fSmrg if (!no_error && 259901e04c3fSmrg (offset % clearValueSize != 0 || size % clearValueSize != 0)) { 2600af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 260101e04c3fSmrg "%s(offset or size is not a multiple of " 260201e04c3fSmrg "internalformat size)", func); 2603af69d88dSmrg return; 2604af69d88dSmrg } 2605af69d88dSmrg 260601e04c3fSmrg /* Bail early. Negative size has already been checked. */ 260701e04c3fSmrg if (size == 0) 260801e04c3fSmrg return; 260901e04c3fSmrg 261001e04c3fSmrg bufObj->MinMaxCacheDirty = true; 261101e04c3fSmrg 2612af69d88dSmrg if (data == NULL) { 2613af69d88dSmrg /* clear to zeros, per the spec */ 261401e04c3fSmrg ctx->Driver.ClearBufferSubData(ctx, offset, size, 2615af69d88dSmrg NULL, clearValueSize, bufObj); 2616af69d88dSmrg return; 2617af69d88dSmrg } 2618af69d88dSmrg 2619af69d88dSmrg if (!convert_clear_buffer_data(ctx, mesaFormat, clearValue, 262001e04c3fSmrg format, type, data, func)) { 2621af69d88dSmrg return; 2622af69d88dSmrg } 2623af69d88dSmrg 262401e04c3fSmrg ctx->Driver.ClearBufferSubData(ctx, offset, size, 2625af69d88dSmrg clearValue, clearValueSize, bufObj); 2626af69d88dSmrg} 2627af69d88dSmrg 262801e04c3fSmrgstatic void 262901e04c3fSmrgclear_buffer_sub_data_error(struct gl_context *ctx, 263001e04c3fSmrg struct gl_buffer_object *bufObj, 263101e04c3fSmrg GLenum internalformat, GLintptr offset, 263201e04c3fSmrg GLsizeiptr size, GLenum format, GLenum type, 263301e04c3fSmrg const GLvoid *data, const char *func, bool subdata) 263401e04c3fSmrg{ 263501e04c3fSmrg clear_buffer_sub_data(ctx, bufObj, internalformat, offset, size, format, 263601e04c3fSmrg type, data, func, subdata, false); 263701e04c3fSmrg} 263801e04c3fSmrg 263901e04c3fSmrg 264001e04c3fSmrgstatic void 264101e04c3fSmrgclear_buffer_sub_data_no_error(struct gl_context *ctx, 264201e04c3fSmrg struct gl_buffer_object *bufObj, 264301e04c3fSmrg GLenum internalformat, GLintptr offset, 264401e04c3fSmrg GLsizeiptr size, GLenum format, GLenum type, 264501e04c3fSmrg const GLvoid *data, const char *func, 264601e04c3fSmrg bool subdata) 264701e04c3fSmrg{ 264801e04c3fSmrg clear_buffer_sub_data(ctx, bufObj, internalformat, offset, size, format, 264901e04c3fSmrg type, data, func, subdata, true); 265001e04c3fSmrg} 265101e04c3fSmrg 2652af69d88dSmrg 2653af69d88dSmrgvoid GLAPIENTRY 265401e04c3fSmrg_mesa_ClearBufferData_no_error(GLenum target, GLenum internalformat, 265501e04c3fSmrg GLenum format, GLenum type, const GLvoid *data) 2656af69d88dSmrg{ 2657af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 2658af69d88dSmrg 265901e04c3fSmrg struct gl_buffer_object **bufObj = get_buffer_target(ctx, target); 266001e04c3fSmrg clear_buffer_sub_data_no_error(ctx, *bufObj, internalformat, 0, 266101e04c3fSmrg (*bufObj)->Size, format, type, data, 266201e04c3fSmrg "glClearBufferData", false); 266301e04c3fSmrg} 2664af69d88dSmrg 2665af69d88dSmrg 266601e04c3fSmrgvoid GLAPIENTRY 266701e04c3fSmrg_mesa_ClearBufferData(GLenum target, GLenum internalformat, GLenum format, 266801e04c3fSmrg GLenum type, const GLvoid *data) 266901e04c3fSmrg{ 267001e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 267101e04c3fSmrg struct gl_buffer_object *bufObj; 2672af69d88dSmrg 267301e04c3fSmrg bufObj = get_buffer(ctx, "glClearBufferData", target, GL_INVALID_VALUE); 267401e04c3fSmrg if (!bufObj) 2675af69d88dSmrg return; 2676af69d88dSmrg 267701e04c3fSmrg clear_buffer_sub_data_error(ctx, bufObj, internalformat, 0, bufObj->Size, 267801e04c3fSmrg format, type, data, "glClearBufferData", false); 26797117f1b4Smrg} 26807117f1b4Smrg 26817117f1b4Smrg 268201e04c3fSmrgvoid GLAPIENTRY 268301e04c3fSmrg_mesa_ClearNamedBufferData_no_error(GLuint buffer, GLenum internalformat, 268401e04c3fSmrg GLenum format, GLenum type, 268501e04c3fSmrg const GLvoid *data) 26867117f1b4Smrg{ 26877117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 26884a49301eSmrg 268901e04c3fSmrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 269001e04c3fSmrg clear_buffer_sub_data_no_error(ctx, bufObj, internalformat, 0, bufObj->Size, 269101e04c3fSmrg format, type, data, "glClearNamedBufferData", 269201e04c3fSmrg false); 269301e04c3fSmrg} 26947117f1b4Smrg 2695af69d88dSmrg 269601e04c3fSmrgvoid GLAPIENTRY 269701e04c3fSmrg_mesa_ClearNamedBufferData(GLuint buffer, GLenum internalformat, 269801e04c3fSmrg GLenum format, GLenum type, const GLvoid *data) 269901e04c3fSmrg{ 270001e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 270101e04c3fSmrg struct gl_buffer_object *bufObj; 27027117f1b4Smrg 270301e04c3fSmrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glClearNamedBufferData"); 2704af69d88dSmrg if (!bufObj) 270501e04c3fSmrg return; 2706af69d88dSmrg 270701e04c3fSmrg clear_buffer_sub_data_error(ctx, bufObj, internalformat, 0, bufObj->Size, 270801e04c3fSmrg format, type, data, "glClearNamedBufferData", 270901e04c3fSmrg false); 271001e04c3fSmrg} 2711af69d88dSmrg 2712af69d88dSmrg 27137ec681f3Smrgvoid GLAPIENTRY 27147ec681f3Smrg_mesa_ClearNamedBufferDataEXT(GLuint buffer, GLenum internalformat, 27157ec681f3Smrg GLenum format, GLenum type, const GLvoid *data) 27167ec681f3Smrg{ 27177ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 27187ec681f3Smrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 27197ec681f3Smrg if (!_mesa_handle_bind_buffer_gen(ctx, buffer, 27207ec681f3Smrg &bufObj, "glClearNamedBufferDataEXT")) 27217ec681f3Smrg return; 27227ec681f3Smrg 27237ec681f3Smrg clear_buffer_sub_data_error(ctx, bufObj, internalformat, 0, bufObj->Size, 27247ec681f3Smrg format, type, data, "glClearNamedBufferDataEXT", 27257ec681f3Smrg false); 27267ec681f3Smrg} 27277ec681f3Smrg 27287ec681f3Smrg 272901e04c3fSmrgvoid GLAPIENTRY 273001e04c3fSmrg_mesa_ClearBufferSubData_no_error(GLenum target, GLenum internalformat, 273101e04c3fSmrg GLintptr offset, GLsizeiptr size, 273201e04c3fSmrg GLenum format, GLenum type, 273301e04c3fSmrg const GLvoid *data) 273401e04c3fSmrg{ 273501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 27367117f1b4Smrg 273701e04c3fSmrg struct gl_buffer_object **bufObj = get_buffer_target(ctx, target); 273801e04c3fSmrg clear_buffer_sub_data_no_error(ctx, *bufObj, internalformat, offset, size, 273901e04c3fSmrg format, type, data, "glClearBufferSubData", 274001e04c3fSmrg true); 274101e04c3fSmrg} 2742af69d88dSmrg 27437117f1b4Smrg 274401e04c3fSmrgvoid GLAPIENTRY 274501e04c3fSmrg_mesa_ClearBufferSubData(GLenum target, GLenum internalformat, 274601e04c3fSmrg GLintptr offset, GLsizeiptr size, 274701e04c3fSmrg GLenum format, GLenum type, 274801e04c3fSmrg const GLvoid *data) 274901e04c3fSmrg{ 275001e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 275101e04c3fSmrg struct gl_buffer_object *bufObj; 27524a49301eSmrg 275301e04c3fSmrg bufObj = get_buffer(ctx, "glClearBufferSubData", target, GL_INVALID_VALUE); 275401e04c3fSmrg if (!bufObj) 275501e04c3fSmrg return; 275601e04c3fSmrg 275701e04c3fSmrg clear_buffer_sub_data_error(ctx, bufObj, internalformat, offset, size, 275801e04c3fSmrg format, type, data, "glClearBufferSubData", 275901e04c3fSmrg true); 276001e04c3fSmrg} 27614a49301eSmrg 27627117f1b4Smrg 276301e04c3fSmrgvoid GLAPIENTRY 276401e04c3fSmrg_mesa_ClearNamedBufferSubData_no_error(GLuint buffer, GLenum internalformat, 276501e04c3fSmrg GLintptr offset, GLsizeiptr size, 276601e04c3fSmrg GLenum format, GLenum type, 276701e04c3fSmrg const GLvoid *data) 276801e04c3fSmrg{ 276901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 277001e04c3fSmrg 277101e04c3fSmrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 277201e04c3fSmrg clear_buffer_sub_data_no_error(ctx, bufObj, internalformat, offset, size, 277301e04c3fSmrg format, type, data, 277401e04c3fSmrg "glClearNamedBufferSubData", true); 27757117f1b4Smrg} 27767117f1b4Smrg 27777117f1b4Smrg 277801e04c3fSmrgvoid GLAPIENTRY 277901e04c3fSmrg_mesa_ClearNamedBufferSubData(GLuint buffer, GLenum internalformat, 278001e04c3fSmrg GLintptr offset, GLsizeiptr size, 278101e04c3fSmrg GLenum format, GLenum type, 278201e04c3fSmrg const GLvoid *data) 27837117f1b4Smrg{ 27847117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 27857117f1b4Smrg struct gl_buffer_object *bufObj; 27867117f1b4Smrg 278701e04c3fSmrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, 278801e04c3fSmrg "glClearNamedBufferSubData"); 2789af69d88dSmrg if (!bufObj) 279001e04c3fSmrg return; 279101e04c3fSmrg 279201e04c3fSmrg clear_buffer_sub_data_error(ctx, bufObj, internalformat, offset, size, 279301e04c3fSmrg format, type, data, "glClearNamedBufferSubData", 279401e04c3fSmrg true); 279501e04c3fSmrg} 279601e04c3fSmrg 27977ec681f3Smrgvoid GLAPIENTRY 27987ec681f3Smrg_mesa_ClearNamedBufferSubDataEXT(GLuint buffer, GLenum internalformat, 27997ec681f3Smrg GLintptr offset, GLsizeiptr size, 28007ec681f3Smrg GLenum format, GLenum type, 28017ec681f3Smrg const GLvoid *data) 28027ec681f3Smrg{ 28037ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 28047ec681f3Smrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 28057ec681f3Smrg if (!_mesa_handle_bind_buffer_gen(ctx, buffer, 28067ec681f3Smrg &bufObj, "glClearNamedBufferSubDataEXT")) 28077ec681f3Smrg return; 28087ec681f3Smrg 28097ec681f3Smrg clear_buffer_sub_data_error(ctx, bufObj, internalformat, offset, size, 28107ec681f3Smrg format, type, data, "glClearNamedBufferSubDataEXT", 28117ec681f3Smrg true); 28127ec681f3Smrg} 28137ec681f3Smrg 281401e04c3fSmrgstatic GLboolean 281501e04c3fSmrgunmap_buffer(struct gl_context *ctx, struct gl_buffer_object *bufObj) 281601e04c3fSmrg{ 281701e04c3fSmrg GLboolean status = ctx->Driver.UnmapBuffer(ctx, bufObj, MAP_USER); 281801e04c3fSmrg bufObj->Mappings[MAP_USER].AccessFlags = 0; 281901e04c3fSmrg assert(bufObj->Mappings[MAP_USER].Pointer == NULL); 282001e04c3fSmrg assert(bufObj->Mappings[MAP_USER].Offset == 0); 282101e04c3fSmrg assert(bufObj->Mappings[MAP_USER].Length == 0); 282201e04c3fSmrg 282301e04c3fSmrg return status; 282401e04c3fSmrg} 282501e04c3fSmrg 282601e04c3fSmrgstatic GLboolean 282701e04c3fSmrgvalidate_and_unmap_buffer(struct gl_context *ctx, 282801e04c3fSmrg struct gl_buffer_object *bufObj, 282901e04c3fSmrg const char *func) 283001e04c3fSmrg{ 283101e04c3fSmrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 2832af69d88dSmrg 2833af69d88dSmrg if (!_mesa_bufferobj_mapped(bufObj, MAP_USER)) { 283401e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 283501e04c3fSmrg "%s(buffer is not mapped)", func); 28367117f1b4Smrg return GL_FALSE; 28377117f1b4Smrg } 28387117f1b4Smrg 28394a49301eSmrg#ifdef BOUNDS_CHECK 28407ec681f3Smrg if (bufObj->Mappings[MAP_USER].AccessFlags != GL_READ_ONLY_ARB) { 28417ec681f3Smrg GLubyte *buf = (GLubyte *) bufObj->Mappings[MAP_USER].Pointer; 28424a49301eSmrg GLuint i; 28434a49301eSmrg /* check that last 100 bytes are still = magic value */ 28444a49301eSmrg for (i = 0; i < 100; i++) { 28454a49301eSmrg GLuint pos = bufObj->Size - i - 1; 28464a49301eSmrg if (buf[pos] != 123) { 28474a49301eSmrg _mesa_warning(ctx, "Out of bounds buffer object write detected" 28484a49301eSmrg " at position %d (value = %u)\n", 28494a49301eSmrg pos, buf[pos]); 28504a49301eSmrg } 28514a49301eSmrg } 28524a49301eSmrg } 28534a49301eSmrg#endif 28544a49301eSmrg 28554a49301eSmrg#ifdef VBO_DEBUG 28567ec681f3Smrg if (bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_WRITE_BIT) { 28574a49301eSmrg GLuint i, unchanged = 0; 28587ec681f3Smrg GLubyte *b = (GLubyte *) bufObj->Mappings[MAP_USER].Pointer; 28594a49301eSmrg GLint pos = -1; 28604a49301eSmrg /* check which bytes changed */ 28614a49301eSmrg for (i = 0; i < bufObj->Size - 1; i++) { 28624a49301eSmrg if (b[i] == (i & 0xff) && b[i+1] == ((i+1) & 0xff)) { 28634a49301eSmrg unchanged++; 28644a49301eSmrg if (pos == -1) 28654a49301eSmrg pos = i; 28664a49301eSmrg } 28674a49301eSmrg } 28684a49301eSmrg if (unchanged) { 2869cdc920a0Smrg printf("glUnmapBufferARB(%u): %u of %ld unchanged, starting at %d\n", 28704a49301eSmrg bufObj->Name, unchanged, bufObj->Size, pos); 28714a49301eSmrg } 28724a49301eSmrg } 28734a49301eSmrg#endif 28744a49301eSmrg 287501e04c3fSmrg return unmap_buffer(ctx, bufObj); 28767117f1b4Smrg} 28777117f1b4Smrg 287801e04c3fSmrgGLboolean GLAPIENTRY 287901e04c3fSmrg_mesa_UnmapBuffer_no_error(GLenum target) 288001e04c3fSmrg{ 288101e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 288201e04c3fSmrg struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target); 288301e04c3fSmrg struct gl_buffer_object *bufObj = *bufObjPtr; 288401e04c3fSmrg 288501e04c3fSmrg return unmap_buffer(ctx, bufObj); 288601e04c3fSmrg} 28877117f1b4Smrg 288801e04c3fSmrgGLboolean GLAPIENTRY 288901e04c3fSmrg_mesa_UnmapBuffer(GLenum target) 28907117f1b4Smrg{ 28917117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 28927117f1b4Smrg struct gl_buffer_object *bufObj; 28937117f1b4Smrg 289401e04c3fSmrg bufObj = get_buffer(ctx, "glUnmapBuffer", target, GL_INVALID_OPERATION); 2895af69d88dSmrg if (!bufObj) 289601e04c3fSmrg return GL_FALSE; 28973464ebd5Sriastradh 289801e04c3fSmrg return validate_and_unmap_buffer(ctx, bufObj, "glUnmapBuffer"); 2899cdc920a0Smrg} 2900cdc920a0Smrg 290101e04c3fSmrgGLboolean GLAPIENTRY 29027ec681f3Smrg_mesa_UnmapNamedBufferEXT_no_error(GLuint buffer) 290301e04c3fSmrg{ 290401e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 290501e04c3fSmrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 2906cdc920a0Smrg 290701e04c3fSmrg return unmap_buffer(ctx, bufObj); 290801e04c3fSmrg} 290901e04c3fSmrg 291001e04c3fSmrgGLboolean GLAPIENTRY 29117ec681f3Smrg_mesa_UnmapNamedBufferEXT(GLuint buffer) 2912cdc920a0Smrg{ 2913cdc920a0Smrg GET_CURRENT_CONTEXT(ctx); 2914cdc920a0Smrg struct gl_buffer_object *bufObj; 2915cdc920a0Smrg 29167ec681f3Smrg if (!buffer) { 29177ec681f3Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 29187ec681f3Smrg "glUnmapNamedBufferEXT(buffer=0)"); 29197ec681f3Smrg return GL_FALSE; 29207ec681f3Smrg } 29217ec681f3Smrg 292201e04c3fSmrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glUnmapNamedBuffer"); 2923af69d88dSmrg if (!bufObj) 292401e04c3fSmrg return GL_FALSE; 292501e04c3fSmrg 292601e04c3fSmrg return validate_and_unmap_buffer(ctx, bufObj, "glUnmapNamedBuffer"); 292701e04c3fSmrg} 292801e04c3fSmrg 2929cdc920a0Smrg 293001e04c3fSmrgstatic bool 293101e04c3fSmrgget_buffer_parameter(struct gl_context *ctx, 293201e04c3fSmrg struct gl_buffer_object *bufObj, GLenum pname, 293301e04c3fSmrg GLint64 *params, const char *func) 293401e04c3fSmrg{ 2935cdc920a0Smrg switch (pname) { 2936cdc920a0Smrg case GL_BUFFER_SIZE_ARB: 2937cdc920a0Smrg *params = bufObj->Size; 293801e04c3fSmrg break; 2939cdc920a0Smrg case GL_BUFFER_USAGE_ARB: 2940cdc920a0Smrg *params = bufObj->Usage; 294101e04c3fSmrg break; 2942cdc920a0Smrg case GL_BUFFER_ACCESS_ARB: 2943af69d88dSmrg *params = simplified_access_mode(ctx, 294401e04c3fSmrg bufObj->Mappings[MAP_USER].AccessFlags); 294501e04c3fSmrg break; 294601e04c3fSmrg case GL_BUFFER_MAPPED_ARB: 294701e04c3fSmrg *params = _mesa_bufferobj_mapped(bufObj, MAP_USER); 294801e04c3fSmrg break; 29493464ebd5Sriastradh case GL_BUFFER_ACCESS_FLAGS: 2950af69d88dSmrg if (!ctx->Extensions.ARB_map_buffer_range) 29513464ebd5Sriastradh goto invalid_pname; 2952af69d88dSmrg *params = bufObj->Mappings[MAP_USER].AccessFlags; 295301e04c3fSmrg break; 29543464ebd5Sriastradh case GL_BUFFER_MAP_OFFSET: 2955af69d88dSmrg if (!ctx->Extensions.ARB_map_buffer_range) 29563464ebd5Sriastradh goto invalid_pname; 2957af69d88dSmrg *params = bufObj->Mappings[MAP_USER].Offset; 295801e04c3fSmrg break; 29593464ebd5Sriastradh case GL_BUFFER_MAP_LENGTH: 2960af69d88dSmrg if (!ctx->Extensions.ARB_map_buffer_range) 2961af69d88dSmrg goto invalid_pname; 2962af69d88dSmrg *params = bufObj->Mappings[MAP_USER].Length; 296301e04c3fSmrg break; 2964af69d88dSmrg case GL_BUFFER_IMMUTABLE_STORAGE: 2965af69d88dSmrg if (!ctx->Extensions.ARB_buffer_storage) 2966af69d88dSmrg goto invalid_pname; 2967af69d88dSmrg *params = bufObj->Immutable; 296801e04c3fSmrg break; 2969af69d88dSmrg case GL_BUFFER_STORAGE_FLAGS: 2970af69d88dSmrg if (!ctx->Extensions.ARB_buffer_storage) 29713464ebd5Sriastradh goto invalid_pname; 2972af69d88dSmrg *params = bufObj->StorageFlags; 297301e04c3fSmrg break; 29743464ebd5Sriastradh default: 297501e04c3fSmrg goto invalid_pname; 29767117f1b4Smrg } 29773464ebd5Sriastradh 297801e04c3fSmrg return true; 297901e04c3fSmrg 29803464ebd5Sriastradhinvalid_pname: 298101e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname: %s)", func, 298201e04c3fSmrg _mesa_enum_to_string(pname)); 298301e04c3fSmrg return false; 298401e04c3fSmrg} 298501e04c3fSmrg 298601e04c3fSmrgvoid GLAPIENTRY 298701e04c3fSmrg_mesa_GetBufferParameteriv(GLenum target, GLenum pname, GLint *params) 298801e04c3fSmrg{ 298901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 299001e04c3fSmrg struct gl_buffer_object *bufObj; 299101e04c3fSmrg GLint64 parameter; 299201e04c3fSmrg 299301e04c3fSmrg bufObj = get_buffer(ctx, "glGetBufferParameteriv", target, 299401e04c3fSmrg GL_INVALID_OPERATION); 299501e04c3fSmrg if (!bufObj) 299601e04c3fSmrg return; 299701e04c3fSmrg 299801e04c3fSmrg if (!get_buffer_parameter(ctx, bufObj, pname, ¶meter, 299901e04c3fSmrg "glGetBufferParameteriv")) 300001e04c3fSmrg return; /* Error already recorded. */ 300101e04c3fSmrg 300201e04c3fSmrg *params = (GLint) parameter; 300301e04c3fSmrg} 300401e04c3fSmrg 300501e04c3fSmrgvoid GLAPIENTRY 300601e04c3fSmrg_mesa_GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params) 300701e04c3fSmrg{ 300801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 300901e04c3fSmrg struct gl_buffer_object *bufObj; 301001e04c3fSmrg GLint64 parameter; 301101e04c3fSmrg 301201e04c3fSmrg bufObj = get_buffer(ctx, "glGetBufferParameteri64v", target, 301301e04c3fSmrg GL_INVALID_OPERATION); 301401e04c3fSmrg if (!bufObj) 301501e04c3fSmrg return; 301601e04c3fSmrg 301701e04c3fSmrg if (!get_buffer_parameter(ctx, bufObj, pname, ¶meter, 301801e04c3fSmrg "glGetBufferParameteri64v")) 301901e04c3fSmrg return; /* Error already recorded. */ 302001e04c3fSmrg 302101e04c3fSmrg *params = parameter; 302201e04c3fSmrg} 302301e04c3fSmrg 302401e04c3fSmrgvoid GLAPIENTRY 302501e04c3fSmrg_mesa_GetNamedBufferParameteriv(GLuint buffer, GLenum pname, GLint *params) 302601e04c3fSmrg{ 302701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 302801e04c3fSmrg struct gl_buffer_object *bufObj; 302901e04c3fSmrg GLint64 parameter; 303001e04c3fSmrg 303101e04c3fSmrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, 303201e04c3fSmrg "glGetNamedBufferParameteriv"); 303301e04c3fSmrg if (!bufObj) 303401e04c3fSmrg return; 303501e04c3fSmrg 303601e04c3fSmrg if (!get_buffer_parameter(ctx, bufObj, pname, ¶meter, 303701e04c3fSmrg "glGetNamedBufferParameteriv")) 303801e04c3fSmrg return; /* Error already recorded. */ 303901e04c3fSmrg 304001e04c3fSmrg *params = (GLint) parameter; 304101e04c3fSmrg} 304201e04c3fSmrg 30437ec681f3Smrgvoid GLAPIENTRY 30447ec681f3Smrg_mesa_GetNamedBufferParameterivEXT(GLuint buffer, GLenum pname, GLint *params) 30457ec681f3Smrg{ 30467ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 30477ec681f3Smrg struct gl_buffer_object *bufObj; 30487ec681f3Smrg GLint64 parameter; 30497ec681f3Smrg 30507ec681f3Smrg if (!buffer) { 30517ec681f3Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 30527ec681f3Smrg "glGetNamedBufferParameterivEXT: buffer=0"); 30537ec681f3Smrg return; 30547ec681f3Smrg } 30557ec681f3Smrg 30567ec681f3Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 30577ec681f3Smrg if (!_mesa_handle_bind_buffer_gen(ctx, buffer, 30587ec681f3Smrg &bufObj, "glGetNamedBufferParameterivEXT")) 30597ec681f3Smrg return; 30607ec681f3Smrg 30617ec681f3Smrg if (!get_buffer_parameter(ctx, bufObj, pname, ¶meter, 30627ec681f3Smrg "glGetNamedBufferParameterivEXT")) 30637ec681f3Smrg return; /* Error already recorded. */ 30647ec681f3Smrg 30657ec681f3Smrg *params = (GLint) parameter; 30667ec681f3Smrg} 30677ec681f3Smrg 306801e04c3fSmrgvoid GLAPIENTRY 306901e04c3fSmrg_mesa_GetNamedBufferParameteri64v(GLuint buffer, GLenum pname, 307001e04c3fSmrg GLint64 *params) 307101e04c3fSmrg{ 307201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 307301e04c3fSmrg struct gl_buffer_object *bufObj; 307401e04c3fSmrg GLint64 parameter; 307501e04c3fSmrg 307601e04c3fSmrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, 307701e04c3fSmrg "glGetNamedBufferParameteri64v"); 307801e04c3fSmrg if (!bufObj) 307901e04c3fSmrg return; 308001e04c3fSmrg 308101e04c3fSmrg if (!get_buffer_parameter(ctx, bufObj, pname, ¶meter, 308201e04c3fSmrg "glGetNamedBufferParameteri64v")) 308301e04c3fSmrg return; /* Error already recorded. */ 308401e04c3fSmrg 308501e04c3fSmrg *params = parameter; 30867117f1b4Smrg} 30877117f1b4Smrg 30887117f1b4Smrg 30897117f1b4Smrgvoid GLAPIENTRY 3090af69d88dSmrg_mesa_GetBufferPointerv(GLenum target, GLenum pname, GLvoid **params) 30917117f1b4Smrg{ 30927117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 309301e04c3fSmrg struct gl_buffer_object *bufObj; 30947117f1b4Smrg 309501e04c3fSmrg if (pname != GL_BUFFER_MAP_POINTER) { 309601e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetBufferPointerv(pname != " 309701e04c3fSmrg "GL_BUFFER_MAP_POINTER)"); 30987117f1b4Smrg return; 30997117f1b4Smrg } 31007117f1b4Smrg 310101e04c3fSmrg bufObj = get_buffer(ctx, "glGetBufferPointerv", target, 3102af69d88dSmrg GL_INVALID_OPERATION); 3103af69d88dSmrg if (!bufObj) 31047117f1b4Smrg return; 31057117f1b4Smrg 3106af69d88dSmrg *params = bufObj->Mappings[MAP_USER].Pointer; 31077117f1b4Smrg} 31084a49301eSmrg 31094a49301eSmrgvoid GLAPIENTRY 311001e04c3fSmrg_mesa_GetNamedBufferPointerv(GLuint buffer, GLenum pname, GLvoid **params) 31114a49301eSmrg{ 31124a49301eSmrg GET_CURRENT_CONTEXT(ctx); 311301e04c3fSmrg struct gl_buffer_object *bufObj; 31144a49301eSmrg 311501e04c3fSmrg if (pname != GL_BUFFER_MAP_POINTER) { 311601e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetNamedBufferPointerv(pname != " 311701e04c3fSmrg "GL_BUFFER_MAP_POINTER)"); 31184a49301eSmrg return; 311901e04c3fSmrg } 31204a49301eSmrg 312101e04c3fSmrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, 312201e04c3fSmrg "glGetNamedBufferPointerv"); 312301e04c3fSmrg if (!bufObj) 31244a49301eSmrg return; 31254a49301eSmrg 312601e04c3fSmrg *params = bufObj->Mappings[MAP_USER].Pointer; 312701e04c3fSmrg} 312801e04c3fSmrg 31297ec681f3Smrgvoid GLAPIENTRY 31307ec681f3Smrg_mesa_GetNamedBufferPointervEXT(GLuint buffer, GLenum pname, GLvoid **params) 31317ec681f3Smrg{ 31327ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 31337ec681f3Smrg struct gl_buffer_object *bufObj; 31347ec681f3Smrg 31357ec681f3Smrg if (!buffer) { 31367ec681f3Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 31377ec681f3Smrg "glGetNamedBufferPointervEXT(buffer=0)"); 31387ec681f3Smrg return; 31397ec681f3Smrg } 31407ec681f3Smrg if (pname != GL_BUFFER_MAP_POINTER) { 31417ec681f3Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glGetNamedBufferPointervEXT(pname != " 31427ec681f3Smrg "GL_BUFFER_MAP_POINTER)"); 31437ec681f3Smrg return; 31447ec681f3Smrg } 31457ec681f3Smrg 31467ec681f3Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 31477ec681f3Smrg if (!_mesa_handle_bind_buffer_gen(ctx, buffer, 31487ec681f3Smrg &bufObj, "glGetNamedBufferPointervEXT")) 31497ec681f3Smrg return; 31507ec681f3Smrg 31517ec681f3Smrg *params = bufObj->Mappings[MAP_USER].Pointer; 31527ec681f3Smrg} 315301e04c3fSmrg 315401e04c3fSmrgstatic void 315501e04c3fSmrgcopy_buffer_sub_data(struct gl_context *ctx, struct gl_buffer_object *src, 315601e04c3fSmrg struct gl_buffer_object *dst, GLintptr readOffset, 315701e04c3fSmrg GLintptr writeOffset, GLsizeiptr size, const char *func) 315801e04c3fSmrg{ 3159af69d88dSmrg if (_mesa_check_disallowed_mapping(src)) { 31604a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 316101e04c3fSmrg "%s(readBuffer is mapped)", func); 31624a49301eSmrg return; 31634a49301eSmrg } 31644a49301eSmrg 3165af69d88dSmrg if (_mesa_check_disallowed_mapping(dst)) { 31664a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 316701e04c3fSmrg "%s(writeBuffer is mapped)", func); 31684a49301eSmrg return; 31694a49301eSmrg } 31704a49301eSmrg 31714a49301eSmrg if (readOffset < 0) { 31724a49301eSmrg _mesa_error(ctx, GL_INVALID_VALUE, 317301e04c3fSmrg "%s(readOffset %d < 0)", func, (int) readOffset); 31744a49301eSmrg return; 31754a49301eSmrg } 31764a49301eSmrg 31774a49301eSmrg if (writeOffset < 0) { 31784a49301eSmrg _mesa_error(ctx, GL_INVALID_VALUE, 317901e04c3fSmrg "%s(writeOffset %d < 0)", func, (int) writeOffset); 3180af69d88dSmrg return; 3181af69d88dSmrg } 3182af69d88dSmrg 3183af69d88dSmrg if (size < 0) { 3184af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 318501e04c3fSmrg "%s(size %d < 0)", func, (int) size); 31864a49301eSmrg return; 31874a49301eSmrg } 31884a49301eSmrg 31894a49301eSmrg if (readOffset + size > src->Size) { 31904a49301eSmrg _mesa_error(ctx, GL_INVALID_VALUE, 319101e04c3fSmrg "%s(readOffset %d + size %d > src_buffer_size %d)", func, 319201e04c3fSmrg (int) readOffset, (int) size, (int) src->Size); 31934a49301eSmrg return; 31944a49301eSmrg } 31954a49301eSmrg 31964a49301eSmrg if (writeOffset + size > dst->Size) { 31974a49301eSmrg _mesa_error(ctx, GL_INVALID_VALUE, 319801e04c3fSmrg "%s(writeOffset %d + size %d > dst_buffer_size %d)", func, 319901e04c3fSmrg (int) writeOffset, (int) size, (int) dst->Size); 32004a49301eSmrg return; 32014a49301eSmrg } 32024a49301eSmrg 32034a49301eSmrg if (src == dst) { 32044a49301eSmrg if (readOffset + size <= writeOffset) { 32054a49301eSmrg /* OK */ 32064a49301eSmrg } 32074a49301eSmrg else if (writeOffset + size <= readOffset) { 32084a49301eSmrg /* OK */ 32094a49301eSmrg } 32104a49301eSmrg else { 32114a49301eSmrg /* overlapping src/dst is illegal */ 32124a49301eSmrg _mesa_error(ctx, GL_INVALID_VALUE, 321301e04c3fSmrg "%s(overlapping src/dst)", func); 32144a49301eSmrg return; 32154a49301eSmrg } 32164a49301eSmrg } 32174a49301eSmrg 321801e04c3fSmrg dst->MinMaxCacheDirty = true; 321901e04c3fSmrg 32204a49301eSmrg ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size); 32214a49301eSmrg} 32224a49301eSmrg 322301e04c3fSmrgvoid GLAPIENTRY 322401e04c3fSmrg_mesa_CopyBufferSubData_no_error(GLenum readTarget, GLenum writeTarget, 322501e04c3fSmrg GLintptr readOffset, GLintptr writeOffset, 322601e04c3fSmrg GLsizeiptr size) 322701e04c3fSmrg{ 322801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 322901e04c3fSmrg 323001e04c3fSmrg struct gl_buffer_object **src_ptr = get_buffer_target(ctx, readTarget); 323101e04c3fSmrg struct gl_buffer_object *src = *src_ptr; 32324a49301eSmrg 323301e04c3fSmrg struct gl_buffer_object **dst_ptr = get_buffer_target(ctx, writeTarget); 323401e04c3fSmrg struct gl_buffer_object *dst = *dst_ptr; 323501e04c3fSmrg 323601e04c3fSmrg dst->MinMaxCacheDirty = true; 323701e04c3fSmrg ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, 323801e04c3fSmrg size); 323901e04c3fSmrg} 324001e04c3fSmrg 324101e04c3fSmrgvoid GLAPIENTRY 324201e04c3fSmrg_mesa_CopyBufferSubData(GLenum readTarget, GLenum writeTarget, 324301e04c3fSmrg GLintptr readOffset, GLintptr writeOffset, 324401e04c3fSmrg GLsizeiptr size) 32454a49301eSmrg{ 32464a49301eSmrg GET_CURRENT_CONTEXT(ctx); 324701e04c3fSmrg struct gl_buffer_object *src, *dst; 32484a49301eSmrg 324901e04c3fSmrg src = get_buffer(ctx, "glCopyBufferSubData", readTarget, 325001e04c3fSmrg GL_INVALID_OPERATION); 325101e04c3fSmrg if (!src) 325201e04c3fSmrg return; 32534a49301eSmrg 325401e04c3fSmrg dst = get_buffer(ctx, "glCopyBufferSubData", writeTarget, 325501e04c3fSmrg GL_INVALID_OPERATION); 325601e04c3fSmrg if (!dst) 325701e04c3fSmrg return; 325801e04c3fSmrg 325901e04c3fSmrg copy_buffer_sub_data(ctx, src, dst, readOffset, writeOffset, size, 326001e04c3fSmrg "glCopyBufferSubData"); 326101e04c3fSmrg} 326201e04c3fSmrg 32637ec681f3Smrgvoid GLAPIENTRY 32647ec681f3Smrg_mesa_NamedCopyBufferSubDataEXT(GLuint readBuffer, GLuint writeBuffer, 32657ec681f3Smrg GLintptr readOffset, GLintptr writeOffset, 32667ec681f3Smrg GLsizeiptr size) 32677ec681f3Smrg{ 32687ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 32697ec681f3Smrg struct gl_buffer_object *src, *dst; 32707ec681f3Smrg 32717ec681f3Smrg src = _mesa_lookup_bufferobj(ctx, readBuffer); 32727ec681f3Smrg if (!_mesa_handle_bind_buffer_gen(ctx, readBuffer, 32737ec681f3Smrg &src, 32747ec681f3Smrg "glNamedCopyBufferSubDataEXT")) 32757ec681f3Smrg return; 32767ec681f3Smrg 32777ec681f3Smrg dst = _mesa_lookup_bufferobj(ctx, writeBuffer); 32787ec681f3Smrg if (!_mesa_handle_bind_buffer_gen(ctx, writeBuffer, 32797ec681f3Smrg &dst, 32807ec681f3Smrg "glNamedCopyBufferSubDataEXT")) 32817ec681f3Smrg return; 32827ec681f3Smrg 32837ec681f3Smrg copy_buffer_sub_data(ctx, src, dst, readOffset, writeOffset, size, 32847ec681f3Smrg "glNamedCopyBufferSubDataEXT"); 32857ec681f3Smrg} 32867ec681f3Smrg 328701e04c3fSmrgvoid GLAPIENTRY 328801e04c3fSmrg_mesa_CopyNamedBufferSubData_no_error(GLuint readBuffer, GLuint writeBuffer, 328901e04c3fSmrg GLintptr readOffset, 329001e04c3fSmrg GLintptr writeOffset, GLsizeiptr size) 329101e04c3fSmrg{ 329201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 329301e04c3fSmrg 329401e04c3fSmrg struct gl_buffer_object *src = _mesa_lookup_bufferobj(ctx, readBuffer); 329501e04c3fSmrg struct gl_buffer_object *dst = _mesa_lookup_bufferobj(ctx, writeBuffer); 329601e04c3fSmrg 329701e04c3fSmrg dst->MinMaxCacheDirty = true; 329801e04c3fSmrg ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, 329901e04c3fSmrg size); 330001e04c3fSmrg} 330101e04c3fSmrg 330201e04c3fSmrgvoid GLAPIENTRY 330301e04c3fSmrg_mesa_CopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer, 330401e04c3fSmrg GLintptr readOffset, GLintptr writeOffset, 330501e04c3fSmrg GLsizeiptr size) 330601e04c3fSmrg{ 330701e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 330801e04c3fSmrg struct gl_buffer_object *src, *dst; 330901e04c3fSmrg 331001e04c3fSmrg src = _mesa_lookup_bufferobj_err(ctx, readBuffer, 331101e04c3fSmrg "glCopyNamedBufferSubData"); 331201e04c3fSmrg if (!src) 331301e04c3fSmrg return; 331401e04c3fSmrg 331501e04c3fSmrg dst = _mesa_lookup_bufferobj_err(ctx, writeBuffer, 331601e04c3fSmrg "glCopyNamedBufferSubData"); 331701e04c3fSmrg if (!dst) 331801e04c3fSmrg return; 331901e04c3fSmrg 332001e04c3fSmrg copy_buffer_sub_data(ctx, src, dst, readOffset, writeOffset, size, 332101e04c3fSmrg "glCopyNamedBufferSubData"); 332201e04c3fSmrg} 332301e04c3fSmrg 33247ec681f3Smrgvoid GLAPIENTRY 33257ec681f3Smrg_mesa_InternalBufferSubDataCopyMESA(GLintptr srcBuffer, GLuint srcOffset, 33267ec681f3Smrg GLuint dstTargetOrName, GLintptr dstOffset, 33277ec681f3Smrg GLsizeiptr size, GLboolean named, 33287ec681f3Smrg GLboolean ext_dsa) 33297ec681f3Smrg{ 33307ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 33317ec681f3Smrg struct gl_buffer_object *src = (struct gl_buffer_object *)srcBuffer; 33327ec681f3Smrg struct gl_buffer_object *dst; 33337ec681f3Smrg const char *func; 33347ec681f3Smrg 33357ec681f3Smrg /* Handle behavior for all 3 variants. */ 33367ec681f3Smrg if (named && ext_dsa) { 33377ec681f3Smrg func = "glNamedBufferSubDataEXT"; 33387ec681f3Smrg dst = _mesa_lookup_bufferobj(ctx, dstTargetOrName); 33397ec681f3Smrg if (!_mesa_handle_bind_buffer_gen(ctx, dstTargetOrName, &dst, func)) 33407ec681f3Smrg goto done; 33417ec681f3Smrg } else if (named) { 33427ec681f3Smrg func = "glNamedBufferSubData"; 33437ec681f3Smrg dst = _mesa_lookup_bufferobj_err(ctx, dstTargetOrName, func); 33447ec681f3Smrg if (!dst) 33457ec681f3Smrg goto done; 33467ec681f3Smrg } else { 33477ec681f3Smrg assert(!ext_dsa); 33487ec681f3Smrg func = "glBufferSubData"; 33497ec681f3Smrg dst = get_buffer(ctx, func, dstTargetOrName, GL_INVALID_OPERATION); 33507ec681f3Smrg if (!dst) 33517ec681f3Smrg goto done; 33527ec681f3Smrg } 33537ec681f3Smrg 33547ec681f3Smrg if (!validate_buffer_sub_data(ctx, dst, dstOffset, size, func)) 33557ec681f3Smrg goto done; /* the error is already set */ 33567ec681f3Smrg 33577ec681f3Smrg dst->MinMaxCacheDirty = true; 33587ec681f3Smrg ctx->Driver.CopyBufferSubData(ctx, src, dst, srcOffset, dstOffset, size); 33597ec681f3Smrg 33607ec681f3Smrgdone: 33617ec681f3Smrg /* The caller passes the reference to this function, so unreference it. */ 33627ec681f3Smrg _mesa_reference_buffer_object(ctx, &src, NULL); 33637ec681f3Smrg} 33647ec681f3Smrg 336501e04c3fSmrgstatic bool 336601e04c3fSmrgvalidate_map_buffer_range(struct gl_context *ctx, 336701e04c3fSmrg struct gl_buffer_object *bufObj, GLintptr offset, 336801e04c3fSmrg GLsizeiptr length, GLbitfield access, 336901e04c3fSmrg const char *func) 337001e04c3fSmrg{ 337101e04c3fSmrg GLbitfield allowed_access; 337201e04c3fSmrg 337301e04c3fSmrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, false); 33744a49301eSmrg 33754a49301eSmrg if (offset < 0) { 33764a49301eSmrg _mesa_error(ctx, GL_INVALID_VALUE, 337701e04c3fSmrg "%s(offset %ld < 0)", func, (long) offset); 337801e04c3fSmrg return false; 33794a49301eSmrg } 33804a49301eSmrg 33814a49301eSmrg if (length < 0) { 33824a49301eSmrg _mesa_error(ctx, GL_INVALID_VALUE, 338301e04c3fSmrg "%s(length %ld < 0)", func, (long) length); 338401e04c3fSmrg return false; 33853464ebd5Sriastradh } 33863464ebd5Sriastradh 3387af69d88dSmrg /* Page 38 of the PDF of the OpenGL ES 3.0 spec says: 3388af69d88dSmrg * 3389af69d88dSmrg * "An INVALID_OPERATION error is generated for any of the following 3390af69d88dSmrg * conditions: 3391af69d88dSmrg * 3392af69d88dSmrg * * <length> is zero." 339301e04c3fSmrg * 339401e04c3fSmrg * Additionally, page 94 of the PDF of the OpenGL 4.5 core spec 339501e04c3fSmrg * (30.10.2014) also says this, so it's no longer allowed for desktop GL, 339601e04c3fSmrg * either. 3397af69d88dSmrg */ 339801e04c3fSmrg if (length == 0) { 339901e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(length = 0)", func); 340001e04c3fSmrg return false; 3401af69d88dSmrg } 3402af69d88dSmrg 3403af69d88dSmrg allowed_access = GL_MAP_READ_BIT | 3404af69d88dSmrg GL_MAP_WRITE_BIT | 3405af69d88dSmrg GL_MAP_INVALIDATE_RANGE_BIT | 3406af69d88dSmrg GL_MAP_INVALIDATE_BUFFER_BIT | 3407af69d88dSmrg GL_MAP_FLUSH_EXPLICIT_BIT | 3408af69d88dSmrg GL_MAP_UNSYNCHRONIZED_BIT; 3409af69d88dSmrg 3410af69d88dSmrg if (ctx->Extensions.ARB_buffer_storage) { 3411af69d88dSmrg allowed_access |= GL_MAP_PERSISTENT_BIT | 3412af69d88dSmrg GL_MAP_COHERENT_BIT; 3413af69d88dSmrg } 3414af69d88dSmrg 3415af69d88dSmrg if (access & ~allowed_access) { 341601e04c3fSmrg /* generate an error if any bits other than those allowed are set */ 341701e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 341801e04c3fSmrg "%s(access has undefined bits set)", func); 341901e04c3fSmrg return false; 34204a49301eSmrg } 34214a49301eSmrg 34224a49301eSmrg if ((access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)) == 0) { 34234a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 342401e04c3fSmrg "%s(access indicates neither read or write)", func); 342501e04c3fSmrg return false; 34264a49301eSmrg } 34274a49301eSmrg 34283464ebd5Sriastradh if ((access & GL_MAP_READ_BIT) && 34293464ebd5Sriastradh (access & (GL_MAP_INVALIDATE_RANGE_BIT | 34303464ebd5Sriastradh GL_MAP_INVALIDATE_BUFFER_BIT | 34313464ebd5Sriastradh GL_MAP_UNSYNCHRONIZED_BIT))) { 34323464ebd5Sriastradh _mesa_error(ctx, GL_INVALID_OPERATION, 343301e04c3fSmrg "%s(read access with disallowed bits)", func); 343401e04c3fSmrg return false; 34354a49301eSmrg } 34364a49301eSmrg 34374a49301eSmrg if ((access & GL_MAP_FLUSH_EXPLICIT_BIT) && 34384a49301eSmrg ((access & GL_MAP_WRITE_BIT) == 0)) { 34394a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 344001e04c3fSmrg "%s(access has flush explicit without write)", func); 344101e04c3fSmrg return false; 34424a49301eSmrg } 34434a49301eSmrg 3444af69d88dSmrg if (access & GL_MAP_READ_BIT && 3445af69d88dSmrg !(bufObj->StorageFlags & GL_MAP_READ_BIT)) { 3446af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 344701e04c3fSmrg "%s(buffer does not allow read access)", func); 344801e04c3fSmrg return false; 3449af69d88dSmrg } 3450af69d88dSmrg 3451af69d88dSmrg if (access & GL_MAP_WRITE_BIT && 3452af69d88dSmrg !(bufObj->StorageFlags & GL_MAP_WRITE_BIT)) { 3453af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 345401e04c3fSmrg "%s(buffer does not allow write access)", func); 345501e04c3fSmrg return false; 3456af69d88dSmrg } 3457af69d88dSmrg 3458af69d88dSmrg if (access & GL_MAP_COHERENT_BIT && 3459af69d88dSmrg !(bufObj->StorageFlags & GL_MAP_COHERENT_BIT)) { 3460af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 346101e04c3fSmrg "%s(buffer does not allow coherent access)", func); 346201e04c3fSmrg return false; 34634a49301eSmrg } 34644a49301eSmrg 346501e04c3fSmrg if (access & GL_MAP_PERSISTENT_BIT && 346601e04c3fSmrg !(bufObj->StorageFlags & GL_MAP_PERSISTENT_BIT)) { 34674a49301eSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 346801e04c3fSmrg "%s(buffer does not allow persistent access)", func); 346901e04c3fSmrg return false; 34704a49301eSmrg } 34714a49301eSmrg 347201e04c3fSmrg if (offset + length > bufObj->Size) { 34734a49301eSmrg _mesa_error(ctx, GL_INVALID_VALUE, 347401e04c3fSmrg "%s(offset %lu + length %lu > buffer_size %lu)", func, 347501e04c3fSmrg (unsigned long) offset, (unsigned long) length, 347601e04c3fSmrg (unsigned long) bufObj->Size); 347701e04c3fSmrg return false; 34784a49301eSmrg } 34794a49301eSmrg 348001e04c3fSmrg if (_mesa_bufferobj_mapped(bufObj, MAP_USER)) { 348101e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 348201e04c3fSmrg "%s(buffer already mapped)", func); 348301e04c3fSmrg return false; 348401e04c3fSmrg } 34854a49301eSmrg 348601e04c3fSmrg if (access & GL_MAP_WRITE_BIT) { 348701e04c3fSmrg bufObj->NumMapBufferWriteCalls++; 348801e04c3fSmrg if ((bufObj->Usage == GL_STATIC_DRAW || 348901e04c3fSmrg bufObj->Usage == GL_STATIC_COPY) && 349001e04c3fSmrg bufObj->NumMapBufferWriteCalls >= BUFFER_WARNING_CALL_COUNT) { 349101e04c3fSmrg BUFFER_USAGE_WARNING(ctx, 349201e04c3fSmrg "using %s(buffer %u, offset %u, length %u) to " 349301e04c3fSmrg "update a %s buffer", 349401e04c3fSmrg func, bufObj->Name, offset, length, 349501e04c3fSmrg _mesa_enum_to_string(bufObj->Usage)); 349601e04c3fSmrg } 349701e04c3fSmrg } 3498cdc920a0Smrg 349901e04c3fSmrg return true; 350001e04c3fSmrg} 3501cdc920a0Smrg 350201e04c3fSmrgstatic void * 350301e04c3fSmrgmap_buffer_range(struct gl_context *ctx, struct gl_buffer_object *bufObj, 350401e04c3fSmrg GLintptr offset, GLsizeiptr length, GLbitfield access, 350501e04c3fSmrg const char *func) 3506cdc920a0Smrg{ 350701e04c3fSmrg if (!bufObj->Size) { 350801e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s(buffer size = 0)", func); 350901e04c3fSmrg return NULL; 351001e04c3fSmrg } 3511cdc920a0Smrg 351201e04c3fSmrg assert(ctx->Driver.MapBufferRange); 351301e04c3fSmrg void *map = ctx->Driver.MapBufferRange(ctx, offset, length, access, bufObj, 351401e04c3fSmrg MAP_USER); 351501e04c3fSmrg if (!map) { 351601e04c3fSmrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s(map failed)", func); 3517cdc920a0Smrg } 351801e04c3fSmrg else { 351901e04c3fSmrg /* The driver callback should have set all these fields. 352001e04c3fSmrg * This is important because other modules (like VBO) might call 352101e04c3fSmrg * the driver function directly. 352201e04c3fSmrg */ 352301e04c3fSmrg assert(bufObj->Mappings[MAP_USER].Pointer == map); 352401e04c3fSmrg assert(bufObj->Mappings[MAP_USER].Length == length); 352501e04c3fSmrg assert(bufObj->Mappings[MAP_USER].Offset == offset); 352601e04c3fSmrg assert(bufObj->Mappings[MAP_USER].AccessFlags == access); 3527cdc920a0Smrg } 3528cdc920a0Smrg 352901e04c3fSmrg if (access & GL_MAP_WRITE_BIT) { 353001e04c3fSmrg bufObj->Written = GL_TRUE; 353101e04c3fSmrg bufObj->MinMaxCacheDirty = true; 3532cdc920a0Smrg } 3533cdc920a0Smrg 353401e04c3fSmrg#ifdef VBO_DEBUG 353501e04c3fSmrg if (strstr(func, "Range") == NULL) { /* If not MapRange */ 353601e04c3fSmrg printf("glMapBuffer(%u, sz %ld, access 0x%x)\n", 353701e04c3fSmrg bufObj->Name, bufObj->Size, access); 353801e04c3fSmrg /* Access must be write only */ 353901e04c3fSmrg if ((access & GL_MAP_WRITE_BIT) && (!(access & ~GL_MAP_WRITE_BIT))) { 354001e04c3fSmrg GLuint i; 35417ec681f3Smrg GLubyte *b = (GLubyte *) bufObj->Mappings[MAP_USER].Pointer; 354201e04c3fSmrg for (i = 0; i < bufObj->Size; i++) 354301e04c3fSmrg b[i] = i & 0xff; 354401e04c3fSmrg } 354501e04c3fSmrg } 354601e04c3fSmrg#endif 3547cdc920a0Smrg 354801e04c3fSmrg#ifdef BOUNDS_CHECK 354901e04c3fSmrg if (strstr(func, "Range") == NULL) { /* If not MapRange */ 35507ec681f3Smrg GLubyte *buf = (GLubyte *) bufObj->Mappings[MAP_USER].Pointer; 355101e04c3fSmrg GLuint i; 355201e04c3fSmrg /* buffer is 100 bytes larger than requested, fill with magic value */ 355301e04c3fSmrg for (i = 0; i < 100; i++) { 355401e04c3fSmrg buf[bufObj->Size - i - 1] = 123; 355501e04c3fSmrg } 355601e04c3fSmrg } 355701e04c3fSmrg#endif 3558cdc920a0Smrg 355901e04c3fSmrg return map; 3560cdc920a0Smrg} 3561cdc920a0Smrg 356201e04c3fSmrgvoid * GLAPIENTRY 356301e04c3fSmrg_mesa_MapBufferRange_no_error(GLenum target, GLintptr offset, 356401e04c3fSmrg GLsizeiptr length, GLbitfield access) 3565cdc920a0Smrg{ 356601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 3567cdc920a0Smrg 356801e04c3fSmrg struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target); 356901e04c3fSmrg struct gl_buffer_object *bufObj = *bufObjPtr; 3570cdc920a0Smrg 357101e04c3fSmrg return map_buffer_range(ctx, bufObj, offset, length, access, 357201e04c3fSmrg "glMapBufferRange"); 3573cdc920a0Smrg} 3574cdc920a0Smrg 357501e04c3fSmrgvoid * GLAPIENTRY 357601e04c3fSmrg_mesa_MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, 357701e04c3fSmrg GLbitfield access) 3578cdc920a0Smrg{ 357901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 358001e04c3fSmrg struct gl_buffer_object *bufObj; 3581cdc920a0Smrg 358201e04c3fSmrg if (!ctx->Extensions.ARB_map_buffer_range) { 3583cdc920a0Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 358401e04c3fSmrg "glMapBufferRange(ARB_map_buffer_range not supported)"); 358501e04c3fSmrg return NULL; 3586cdc920a0Smrg } 3587cdc920a0Smrg 358801e04c3fSmrg bufObj = get_buffer(ctx, "glMapBufferRange", target, GL_INVALID_OPERATION); 358901e04c3fSmrg if (!bufObj) 359001e04c3fSmrg return NULL; 3591cdc920a0Smrg 359201e04c3fSmrg if (!validate_map_buffer_range(ctx, bufObj, offset, length, access, 359301e04c3fSmrg "glMapBufferRange")) 359401e04c3fSmrg return NULL; 3595cdc920a0Smrg 359601e04c3fSmrg return map_buffer_range(ctx, bufObj, offset, length, access, 359701e04c3fSmrg "glMapBufferRange"); 3598cdc920a0Smrg} 3599cdc920a0Smrg 360001e04c3fSmrgvoid * GLAPIENTRY 360101e04c3fSmrg_mesa_MapNamedBufferRange_no_error(GLuint buffer, GLintptr offset, 360201e04c3fSmrg GLsizeiptr length, GLbitfield access) 3603cdc920a0Smrg{ 3604cdc920a0Smrg GET_CURRENT_CONTEXT(ctx); 360501e04c3fSmrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 3606cdc920a0Smrg 360701e04c3fSmrg return map_buffer_range(ctx, bufObj, offset, length, access, 360801e04c3fSmrg "glMapNamedBufferRange"); 3609cdc920a0Smrg} 3610cdc920a0Smrg 36117ec681f3Smrgstatic void * 36127ec681f3Smrgmap_named_buffer_range(GLuint buffer, GLintptr offset, GLsizeiptr length, 36137ec681f3Smrg GLbitfield access, bool dsa_ext, const char *func) 3614cdc920a0Smrg{ 361501e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 36167ec681f3Smrg struct gl_buffer_object *bufObj = NULL; 3617cdc920a0Smrg 361801e04c3fSmrg if (!ctx->Extensions.ARB_map_buffer_range) { 3619cdc920a0Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 36207ec681f3Smrg "%s(ARB_map_buffer_range not supported)", func); 362101e04c3fSmrg return NULL; 3622cdc920a0Smrg } 3623cdc920a0Smrg 36247ec681f3Smrg if (dsa_ext) { 36257ec681f3Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 36267ec681f3Smrg if (!_mesa_handle_bind_buffer_gen(ctx, buffer, &bufObj, func)) 36277ec681f3Smrg return NULL; 36287ec681f3Smrg } else { 36297ec681f3Smrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, func); 36307ec681f3Smrg if (!bufObj) 36317ec681f3Smrg return NULL; 36327ec681f3Smrg } 36337ec681f3Smrg 36347ec681f3Smrg if (!validate_map_buffer_range(ctx, bufObj, offset, length, access, func)) 363501e04c3fSmrg return NULL; 3636cdc920a0Smrg 36377ec681f3Smrg return map_buffer_range(ctx, bufObj, offset, length, access, func); 36387ec681f3Smrg} 36397ec681f3Smrg 36407ec681f3Smrgvoid * GLAPIENTRY 36417ec681f3Smrg_mesa_MapNamedBufferRangeEXT(GLuint buffer, GLintptr offset, GLsizeiptr length, 36427ec681f3Smrg GLbitfield access) 36437ec681f3Smrg{ 36447ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 36457ec681f3Smrg if (!buffer) { 36467ec681f3Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 36477ec681f3Smrg "glMapNamedBufferRangeEXT(buffer=0)"); 364801e04c3fSmrg return NULL; 36497ec681f3Smrg } 36507ec681f3Smrg return map_named_buffer_range(buffer, offset, length, access, true, 36517ec681f3Smrg "glMapNamedBufferRangeEXT"); 36527ec681f3Smrg} 3653cdc920a0Smrg 36547ec681f3Smrgvoid * GLAPIENTRY 36557ec681f3Smrg_mesa_MapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, 36567ec681f3Smrg GLbitfield access) 36577ec681f3Smrg{ 36587ec681f3Smrg return map_named_buffer_range(buffer, offset, length, access, false, 36597ec681f3Smrg "glMapNamedBufferRange"); 3660cdc920a0Smrg} 3661cdc920a0Smrg 366201e04c3fSmrg/** 366301e04c3fSmrg * Converts GLenum access from MapBuffer and MapNamedBuffer into 366401e04c3fSmrg * flags for input to map_buffer_range. 366501e04c3fSmrg * 366601e04c3fSmrg * \return true if the type of requested access is permissible. 366701e04c3fSmrg */ 366801e04c3fSmrgstatic bool 366901e04c3fSmrgget_map_buffer_access_flags(struct gl_context *ctx, GLenum access, 367001e04c3fSmrg GLbitfield *flags) 3671cdc920a0Smrg{ 367201e04c3fSmrg switch (access) { 367301e04c3fSmrg case GL_READ_ONLY_ARB: 367401e04c3fSmrg *flags = GL_MAP_READ_BIT; 367501e04c3fSmrg return _mesa_is_desktop_gl(ctx); 367601e04c3fSmrg case GL_WRITE_ONLY_ARB: 367701e04c3fSmrg *flags = GL_MAP_WRITE_BIT; 367801e04c3fSmrg return true; 367901e04c3fSmrg case GL_READ_WRITE_ARB: 368001e04c3fSmrg *flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT; 368101e04c3fSmrg return _mesa_is_desktop_gl(ctx); 368201e04c3fSmrg default: 368301e04c3fSmrg *flags = 0; 368401e04c3fSmrg return false; 3685cdc920a0Smrg } 368601e04c3fSmrg} 3687cdc920a0Smrg 368801e04c3fSmrgvoid * GLAPIENTRY 368901e04c3fSmrg_mesa_MapBuffer_no_error(GLenum target, GLenum access) 369001e04c3fSmrg{ 369101e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 3692cdc920a0Smrg 369301e04c3fSmrg GLbitfield accessFlags; 369401e04c3fSmrg get_map_buffer_access_flags(ctx, access, &accessFlags); 3695cdc920a0Smrg 369601e04c3fSmrg struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target); 369701e04c3fSmrg struct gl_buffer_object *bufObj = *bufObjPtr; 3698cdc920a0Smrg 369901e04c3fSmrg return map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags, 370001e04c3fSmrg "glMapBuffer"); 3701cdc920a0Smrg} 3702cdc920a0Smrg 370301e04c3fSmrgvoid * GLAPIENTRY 370401e04c3fSmrg_mesa_MapBuffer(GLenum target, GLenum access) 3705cdc920a0Smrg{ 370601e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 370701e04c3fSmrg struct gl_buffer_object *bufObj; 370801e04c3fSmrg GLbitfield accessFlags; 3709cdc920a0Smrg 371001e04c3fSmrg if (!get_map_buffer_access_flags(ctx, access, &accessFlags)) { 371101e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glMapBuffer(invalid access)"); 371201e04c3fSmrg return NULL; 3713cdc920a0Smrg } 3714cdc920a0Smrg 371501e04c3fSmrg bufObj = get_buffer(ctx, "glMapBuffer", target, GL_INVALID_OPERATION); 371601e04c3fSmrg if (!bufObj) 371701e04c3fSmrg return NULL; 3718cdc920a0Smrg 371901e04c3fSmrg if (!validate_map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags, 372001e04c3fSmrg "glMapBuffer")) 372101e04c3fSmrg return NULL; 3722cdc920a0Smrg 372301e04c3fSmrg return map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags, 372401e04c3fSmrg "glMapBuffer"); 3725cdc920a0Smrg} 3726cdc920a0Smrg 372701e04c3fSmrgvoid * GLAPIENTRY 372801e04c3fSmrg_mesa_MapNamedBuffer_no_error(GLuint buffer, GLenum access) 372901e04c3fSmrg{ 373001e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 373101e04c3fSmrg 373201e04c3fSmrg GLbitfield accessFlags; 373301e04c3fSmrg get_map_buffer_access_flags(ctx, access, &accessFlags); 373401e04c3fSmrg 373501e04c3fSmrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 373601e04c3fSmrg 373701e04c3fSmrg return map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags, 373801e04c3fSmrg "glMapNamedBuffer"); 373901e04c3fSmrg} 3740cdc920a0Smrg 374101e04c3fSmrgvoid * GLAPIENTRY 374201e04c3fSmrg_mesa_MapNamedBuffer(GLuint buffer, GLenum access) 3743cdc920a0Smrg{ 3744cdc920a0Smrg GET_CURRENT_CONTEXT(ctx); 374501e04c3fSmrg struct gl_buffer_object *bufObj; 374601e04c3fSmrg GLbitfield accessFlags; 3747cdc920a0Smrg 374801e04c3fSmrg if (!get_map_buffer_access_flags(ctx, access, &accessFlags)) { 374901e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glMapNamedBuffer(invalid access)"); 375001e04c3fSmrg return NULL; 3751cdc920a0Smrg } 3752cdc920a0Smrg 375301e04c3fSmrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glMapNamedBuffer"); 375401e04c3fSmrg if (!bufObj) 375501e04c3fSmrg return NULL; 375601e04c3fSmrg 375701e04c3fSmrg if (!validate_map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags, 375801e04c3fSmrg "glMapNamedBuffer")) 375901e04c3fSmrg return NULL; 376001e04c3fSmrg 376101e04c3fSmrg return map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags, 376201e04c3fSmrg "glMapNamedBuffer"); 3763cdc920a0Smrg} 3764cdc920a0Smrg 37657ec681f3Smrgvoid * GLAPIENTRY 37667ec681f3Smrg_mesa_MapNamedBufferEXT(GLuint buffer, GLenum access) 37677ec681f3Smrg{ 37687ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 37697ec681f3Smrg 37707ec681f3Smrg GLbitfield accessFlags; 37717ec681f3Smrg if (!buffer) { 37727ec681f3Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 37737ec681f3Smrg "glMapNamedBufferEXT(buffer=0)"); 37747ec681f3Smrg return NULL; 37757ec681f3Smrg } 37767ec681f3Smrg if (!get_map_buffer_access_flags(ctx, access, &accessFlags)) { 37777ec681f3Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glMapNamedBufferEXT(invalid access)"); 37787ec681f3Smrg return NULL; 37797ec681f3Smrg } 37807ec681f3Smrg 37817ec681f3Smrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 37827ec681f3Smrg if (!_mesa_handle_bind_buffer_gen(ctx, buffer, 37837ec681f3Smrg &bufObj, "glMapNamedBufferEXT")) 37847ec681f3Smrg return NULL; 37857ec681f3Smrg 37867ec681f3Smrg if (!validate_map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags, 37877ec681f3Smrg "glMapNamedBufferEXT")) 37887ec681f3Smrg return NULL; 37897ec681f3Smrg 37907ec681f3Smrg return map_buffer_range(ctx, bufObj, 0, bufObj->Size, accessFlags, 37917ec681f3Smrg "glMapNamedBufferEXT"); 37927ec681f3Smrg} 3793cdc920a0Smrg 3794cdc920a0Smrgstatic void 379501e04c3fSmrgflush_mapped_buffer_range(struct gl_context *ctx, 379601e04c3fSmrg struct gl_buffer_object *bufObj, 379701e04c3fSmrg GLintptr offset, GLsizeiptr length, 379801e04c3fSmrg const char *func) 3799cdc920a0Smrg{ 380001e04c3fSmrg if (!ctx->Extensions.ARB_map_buffer_range) { 380101e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 380201e04c3fSmrg "%s(ARB_map_buffer_range not supported)", func); 3803cdc920a0Smrg return; 3804cdc920a0Smrg } 3805cdc920a0Smrg 380601e04c3fSmrg if (offset < 0) { 380701e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 380801e04c3fSmrg "%s(offset %ld < 0)", func, (long) offset); 380901e04c3fSmrg return; 3810cdc920a0Smrg } 3811cdc920a0Smrg 381201e04c3fSmrg if (length < 0) { 3813cdc920a0Smrg _mesa_error(ctx, GL_INVALID_VALUE, 381401e04c3fSmrg "%s(length %ld < 0)", func, (long) length); 3815cdc920a0Smrg return; 3816cdc920a0Smrg } 3817cdc920a0Smrg 381801e04c3fSmrg if (!_mesa_bufferobj_mapped(bufObj, MAP_USER)) { 381901e04c3fSmrg /* buffer is not mapped */ 382001e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 382101e04c3fSmrg "%s(buffer is not mapped)", func); 382201e04c3fSmrg return; 3823cdc920a0Smrg } 3824cdc920a0Smrg 382501e04c3fSmrg if ((bufObj->Mappings[MAP_USER].AccessFlags & 382601e04c3fSmrg GL_MAP_FLUSH_EXPLICIT_BIT) == 0) { 382701e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 382801e04c3fSmrg "%s(GL_MAP_FLUSH_EXPLICIT_BIT not set)", func); 382901e04c3fSmrg return; 383001e04c3fSmrg } 3831cdc920a0Smrg 383201e04c3fSmrg if (offset + length > bufObj->Mappings[MAP_USER].Length) { 3833cdc920a0Smrg _mesa_error(ctx, GL_INVALID_VALUE, 383401e04c3fSmrg "%s(offset %ld + length %ld > mapped length %ld)", func, 383501e04c3fSmrg (long) offset, (long) length, 383601e04c3fSmrg (long) bufObj->Mappings[MAP_USER].Length); 3837cdc920a0Smrg return; 3838cdc920a0Smrg } 3839cdc920a0Smrg 384001e04c3fSmrg assert(bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_WRITE_BIT); 384101e04c3fSmrg 384201e04c3fSmrg if (ctx->Driver.FlushMappedBufferRange) 384301e04c3fSmrg ctx->Driver.FlushMappedBufferRange(ctx, offset, length, bufObj, 384401e04c3fSmrg MAP_USER); 3845cdc920a0Smrg} 3846cdc920a0Smrg 384701e04c3fSmrgvoid GLAPIENTRY 384801e04c3fSmrg_mesa_FlushMappedBufferRange_no_error(GLenum target, GLintptr offset, 384901e04c3fSmrg GLsizeiptr length) 385001e04c3fSmrg{ 385101e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 385201e04c3fSmrg struct gl_buffer_object **bufObjPtr = get_buffer_target(ctx, target); 385301e04c3fSmrg struct gl_buffer_object *bufObj = *bufObjPtr; 385401e04c3fSmrg 385501e04c3fSmrg if (ctx->Driver.FlushMappedBufferRange) 385601e04c3fSmrg ctx->Driver.FlushMappedBufferRange(ctx, offset, length, bufObj, 385701e04c3fSmrg MAP_USER); 385801e04c3fSmrg} 3859cdc920a0Smrg 3860cdc920a0Smrgvoid GLAPIENTRY 386101e04c3fSmrg_mesa_FlushMappedBufferRange(GLenum target, GLintptr offset, 386201e04c3fSmrg GLsizeiptr length) 3863cdc920a0Smrg{ 3864cdc920a0Smrg GET_CURRENT_CONTEXT(ctx); 386501e04c3fSmrg struct gl_buffer_object *bufObj; 3866cdc920a0Smrg 386701e04c3fSmrg bufObj = get_buffer(ctx, "glFlushMappedBufferRange", target, 386801e04c3fSmrg GL_INVALID_OPERATION); 386901e04c3fSmrg if (!bufObj) 3870cdc920a0Smrg return; 3871cdc920a0Smrg 387201e04c3fSmrg flush_mapped_buffer_range(ctx, bufObj, offset, length, 387301e04c3fSmrg "glFlushMappedBufferRange"); 3874cdc920a0Smrg} 3875cdc920a0Smrg 387601e04c3fSmrgvoid GLAPIENTRY 387701e04c3fSmrg_mesa_FlushMappedNamedBufferRange_no_error(GLuint buffer, GLintptr offset, 387801e04c3fSmrg GLsizeiptr length) 387901e04c3fSmrg{ 388001e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 388101e04c3fSmrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 388201e04c3fSmrg 388301e04c3fSmrg if (ctx->Driver.FlushMappedBufferRange) 388401e04c3fSmrg ctx->Driver.FlushMappedBufferRange(ctx, offset, length, bufObj, 388501e04c3fSmrg MAP_USER); 388601e04c3fSmrg} 388701e04c3fSmrg 388801e04c3fSmrgvoid GLAPIENTRY 388901e04c3fSmrg_mesa_FlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, 389001e04c3fSmrg GLsizeiptr length) 3891af69d88dSmrg{ 389201e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 389301e04c3fSmrg struct gl_buffer_object *bufObj; 3894af69d88dSmrg 389501e04c3fSmrg bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, 389601e04c3fSmrg "glFlushMappedNamedBufferRange"); 389701e04c3fSmrg if (!bufObj) 389801e04c3fSmrg return; 389901e04c3fSmrg 390001e04c3fSmrg flush_mapped_buffer_range(ctx, bufObj, offset, length, 390101e04c3fSmrg "glFlushMappedNamedBufferRange"); 3902af69d88dSmrg} 3903af69d88dSmrg 39047ec681f3Smrgvoid GLAPIENTRY 39057ec681f3Smrg_mesa_FlushMappedNamedBufferRangeEXT(GLuint buffer, GLintptr offset, 39067ec681f3Smrg GLsizeiptr length) 39077ec681f3Smrg{ 39087ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 39097ec681f3Smrg struct gl_buffer_object *bufObj; 39107ec681f3Smrg 39117ec681f3Smrg if (!buffer) { 39127ec681f3Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 39137ec681f3Smrg "glFlushMappedNamedBufferRangeEXT(buffer=0)"); 39147ec681f3Smrg return; 39157ec681f3Smrg } 39167ec681f3Smrg 39177ec681f3Smrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 39187ec681f3Smrg if (!_mesa_handle_bind_buffer_gen(ctx, buffer, 39197ec681f3Smrg &bufObj, "glFlushMappedNamedBufferRangeEXT")) 39207ec681f3Smrg return; 39217ec681f3Smrg 39227ec681f3Smrg flush_mapped_buffer_range(ctx, bufObj, offset, length, 39237ec681f3Smrg "glFlushMappedNamedBufferRangeEXT"); 39247ec681f3Smrg} 39257ec681f3Smrg 3926af69d88dSmrgstatic void 392701e04c3fSmrgbind_buffer_range_uniform_buffer(struct gl_context *ctx, GLuint index, 392801e04c3fSmrg struct gl_buffer_object *bufObj, 392901e04c3fSmrg GLintptr offset, GLsizeiptr size) 3930af69d88dSmrg{ 39317ec681f3Smrg if (!bufObj) { 393201e04c3fSmrg offset = -1; 393301e04c3fSmrg size = -1; 3934af69d88dSmrg } 3935af69d88dSmrg 393601e04c3fSmrg _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj); 393701e04c3fSmrg bind_uniform_buffer(ctx, index, bufObj, offset, size, GL_FALSE); 3938af69d88dSmrg} 3939af69d88dSmrg 3940af69d88dSmrg/** 3941af69d88dSmrg * Bind a region of a buffer object to a uniform block binding point. 3942af69d88dSmrg * \param index the uniform buffer binding point index 3943af69d88dSmrg * \param bufObj the buffer object 3944af69d88dSmrg * \param offset offset to the start of buffer object region 3945af69d88dSmrg * \param size size of the buffer object region 3946af69d88dSmrg */ 3947af69d88dSmrgstatic void 394801e04c3fSmrgbind_buffer_range_uniform_buffer_err(struct gl_context *ctx, GLuint index, 394901e04c3fSmrg struct gl_buffer_object *bufObj, 395001e04c3fSmrg GLintptr offset, GLsizeiptr size) 3951af69d88dSmrg{ 3952af69d88dSmrg if (index >= ctx->Const.MaxUniformBufferBindings) { 3953af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index); 3954af69d88dSmrg return; 3955af69d88dSmrg } 3956af69d88dSmrg 3957af69d88dSmrg if (offset & (ctx->Const.UniformBufferOffsetAlignment - 1)) { 3958af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 395901e04c3fSmrg "glBindBufferRange(offset misaligned %d/%d)", (int) offset, 3960af69d88dSmrg ctx->Const.UniformBufferOffsetAlignment); 3961af69d88dSmrg return; 3962af69d88dSmrg } 3963af69d88dSmrg 396401e04c3fSmrg bind_buffer_range_uniform_buffer(ctx, index, bufObj, offset, size); 396501e04c3fSmrg} 396601e04c3fSmrg 396701e04c3fSmrgstatic void 396801e04c3fSmrgbind_buffer_range_shader_storage_buffer(struct gl_context *ctx, 396901e04c3fSmrg GLuint index, 397001e04c3fSmrg struct gl_buffer_object *bufObj, 397101e04c3fSmrg GLintptr offset, 397201e04c3fSmrg GLsizeiptr size) 397301e04c3fSmrg{ 39747ec681f3Smrg if (!bufObj) { 3975af69d88dSmrg offset = -1; 3976af69d88dSmrg size = -1; 3977af69d88dSmrg } 3978af69d88dSmrg 397901e04c3fSmrg _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer, bufObj); 398001e04c3fSmrg bind_shader_storage_buffer(ctx, index, bufObj, offset, size, GL_FALSE); 3981af69d88dSmrg} 3982af69d88dSmrg 3983af69d88dSmrg/** 398401e04c3fSmrg * Bind a region of a buffer object to a shader storage block binding point. 398501e04c3fSmrg * \param index the shader storage buffer binding point index 398601e04c3fSmrg * \param bufObj the buffer object 398701e04c3fSmrg * \param offset offset to the start of buffer object region 398801e04c3fSmrg * \param size size of the buffer object region 3989af69d88dSmrg */ 3990af69d88dSmrgstatic void 399101e04c3fSmrgbind_buffer_range_shader_storage_buffer_err(struct gl_context *ctx, 399201e04c3fSmrg GLuint index, 399301e04c3fSmrg struct gl_buffer_object *bufObj, 399401e04c3fSmrg GLintptr offset, GLsizeiptr size) 3995af69d88dSmrg{ 399601e04c3fSmrg if (index >= ctx->Const.MaxShaderStorageBufferBindings) { 399701e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index); 3998af69d88dSmrg return; 3999af69d88dSmrg } 4000af69d88dSmrg 400101e04c3fSmrg if (offset & (ctx->Const.ShaderStorageBufferOffsetAlignment - 1)) { 400201e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 400301e04c3fSmrg "glBindBufferRange(offset misaligned %d/%d)", (int) offset, 400401e04c3fSmrg ctx->Const.ShaderStorageBufferOffsetAlignment); 400501e04c3fSmrg return; 400601e04c3fSmrg } 4007af69d88dSmrg 400801e04c3fSmrg bind_buffer_range_shader_storage_buffer(ctx, index, bufObj, offset, size); 4009af69d88dSmrg} 4010af69d88dSmrg 4011af69d88dSmrgstatic void 401201e04c3fSmrgbind_buffer_range_atomic_buffer(struct gl_context *ctx, GLuint index, 401301e04c3fSmrg struct gl_buffer_object *bufObj, 401401e04c3fSmrg GLintptr offset, GLsizeiptr size) 4015af69d88dSmrg{ 40167ec681f3Smrg if (!bufObj) { 401701e04c3fSmrg offset = -1; 401801e04c3fSmrg size = -1; 4019af69d88dSmrg } 402001e04c3fSmrg 402101e04c3fSmrg _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, bufObj); 402201e04c3fSmrg bind_atomic_buffer(ctx, index, bufObj, offset, size, GL_FALSE); 4023af69d88dSmrg} 4024af69d88dSmrg 4025af69d88dSmrg/** 402601e04c3fSmrg * Bind a region of a buffer object to an atomic storage block binding point. 402701e04c3fSmrg * \param index the shader storage buffer binding point index 402801e04c3fSmrg * \param bufObj the buffer object 402901e04c3fSmrg * \param offset offset to the start of buffer object region 403001e04c3fSmrg * \param size size of the buffer object region 4031af69d88dSmrg */ 4032af69d88dSmrgstatic void 403301e04c3fSmrgbind_buffer_range_atomic_buffer_err(struct gl_context *ctx, 403401e04c3fSmrg GLuint index, 403501e04c3fSmrg struct gl_buffer_object *bufObj, 403601e04c3fSmrg GLintptr offset, GLsizeiptr size) 4037af69d88dSmrg{ 4038af69d88dSmrg if (index >= ctx->Const.MaxAtomicBufferBindings) { 403901e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index); 4040af69d88dSmrg return; 4041af69d88dSmrg } 4042af69d88dSmrg 4043af69d88dSmrg if (offset & (ATOMIC_COUNTER_SIZE - 1)) { 4044af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 404501e04c3fSmrg "glBindBufferRange(offset misaligned %d/%d)", (int) offset, 404601e04c3fSmrg ATOMIC_COUNTER_SIZE); 4047af69d88dSmrg return; 4048af69d88dSmrg } 4049af69d88dSmrg 405001e04c3fSmrg bind_buffer_range_atomic_buffer(ctx, index, bufObj, offset, size); 4051af69d88dSmrg} 4052af69d88dSmrg 4053af69d88dSmrgstatic inline bool 4054af69d88dSmrgbind_buffers_check_offset_and_size(struct gl_context *ctx, 4055af69d88dSmrg GLuint index, 4056af69d88dSmrg const GLintptr *offsets, 4057af69d88dSmrg const GLsizeiptr *sizes) 4058af69d88dSmrg{ 4059af69d88dSmrg if (offsets[index] < 0) { 406001e04c3fSmrg /* The ARB_multi_bind spec says: 406101e04c3fSmrg * 406201e04c3fSmrg * "An INVALID_VALUE error is generated by BindBuffersRange if any 406301e04c3fSmrg * value in <offsets> is less than zero (per binding)." 406401e04c3fSmrg */ 4065af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 4066af69d88dSmrg "glBindBuffersRange(offsets[%u]=%" PRId64 " < 0)", 4067af69d88dSmrg index, (int64_t) offsets[index]); 4068af69d88dSmrg return false; 4069af69d88dSmrg } 4070af69d88dSmrg 4071af69d88dSmrg if (sizes[index] <= 0) { 407201e04c3fSmrg /* The ARB_multi_bind spec says: 407301e04c3fSmrg * 407401e04c3fSmrg * "An INVALID_VALUE error is generated by BindBuffersRange if any 407501e04c3fSmrg * value in <sizes> is less than or equal to zero (per binding)." 407601e04c3fSmrg */ 4077af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 4078af69d88dSmrg "glBindBuffersRange(sizes[%u]=%" PRId64 " <= 0)", 4079af69d88dSmrg index, (int64_t) sizes[index]); 4080af69d88dSmrg return false; 4081af69d88dSmrg } 4082af69d88dSmrg 4083af69d88dSmrg return true; 4084af69d88dSmrg} 4085af69d88dSmrg 4086af69d88dSmrgstatic bool 4087af69d88dSmrgerror_check_bind_uniform_buffers(struct gl_context *ctx, 4088af69d88dSmrg GLuint first, GLsizei count, 4089af69d88dSmrg const char *caller) 4090af69d88dSmrg{ 4091af69d88dSmrg if (!ctx->Extensions.ARB_uniform_buffer_object) { 4092af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, 4093af69d88dSmrg "%s(target=GL_UNIFORM_BUFFER)", caller); 4094af69d88dSmrg return false; 4095af69d88dSmrg } 4096af69d88dSmrg 4097af69d88dSmrg /* The ARB_multi_bind_spec says: 4098af69d88dSmrg * 4099af69d88dSmrg * "An INVALID_OPERATION error is generated if <first> + <count> is 4100af69d88dSmrg * greater than the number of target-specific indexed binding points, 4101af69d88dSmrg * as described in section 6.7.1." 4102af69d88dSmrg */ 4103af69d88dSmrg if (first + count > ctx->Const.MaxUniformBufferBindings) { 4104af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 4105af69d88dSmrg "%s(first=%u + count=%d > the value of " 4106af69d88dSmrg "GL_MAX_UNIFORM_BUFFER_BINDINGS=%u)", 4107af69d88dSmrg caller, first, count, 4108af69d88dSmrg ctx->Const.MaxUniformBufferBindings); 4109af69d88dSmrg return false; 4110af69d88dSmrg } 4111af69d88dSmrg 4112af69d88dSmrg return true; 4113af69d88dSmrg} 4114af69d88dSmrg 411501e04c3fSmrgstatic bool 411601e04c3fSmrgerror_check_bind_shader_storage_buffers(struct gl_context *ctx, 411701e04c3fSmrg GLuint first, GLsizei count, 411801e04c3fSmrg const char *caller) 411901e04c3fSmrg{ 412001e04c3fSmrg if (!ctx->Extensions.ARB_shader_storage_buffer_object) { 412101e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, 412201e04c3fSmrg "%s(target=GL_SHADER_STORAGE_BUFFER)", caller); 412301e04c3fSmrg return false; 412401e04c3fSmrg } 412501e04c3fSmrg 412601e04c3fSmrg /* The ARB_multi_bind_spec says: 412701e04c3fSmrg * 412801e04c3fSmrg * "An INVALID_OPERATION error is generated if <first> + <count> is 412901e04c3fSmrg * greater than the number of target-specific indexed binding points, 413001e04c3fSmrg * as described in section 6.7.1." 413101e04c3fSmrg */ 413201e04c3fSmrg if (first + count > ctx->Const.MaxShaderStorageBufferBindings) { 413301e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 413401e04c3fSmrg "%s(first=%u + count=%d > the value of " 413501e04c3fSmrg "GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS=%u)", 413601e04c3fSmrg caller, first, count, 413701e04c3fSmrg ctx->Const.MaxShaderStorageBufferBindings); 413801e04c3fSmrg return false; 413901e04c3fSmrg } 414001e04c3fSmrg 414101e04c3fSmrg return true; 414201e04c3fSmrg} 414301e04c3fSmrg 4144af69d88dSmrg/** 4145af69d88dSmrg * Unbind all uniform buffers in the range 4146af69d88dSmrg * <first> through <first>+<count>-1 4147af69d88dSmrg */ 4148af69d88dSmrgstatic void 4149af69d88dSmrgunbind_uniform_buffers(struct gl_context *ctx, GLuint first, GLsizei count) 4150af69d88dSmrg{ 415101e04c3fSmrg for (int i = 0; i < count; i++) 415201e04c3fSmrg set_buffer_binding(ctx, &ctx->UniformBufferBindings[first + i], 41537ec681f3Smrg NULL, -1, -1, GL_TRUE, 0); 4154af69d88dSmrg} 4155af69d88dSmrg 415601e04c3fSmrg/** 415701e04c3fSmrg * Unbind all shader storage buffers in the range 415801e04c3fSmrg * <first> through <first>+<count>-1 415901e04c3fSmrg */ 4160af69d88dSmrgstatic void 416101e04c3fSmrgunbind_shader_storage_buffers(struct gl_context *ctx, GLuint first, 416201e04c3fSmrg GLsizei count) 4163af69d88dSmrg{ 416401e04c3fSmrg for (int i = 0; i < count; i++) 416501e04c3fSmrg set_buffer_binding(ctx, &ctx->ShaderStorageBufferBindings[first + i], 41667ec681f3Smrg NULL, -1, -1, GL_TRUE, 0); 416701e04c3fSmrg} 4168af69d88dSmrg 416901e04c3fSmrgstatic void 417001e04c3fSmrgbind_uniform_buffers(struct gl_context *ctx, GLuint first, GLsizei count, 417101e04c3fSmrg const GLuint *buffers, 417201e04c3fSmrg bool range, 417301e04c3fSmrg const GLintptr *offsets, const GLsizeiptr *sizes, 417401e04c3fSmrg const char *caller) 417501e04c3fSmrg{ 417601e04c3fSmrg if (!error_check_bind_uniform_buffers(ctx, first, count, caller)) 4177af69d88dSmrg return; 4178af69d88dSmrg 4179af69d88dSmrg /* Assume that at least one binding will be changed */ 41807ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 4181af69d88dSmrg ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer; 4182af69d88dSmrg 4183af69d88dSmrg if (!buffers) { 4184af69d88dSmrg /* The ARB_multi_bind spec says: 4185af69d88dSmrg * 418601e04c3fSmrg * "If <buffers> is NULL, all bindings from <first> through 418701e04c3fSmrg * <first>+<count>-1 are reset to their unbound (zero) state. 418801e04c3fSmrg * In this case, the offsets and sizes associated with the 418901e04c3fSmrg * binding points are set to default values, ignoring 419001e04c3fSmrg * <offsets> and <sizes>." 4191af69d88dSmrg */ 4192af69d88dSmrg unbind_uniform_buffers(ctx, first, count); 4193af69d88dSmrg return; 4194af69d88dSmrg } 4195af69d88dSmrg 4196af69d88dSmrg /* Note that the error semantics for multi-bind commands differ from 4197af69d88dSmrg * those of other GL commands. 4198af69d88dSmrg * 4199af69d88dSmrg * The Issues section in the ARB_multi_bind spec says: 4200af69d88dSmrg * 4201af69d88dSmrg * "(11) Typically, OpenGL specifies that if an error is generated by a 4202af69d88dSmrg * command, that command has no effect. This is somewhat 4203af69d88dSmrg * unfortunate for multi-bind commands, because it would require a 4204af69d88dSmrg * first pass to scan the entire list of bound objects for errors 4205af69d88dSmrg * and then a second pass to actually perform the bindings. 4206af69d88dSmrg * Should we have different error semantics? 4207af69d88dSmrg * 4208af69d88dSmrg * RESOLVED: Yes. In this specification, when the parameters for 4209af69d88dSmrg * one of the <count> binding points are invalid, that binding point 4210af69d88dSmrg * is not updated and an error will be generated. However, other 4211af69d88dSmrg * binding points in the same command will be updated if their 4212af69d88dSmrg * parameters are valid and no other error occurs." 4213af69d88dSmrg */ 4214af69d88dSmrg 42157ec681f3Smrg _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects, 42167ec681f3Smrg ctx->BufferObjectsLocked); 4217af69d88dSmrg 421801e04c3fSmrg for (int i = 0; i < count; i++) { 421901e04c3fSmrg struct gl_buffer_binding *binding = 422001e04c3fSmrg &ctx->UniformBufferBindings[first + i]; 422101e04c3fSmrg GLintptr offset = 0; 422201e04c3fSmrg GLsizeiptr size = 0; 4223af69d88dSmrg 422401e04c3fSmrg if (range) { 422501e04c3fSmrg if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes)) 422601e04c3fSmrg continue; 4227af69d88dSmrg 422801e04c3fSmrg /* The ARB_multi_bind spec says: 422901e04c3fSmrg * 423001e04c3fSmrg * "An INVALID_VALUE error is generated by BindBuffersRange if any 423101e04c3fSmrg * pair of values in <offsets> and <sizes> does not respectively 423201e04c3fSmrg * satisfy the constraints described for those parameters for the 423301e04c3fSmrg * specified target, as described in section 6.7.1 (per binding)." 423401e04c3fSmrg * 423501e04c3fSmrg * Section 6.7.1 refers to table 6.5, which says: 423601e04c3fSmrg * 423701e04c3fSmrg * "┌───────────────────────────────────────────────────────────────┐ 423801e04c3fSmrg * │ Uniform buffer array bindings (see sec. 7.6) │ 423901e04c3fSmrg * ├─────────────────────┬─────────────────────────────────────────┤ 424001e04c3fSmrg * │ ... │ ... │ 424101e04c3fSmrg * │ offset restriction │ multiple of value of UNIFORM_BUFFER_- │ 424201e04c3fSmrg * │ │ OFFSET_ALIGNMENT │ 424301e04c3fSmrg * │ ... │ ... │ 424401e04c3fSmrg * │ size restriction │ none │ 424501e04c3fSmrg * └─────────────────────┴─────────────────────────────────────────┘" 424601e04c3fSmrg */ 424701e04c3fSmrg if (offsets[i] & (ctx->Const.UniformBufferOffsetAlignment - 1)) { 424801e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 424901e04c3fSmrg "glBindBuffersRange(offsets[%u]=%" PRId64 425001e04c3fSmrg " is misaligned; it must be a multiple of the value of " 425101e04c3fSmrg "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT=%u when " 425201e04c3fSmrg "target=GL_UNIFORM_BUFFER)", 425301e04c3fSmrg i, (int64_t) offsets[i], 425401e04c3fSmrg ctx->Const.UniformBufferOffsetAlignment); 425501e04c3fSmrg continue; 425601e04c3fSmrg } 425701e04c3fSmrg 425801e04c3fSmrg offset = offsets[i]; 425901e04c3fSmrg size = sizes[i]; 4260af69d88dSmrg } 426101e04c3fSmrg 426201e04c3fSmrg set_buffer_multi_binding(ctx, buffers, i, caller, 426301e04c3fSmrg binding, offset, size, range, 426401e04c3fSmrg USAGE_UNIFORM_BUFFER); 4265af69d88dSmrg } 4266af69d88dSmrg 42677ec681f3Smrg _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects, 42687ec681f3Smrg ctx->BufferObjectsLocked); 4269af69d88dSmrg} 4270af69d88dSmrg 4271af69d88dSmrgstatic void 427201e04c3fSmrgbind_shader_storage_buffers(struct gl_context *ctx, GLuint first, 427301e04c3fSmrg GLsizei count, const GLuint *buffers, 427401e04c3fSmrg bool range, 427501e04c3fSmrg const GLintptr *offsets, 427601e04c3fSmrg const GLsizeiptr *sizes, 427701e04c3fSmrg const char *caller) 4278af69d88dSmrg{ 427901e04c3fSmrg if (!error_check_bind_shader_storage_buffers(ctx, first, count, caller)) 4280af69d88dSmrg return; 4281af69d88dSmrg 4282af69d88dSmrg /* Assume that at least one binding will be changed */ 42837ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 428401e04c3fSmrg ctx->NewDriverState |= ctx->DriverFlags.NewShaderStorageBuffer; 4285af69d88dSmrg 4286af69d88dSmrg if (!buffers) { 4287af69d88dSmrg /* The ARB_multi_bind spec says: 4288af69d88dSmrg * 4289af69d88dSmrg * "If <buffers> is NULL, all bindings from <first> through 4290af69d88dSmrg * <first>+<count>-1 are reset to their unbound (zero) state. 4291af69d88dSmrg * In this case, the offsets and sizes associated with the 4292af69d88dSmrg * binding points are set to default values, ignoring 4293af69d88dSmrg * <offsets> and <sizes>." 4294af69d88dSmrg */ 429501e04c3fSmrg unbind_shader_storage_buffers(ctx, first, count); 4296af69d88dSmrg return; 4297af69d88dSmrg } 4298af69d88dSmrg 4299af69d88dSmrg /* Note that the error semantics for multi-bind commands differ from 4300af69d88dSmrg * those of other GL commands. 4301af69d88dSmrg * 4302af69d88dSmrg * The Issues section in the ARB_multi_bind spec says: 4303af69d88dSmrg * 4304af69d88dSmrg * "(11) Typically, OpenGL specifies that if an error is generated by a 4305af69d88dSmrg * command, that command has no effect. This is somewhat 4306af69d88dSmrg * unfortunate for multi-bind commands, because it would require a 4307af69d88dSmrg * first pass to scan the entire list of bound objects for errors 4308af69d88dSmrg * and then a second pass to actually perform the bindings. 4309af69d88dSmrg * Should we have different error semantics? 4310af69d88dSmrg * 4311af69d88dSmrg * RESOLVED: Yes. In this specification, when the parameters for 4312af69d88dSmrg * one of the <count> binding points are invalid, that binding point 4313af69d88dSmrg * is not updated and an error will be generated. However, other 4314af69d88dSmrg * binding points in the same command will be updated if their 4315af69d88dSmrg * parameters are valid and no other error occurs." 4316af69d88dSmrg */ 4317af69d88dSmrg 43187ec681f3Smrg _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects, 43197ec681f3Smrg ctx->BufferObjectsLocked); 4320af69d88dSmrg 432101e04c3fSmrg for (int i = 0; i < count; i++) { 432201e04c3fSmrg struct gl_buffer_binding *binding = 432301e04c3fSmrg &ctx->ShaderStorageBufferBindings[first + i]; 432401e04c3fSmrg GLintptr offset = 0; 432501e04c3fSmrg GLsizeiptr size = 0; 432601e04c3fSmrg 432701e04c3fSmrg if (range) { 432801e04c3fSmrg if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes)) 432901e04c3fSmrg continue; 433001e04c3fSmrg 433101e04c3fSmrg /* The ARB_multi_bind spec says: 433201e04c3fSmrg * 433301e04c3fSmrg * "An INVALID_VALUE error is generated by BindBuffersRange if any 433401e04c3fSmrg * pair of values in <offsets> and <sizes> does not respectively 433501e04c3fSmrg * satisfy the constraints described for those parameters for the 433601e04c3fSmrg * specified target, as described in section 6.7.1 (per binding)." 433701e04c3fSmrg * 433801e04c3fSmrg * Section 6.7.1 refers to table 6.5, which says: 433901e04c3fSmrg * 434001e04c3fSmrg * "┌───────────────────────────────────────────────────────────────┐ 434101e04c3fSmrg * │ Shader storage buffer array bindings (see sec. 7.8) │ 434201e04c3fSmrg * ├─────────────────────┬─────────────────────────────────────────┤ 434301e04c3fSmrg * │ ... │ ... │ 434401e04c3fSmrg * │ offset restriction │ multiple of value of SHADER_STORAGE_- │ 434501e04c3fSmrg * │ │ BUFFER_OFFSET_ALIGNMENT │ 434601e04c3fSmrg * │ ... │ ... │ 434701e04c3fSmrg * │ size restriction │ none │ 434801e04c3fSmrg * └─────────────────────┴─────────────────────────────────────────┘" 434901e04c3fSmrg */ 435001e04c3fSmrg if (offsets[i] & (ctx->Const.ShaderStorageBufferOffsetAlignment - 1)) { 435101e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 435201e04c3fSmrg "glBindBuffersRange(offsets[%u]=%" PRId64 435301e04c3fSmrg " is misaligned; it must be a multiple of the value of " 435401e04c3fSmrg "GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT=%u when " 435501e04c3fSmrg "target=GL_SHADER_STORAGE_BUFFER)", 435601e04c3fSmrg i, (int64_t) offsets[i], 435701e04c3fSmrg ctx->Const.ShaderStorageBufferOffsetAlignment); 435801e04c3fSmrg continue; 435901e04c3fSmrg } 4360af69d88dSmrg 436101e04c3fSmrg offset = offsets[i]; 436201e04c3fSmrg size = sizes[i]; 4363af69d88dSmrg } 4364af69d88dSmrg 436501e04c3fSmrg set_buffer_multi_binding(ctx, buffers, i, caller, 436601e04c3fSmrg binding, offset, size, range, 436701e04c3fSmrg USAGE_SHADER_STORAGE_BUFFER); 4368af69d88dSmrg } 4369af69d88dSmrg 43707ec681f3Smrg _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects, 43717ec681f3Smrg ctx->BufferObjectsLocked); 4372af69d88dSmrg} 4373af69d88dSmrg 4374af69d88dSmrgstatic bool 4375af69d88dSmrgerror_check_bind_xfb_buffers(struct gl_context *ctx, 4376af69d88dSmrg struct gl_transform_feedback_object *tfObj, 4377af69d88dSmrg GLuint first, GLsizei count, const char *caller) 4378af69d88dSmrg{ 4379af69d88dSmrg if (!ctx->Extensions.EXT_transform_feedback) { 4380af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, 4381af69d88dSmrg "%s(target=GL_TRANSFORM_FEEDBACK_BUFFER)", caller); 4382af69d88dSmrg return false; 4383af69d88dSmrg } 4384af69d88dSmrg 4385af69d88dSmrg /* Page 398 of the PDF of the OpenGL 4.4 (Core Profile) spec says: 4386af69d88dSmrg * 4387af69d88dSmrg * "An INVALID_OPERATION error is generated : 4388af69d88dSmrg * 4389af69d88dSmrg * ... 4390af69d88dSmrg * • by BindBufferRange or BindBufferBase if target is TRANSFORM_- 439101e04c3fSmrg * FEEDBACK_BUFFER and transform feedback is currently active." 439201e04c3fSmrg * 439301e04c3fSmrg * We assume that this is also meant to apply to BindBuffersRange 439401e04c3fSmrg * and BindBuffersBase. 4395af69d88dSmrg */ 439601e04c3fSmrg if (tfObj->Active) { 439701e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 439801e04c3fSmrg "%s(Changing transform feedback buffers while " 439901e04c3fSmrg "transform feedback is active)", caller); 440001e04c3fSmrg return false; 440101e04c3fSmrg } 4402af69d88dSmrg 440301e04c3fSmrg /* The ARB_multi_bind_spec says: 440401e04c3fSmrg * 440501e04c3fSmrg * "An INVALID_OPERATION error is generated if <first> + <count> is 440601e04c3fSmrg * greater than the number of target-specific indexed binding points, 440701e04c3fSmrg * as described in section 6.7.1." 440801e04c3fSmrg */ 440901e04c3fSmrg if (first + count > ctx->Const.MaxTransformFeedbackBuffers) { 441001e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 441101e04c3fSmrg "%s(first=%u + count=%d > the value of " 441201e04c3fSmrg "GL_MAX_TRANSFORM_FEEDBACK_BUFFERS=%u)", 441301e04c3fSmrg caller, first, count, 441401e04c3fSmrg ctx->Const.MaxTransformFeedbackBuffers); 441501e04c3fSmrg return false; 441601e04c3fSmrg } 4417af69d88dSmrg 441801e04c3fSmrg return true; 441901e04c3fSmrg} 4420af69d88dSmrg 442101e04c3fSmrg/** 442201e04c3fSmrg * Unbind all transform feedback buffers in the range 442301e04c3fSmrg * <first> through <first>+<count>-1 442401e04c3fSmrg */ 442501e04c3fSmrgstatic void 442601e04c3fSmrgunbind_xfb_buffers(struct gl_context *ctx, 442701e04c3fSmrg struct gl_transform_feedback_object *tfObj, 442801e04c3fSmrg GLuint first, GLsizei count) 442901e04c3fSmrg{ 443001e04c3fSmrg for (int i = 0; i < count; i++) 443101e04c3fSmrg _mesa_set_transform_feedback_binding(ctx, tfObj, first + i, 44327ec681f3Smrg NULL, 0, 0); 4433af69d88dSmrg} 4434af69d88dSmrg 4435af69d88dSmrgstatic void 443601e04c3fSmrgbind_xfb_buffers(struct gl_context *ctx, 443701e04c3fSmrg GLuint first, GLsizei count, 443801e04c3fSmrg const GLuint *buffers, 443901e04c3fSmrg bool range, 444001e04c3fSmrg const GLintptr *offsets, 444101e04c3fSmrg const GLsizeiptr *sizes, 444201e04c3fSmrg const char *caller) 4443af69d88dSmrg{ 4444af69d88dSmrg struct gl_transform_feedback_object *tfObj = 4445af69d88dSmrg ctx->TransformFeedback.CurrentObject; 4446af69d88dSmrg 444701e04c3fSmrg if (!error_check_bind_xfb_buffers(ctx, tfObj, first, count, caller)) 4448af69d88dSmrg return; 4449af69d88dSmrg 4450af69d88dSmrg /* Assume that at least one binding will be changed */ 44517ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 4452af69d88dSmrg ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback; 4453af69d88dSmrg 4454af69d88dSmrg if (!buffers) { 4455af69d88dSmrg /* The ARB_multi_bind spec says: 4456af69d88dSmrg * 4457af69d88dSmrg * "If <buffers> is NULL, all bindings from <first> through 4458af69d88dSmrg * <first>+<count>-1 are reset to their unbound (zero) state. 4459af69d88dSmrg * In this case, the offsets and sizes associated with the 4460af69d88dSmrg * binding points are set to default values, ignoring 4461af69d88dSmrg * <offsets> and <sizes>." 4462af69d88dSmrg */ 4463af69d88dSmrg unbind_xfb_buffers(ctx, tfObj, first, count); 4464af69d88dSmrg return; 4465af69d88dSmrg } 4466af69d88dSmrg 4467af69d88dSmrg /* Note that the error semantics for multi-bind commands differ from 4468af69d88dSmrg * those of other GL commands. 4469af69d88dSmrg * 4470af69d88dSmrg * The Issues section in the ARB_multi_bind spec says: 4471af69d88dSmrg * 4472af69d88dSmrg * "(11) Typically, OpenGL specifies that if an error is generated by a 4473af69d88dSmrg * command, that command has no effect. This is somewhat 4474af69d88dSmrg * unfortunate for multi-bind commands, because it would require a 4475af69d88dSmrg * first pass to scan the entire list of bound objects for errors 4476af69d88dSmrg * and then a second pass to actually perform the bindings. 4477af69d88dSmrg * Should we have different error semantics? 4478af69d88dSmrg * 4479af69d88dSmrg * RESOLVED: Yes. In this specification, when the parameters for 4480af69d88dSmrg * one of the <count> binding points are invalid, that binding point 4481af69d88dSmrg * is not updated and an error will be generated. However, other 4482af69d88dSmrg * binding points in the same command will be updated if their 4483af69d88dSmrg * parameters are valid and no other error occurs." 4484af69d88dSmrg */ 4485af69d88dSmrg 44867ec681f3Smrg _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects, 44877ec681f3Smrg ctx->BufferObjectsLocked); 4488af69d88dSmrg 448901e04c3fSmrg for (int i = 0; i < count; i++) { 4490af69d88dSmrg const GLuint index = first + i; 4491af69d88dSmrg struct gl_buffer_object * const boundBufObj = tfObj->Buffers[index]; 4492af69d88dSmrg struct gl_buffer_object *bufObj; 449301e04c3fSmrg GLintptr offset = 0; 449401e04c3fSmrg GLsizeiptr size = 0; 4495af69d88dSmrg 449601e04c3fSmrg if (range) { 449701e04c3fSmrg if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes)) 449801e04c3fSmrg continue; 4499af69d88dSmrg 450001e04c3fSmrg /* The ARB_multi_bind spec says: 450101e04c3fSmrg * 450201e04c3fSmrg * "An INVALID_VALUE error is generated by BindBuffersRange if any 450301e04c3fSmrg * pair of values in <offsets> and <sizes> does not respectively 450401e04c3fSmrg * satisfy the constraints described for those parameters for the 450501e04c3fSmrg * specified target, as described in section 6.7.1 (per binding)." 450601e04c3fSmrg * 450701e04c3fSmrg * Section 6.7.1 refers to table 6.5, which says: 450801e04c3fSmrg * 450901e04c3fSmrg * "┌───────────────────────────────────────────────────────────────┐ 451001e04c3fSmrg * │ Transform feedback array bindings (see sec. 13.2.2) │ 451101e04c3fSmrg * ├───────────────────────┬───────────────────────────────────────┤ 451201e04c3fSmrg * │ ... │ ... │ 451301e04c3fSmrg * │ offset restriction │ multiple of 4 │ 451401e04c3fSmrg * │ ... │ ... │ 451501e04c3fSmrg * │ size restriction │ multiple of 4 │ 451601e04c3fSmrg * └───────────────────────┴───────────────────────────────────────┘" 451701e04c3fSmrg */ 451801e04c3fSmrg if (offsets[i] & 0x3) { 451901e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 452001e04c3fSmrg "glBindBuffersRange(offsets[%u]=%" PRId64 452101e04c3fSmrg " is misaligned; it must be a multiple of 4 when " 452201e04c3fSmrg "target=GL_TRANSFORM_FEEDBACK_BUFFER)", 452301e04c3fSmrg i, (int64_t) offsets[i]); 452401e04c3fSmrg continue; 452501e04c3fSmrg } 4526af69d88dSmrg 452701e04c3fSmrg if (sizes[i] & 0x3) { 452801e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 452901e04c3fSmrg "glBindBuffersRange(sizes[%u]=%" PRId64 453001e04c3fSmrg " is misaligned; it must be a multiple of 4 when " 453101e04c3fSmrg "target=GL_TRANSFORM_FEEDBACK_BUFFER)", 453201e04c3fSmrg i, (int64_t) sizes[i]); 453301e04c3fSmrg continue; 453401e04c3fSmrg } 453501e04c3fSmrg 453601e04c3fSmrg offset = offsets[i]; 453701e04c3fSmrg size = sizes[i]; 4538af69d88dSmrg } 4539af69d88dSmrg 4540af69d88dSmrg if (boundBufObj && boundBufObj->Name == buffers[i]) 4541af69d88dSmrg bufObj = boundBufObj; 45427ec681f3Smrg else { 45437ec681f3Smrg bool error; 45447ec681f3Smrg bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, caller, 45457ec681f3Smrg &error); 45467ec681f3Smrg if (error) 45477ec681f3Smrg continue; 45487ec681f3Smrg } 4549af69d88dSmrg 45507ec681f3Smrg _mesa_set_transform_feedback_binding(ctx, tfObj, index, bufObj, 45517ec681f3Smrg offset, size); 4552af69d88dSmrg } 4553af69d88dSmrg 45547ec681f3Smrg _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects, 45557ec681f3Smrg ctx->BufferObjectsLocked); 4556af69d88dSmrg} 4557af69d88dSmrg 4558af69d88dSmrgstatic bool 4559af69d88dSmrgerror_check_bind_atomic_buffers(struct gl_context *ctx, 4560af69d88dSmrg GLuint first, GLsizei count, 4561af69d88dSmrg const char *caller) 4562af69d88dSmrg{ 4563af69d88dSmrg if (!ctx->Extensions.ARB_shader_atomic_counters) { 4564af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, 4565af69d88dSmrg "%s(target=GL_ATOMIC_COUNTER_BUFFER)", caller); 4566af69d88dSmrg return false; 4567af69d88dSmrg } 4568af69d88dSmrg 4569af69d88dSmrg /* The ARB_multi_bind_spec says: 4570af69d88dSmrg * 4571af69d88dSmrg * "An INVALID_OPERATION error is generated if <first> + <count> is 4572af69d88dSmrg * greater than the number of target-specific indexed binding points, 4573af69d88dSmrg * as described in section 6.7.1." 4574af69d88dSmrg */ 4575af69d88dSmrg if (first + count > ctx->Const.MaxAtomicBufferBindings) { 4576af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 4577af69d88dSmrg "%s(first=%u + count=%d > the value of " 4578af69d88dSmrg "GL_MAX_ATOMIC_BUFFER_BINDINGS=%u)", 4579af69d88dSmrg caller, first, count, ctx->Const.MaxAtomicBufferBindings); 4580af69d88dSmrg return false; 4581af69d88dSmrg } 4582af69d88dSmrg 4583af69d88dSmrg return true; 4584af69d88dSmrg} 4585af69d88dSmrg 4586af69d88dSmrg/** 4587af69d88dSmrg * Unbind all atomic counter buffers in the range 4588af69d88dSmrg * <first> through <first>+<count>-1 4589af69d88dSmrg */ 4590af69d88dSmrgstatic void 4591af69d88dSmrgunbind_atomic_buffers(struct gl_context *ctx, GLuint first, GLsizei count) 4592af69d88dSmrg{ 459301e04c3fSmrg for (int i = 0; i < count; i++) 459401e04c3fSmrg set_buffer_binding(ctx, &ctx->AtomicBufferBindings[first + i], 45957ec681f3Smrg NULL, -1, -1, GL_TRUE, 0); 4596af69d88dSmrg} 4597af69d88dSmrg 4598af69d88dSmrgstatic void 459901e04c3fSmrgbind_atomic_buffers(struct gl_context *ctx, 460001e04c3fSmrg GLuint first, 460101e04c3fSmrg GLsizei count, 460201e04c3fSmrg const GLuint *buffers, 460301e04c3fSmrg bool range, 460401e04c3fSmrg const GLintptr *offsets, 460501e04c3fSmrg const GLsizeiptr *sizes, 460601e04c3fSmrg const char *caller) 4607af69d88dSmrg{ 460801e04c3fSmrg if (!error_check_bind_atomic_buffers(ctx, first, count, caller)) 4609af69d88dSmrg return; 4610af69d88dSmrg 4611af69d88dSmrg /* Assume that at least one binding will be changed */ 46127ec681f3Smrg FLUSH_VERTICES(ctx, 0, 0); 4613af69d88dSmrg ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer; 4614af69d88dSmrg 4615af69d88dSmrg if (!buffers) { 4616af69d88dSmrg /* The ARB_multi_bind spec says: 4617af69d88dSmrg * 4618af69d88dSmrg * "If <buffers> is NULL, all bindings from <first> through 4619af69d88dSmrg * <first>+<count>-1 are reset to their unbound (zero) state. 4620af69d88dSmrg * In this case, the offsets and sizes associated with the 4621af69d88dSmrg * binding points are set to default values, ignoring 4622af69d88dSmrg * <offsets> and <sizes>." 4623af69d88dSmrg */ 4624af69d88dSmrg unbind_atomic_buffers(ctx, first, count); 4625af69d88dSmrg return; 4626af69d88dSmrg } 4627af69d88dSmrg 4628af69d88dSmrg /* Note that the error semantics for multi-bind commands differ from 4629af69d88dSmrg * those of other GL commands. 4630af69d88dSmrg * 4631af69d88dSmrg * The Issues section in the ARB_multi_bind spec says: 4632af69d88dSmrg * 4633af69d88dSmrg * "(11) Typically, OpenGL specifies that if an error is generated by a 4634af69d88dSmrg * command, that command has no effect. This is somewhat 4635af69d88dSmrg * unfortunate for multi-bind commands, because it would require a 4636af69d88dSmrg * first pass to scan the entire list of bound objects for errors 4637af69d88dSmrg * and then a second pass to actually perform the bindings. 4638af69d88dSmrg * Should we have different error semantics? 4639af69d88dSmrg * 4640af69d88dSmrg * RESOLVED: Yes. In this specification, when the parameters for 4641af69d88dSmrg * one of the <count> binding points are invalid, that binding point 4642af69d88dSmrg * is not updated and an error will be generated. However, other 4643af69d88dSmrg * binding points in the same command will be updated if their 4644af69d88dSmrg * parameters are valid and no other error occurs." 4645af69d88dSmrg */ 4646af69d88dSmrg 46477ec681f3Smrg _mesa_HashLockMaybeLocked(ctx->Shared->BufferObjects, 46487ec681f3Smrg ctx->BufferObjectsLocked); 4649af69d88dSmrg 465001e04c3fSmrg for (int i = 0; i < count; i++) { 465101e04c3fSmrg struct gl_buffer_binding *binding = 4652af69d88dSmrg &ctx->AtomicBufferBindings[first + i]; 465301e04c3fSmrg GLintptr offset = 0; 465401e04c3fSmrg GLsizeiptr size = 0; 4655af69d88dSmrg 465601e04c3fSmrg if (range) { 465701e04c3fSmrg if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes)) 465801e04c3fSmrg continue; 4659af69d88dSmrg 466001e04c3fSmrg /* The ARB_multi_bind spec says: 466101e04c3fSmrg * 466201e04c3fSmrg * "An INVALID_VALUE error is generated by BindBuffersRange if any 466301e04c3fSmrg * pair of values in <offsets> and <sizes> does not respectively 466401e04c3fSmrg * satisfy the constraints described for those parameters for the 466501e04c3fSmrg * specified target, as described in section 6.7.1 (per binding)." 466601e04c3fSmrg * 466701e04c3fSmrg * Section 6.7.1 refers to table 6.5, which says: 466801e04c3fSmrg * 466901e04c3fSmrg * "┌───────────────────────────────────────────────────────────────┐ 467001e04c3fSmrg * │ Atomic counter array bindings (see sec. 7.7.2) │ 467101e04c3fSmrg * ├───────────────────────┬───────────────────────────────────────┤ 467201e04c3fSmrg * │ ... │ ... │ 467301e04c3fSmrg * │ offset restriction │ multiple of 4 │ 467401e04c3fSmrg * │ ... │ ... │ 467501e04c3fSmrg * │ size restriction │ none │ 467601e04c3fSmrg * └───────────────────────┴───────────────────────────────────────┘" 467701e04c3fSmrg */ 467801e04c3fSmrg if (offsets[i] & (ATOMIC_COUNTER_SIZE - 1)) { 467901e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 468001e04c3fSmrg "glBindBuffersRange(offsets[%u]=%" PRId64 468101e04c3fSmrg " is misaligned; it must be a multiple of %d when " 468201e04c3fSmrg "target=GL_ATOMIC_COUNTER_BUFFER)", 468301e04c3fSmrg i, (int64_t) offsets[i], ATOMIC_COUNTER_SIZE); 468401e04c3fSmrg continue; 468501e04c3fSmrg } 4686af69d88dSmrg 468701e04c3fSmrg offset = offsets[i]; 468801e04c3fSmrg size = sizes[i]; 468901e04c3fSmrg } 4690af69d88dSmrg 469101e04c3fSmrg set_buffer_multi_binding(ctx, buffers, i, caller, 469201e04c3fSmrg binding, offset, size, range, 469301e04c3fSmrg USAGE_ATOMIC_COUNTER_BUFFER); 4694af69d88dSmrg } 4695af69d88dSmrg 46967ec681f3Smrg _mesa_HashUnlockMaybeLocked(ctx->Shared->BufferObjects, 46977ec681f3Smrg ctx->BufferObjectsLocked); 4698af69d88dSmrg} 4699af69d88dSmrg 470001e04c3fSmrgstatic ALWAYS_INLINE void 470101e04c3fSmrgbind_buffer_range(GLenum target, GLuint index, GLuint buffer, GLintptr offset, 470201e04c3fSmrg GLsizeiptr size, bool no_error) 4703af69d88dSmrg{ 4704af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 4705af69d88dSmrg struct gl_buffer_object *bufObj; 4706af69d88dSmrg 470701e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) { 470801e04c3fSmrg _mesa_debug(ctx, "glBindBufferRange(%s, %u, %u, %lu, %lu)\n", 470901e04c3fSmrg _mesa_enum_to_string(target), index, buffer, 471001e04c3fSmrg (unsigned long) offset, (unsigned long) size); 471101e04c3fSmrg } 471201e04c3fSmrg 4713af69d88dSmrg if (buffer == 0) { 47147ec681f3Smrg bufObj = NULL; 4715af69d88dSmrg } else { 4716af69d88dSmrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 471701e04c3fSmrg if (!_mesa_handle_bind_buffer_gen(ctx, buffer, 471801e04c3fSmrg &bufObj, "glBindBufferRange")) 471901e04c3fSmrg return; 4720af69d88dSmrg 472101e04c3fSmrg if (!no_error && !bufObj) { 472201e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 472301e04c3fSmrg "glBindBufferRange(invalid buffer=%u)", buffer); 472401e04c3fSmrg return; 472501e04c3fSmrg } 4726af69d88dSmrg } 4727af69d88dSmrg 472801e04c3fSmrg if (no_error) { 472901e04c3fSmrg switch (target) { 473001e04c3fSmrg case GL_TRANSFORM_FEEDBACK_BUFFER: 473101e04c3fSmrg _mesa_bind_buffer_range_xfb(ctx, ctx->TransformFeedback.CurrentObject, 473201e04c3fSmrg index, bufObj, offset, size); 4733af69d88dSmrg return; 473401e04c3fSmrg case GL_UNIFORM_BUFFER: 473501e04c3fSmrg bind_buffer_range_uniform_buffer(ctx, index, bufObj, offset, size); 473601e04c3fSmrg return; 473701e04c3fSmrg case GL_SHADER_STORAGE_BUFFER: 473801e04c3fSmrg bind_buffer_range_shader_storage_buffer(ctx, index, bufObj, offset, 473901e04c3fSmrg size); 474001e04c3fSmrg return; 474101e04c3fSmrg case GL_ATOMIC_COUNTER_BUFFER: 474201e04c3fSmrg bind_buffer_range_atomic_buffer(ctx, index, bufObj, offset, size); 474301e04c3fSmrg return; 474401e04c3fSmrg default: 474501e04c3fSmrg unreachable("invalid BindBufferRange target with KHR_no_error"); 474601e04c3fSmrg } 474701e04c3fSmrg } else { 474801e04c3fSmrg if (buffer != 0) { 474901e04c3fSmrg if (size <= 0) { 475001e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(size=%d)", 475101e04c3fSmrg (int) size); 475201e04c3fSmrg return; 475301e04c3fSmrg } 4754af69d88dSmrg } 4755af69d88dSmrg 475601e04c3fSmrg switch (target) { 475701e04c3fSmrg case GL_TRANSFORM_FEEDBACK_BUFFER: 475801e04c3fSmrg if (!_mesa_validate_buffer_range_xfb(ctx, 475901e04c3fSmrg ctx->TransformFeedback.CurrentObject, 476001e04c3fSmrg index, bufObj, offset, size, 476101e04c3fSmrg false)) 476201e04c3fSmrg return; 476301e04c3fSmrg 476401e04c3fSmrg _mesa_bind_buffer_range_xfb(ctx, ctx->TransformFeedback.CurrentObject, 476501e04c3fSmrg index, bufObj, offset, size); 476601e04c3fSmrg return; 476701e04c3fSmrg case GL_UNIFORM_BUFFER: 476801e04c3fSmrg bind_buffer_range_uniform_buffer_err(ctx, index, bufObj, offset, 476901e04c3fSmrg size); 477001e04c3fSmrg return; 477101e04c3fSmrg case GL_SHADER_STORAGE_BUFFER: 477201e04c3fSmrg bind_buffer_range_shader_storage_buffer_err(ctx, index, bufObj, 477301e04c3fSmrg offset, size); 477401e04c3fSmrg return; 477501e04c3fSmrg case GL_ATOMIC_COUNTER_BUFFER: 477601e04c3fSmrg bind_buffer_range_atomic_buffer_err(ctx, index, bufObj, 477701e04c3fSmrg offset, size); 477801e04c3fSmrg return; 477901e04c3fSmrg default: 478001e04c3fSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferRange(target)"); 478101e04c3fSmrg return; 478201e04c3fSmrg } 4783af69d88dSmrg } 4784af69d88dSmrg} 4785af69d88dSmrg 478601e04c3fSmrgvoid GLAPIENTRY 478701e04c3fSmrg_mesa_BindBufferRange_no_error(GLenum target, GLuint index, GLuint buffer, 478801e04c3fSmrg GLintptr offset, GLsizeiptr size) 478901e04c3fSmrg{ 479001e04c3fSmrg bind_buffer_range(target, index, buffer, offset, size, true); 479101e04c3fSmrg} 479201e04c3fSmrg 479301e04c3fSmrgvoid GLAPIENTRY 479401e04c3fSmrg_mesa_BindBufferRange(GLenum target, GLuint index, 479501e04c3fSmrg GLuint buffer, GLintptr offset, GLsizeiptr size) 479601e04c3fSmrg{ 479701e04c3fSmrg bind_buffer_range(target, index, buffer, offset, size, false); 479801e04c3fSmrg} 479901e04c3fSmrg 4800af69d88dSmrgvoid GLAPIENTRY 4801af69d88dSmrg_mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer) 4802af69d88dSmrg{ 4803af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 4804af69d88dSmrg struct gl_buffer_object *bufObj; 4805af69d88dSmrg 480601e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) { 480701e04c3fSmrg _mesa_debug(ctx, "glBindBufferBase(%s, %u, %u)\n", 480801e04c3fSmrg _mesa_enum_to_string(target), index, buffer); 480901e04c3fSmrg } 481001e04c3fSmrg 4811af69d88dSmrg if (buffer == 0) { 48127ec681f3Smrg bufObj = NULL; 4813af69d88dSmrg } else { 4814af69d88dSmrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 481501e04c3fSmrg if (!_mesa_handle_bind_buffer_gen(ctx, buffer, 481601e04c3fSmrg &bufObj, "glBindBufferBase")) 481701e04c3fSmrg return; 4818af69d88dSmrg 481901e04c3fSmrg if (!bufObj) { 482001e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 482101e04c3fSmrg "glBindBufferBase(invalid buffer=%u)", buffer); 482201e04c3fSmrg return; 482301e04c3fSmrg } 4824af69d88dSmrg } 4825af69d88dSmrg 4826af69d88dSmrg /* Note that there's some oddness in the GL 3.1-GL 3.3 specifications with 4827af69d88dSmrg * regards to BindBufferBase. It says (GL 3.1 core spec, page 63): 4828af69d88dSmrg * 4829af69d88dSmrg * "BindBufferBase is equivalent to calling BindBufferRange with offset 4830af69d88dSmrg * zero and size equal to the size of buffer." 4831af69d88dSmrg * 4832af69d88dSmrg * but it says for glGetIntegeri_v (GL 3.1 core spec, page 230): 4833af69d88dSmrg * 4834af69d88dSmrg * "If the parameter (starting offset or size) was not specified when the 4835af69d88dSmrg * buffer object was bound, zero is returned." 4836af69d88dSmrg * 4837af69d88dSmrg * What happens if the size of the buffer changes? Does the size of the 4838af69d88dSmrg * buffer at the moment glBindBufferBase was called still play a role, like 4839af69d88dSmrg * the first quote would imply, or is the size meaningless in the 4840af69d88dSmrg * glBindBufferBase case like the second quote would suggest? The GL 4.1 4841af69d88dSmrg * core spec page 45 says: 4842af69d88dSmrg * 4843af69d88dSmrg * "It is equivalent to calling BindBufferRange with offset zero, while 4844af69d88dSmrg * size is determined by the size of the bound buffer at the time the 4845af69d88dSmrg * binding is used." 4846af69d88dSmrg * 4847af69d88dSmrg * My interpretation is that the GL 4.1 spec was a clarification of the 4848af69d88dSmrg * behavior, not a change. In particular, this choice will only make 4849af69d88dSmrg * rendering work in cases where it would have had undefined results. 4850af69d88dSmrg */ 4851af69d88dSmrg 4852af69d88dSmrg switch (target) { 4853af69d88dSmrg case GL_TRANSFORM_FEEDBACK_BUFFER: 485401e04c3fSmrg _mesa_bind_buffer_base_transform_feedback(ctx, 485501e04c3fSmrg ctx->TransformFeedback.CurrentObject, 485601e04c3fSmrg index, bufObj, false); 4857af69d88dSmrg return; 4858af69d88dSmrg case GL_UNIFORM_BUFFER: 4859af69d88dSmrg bind_buffer_base_uniform_buffer(ctx, index, bufObj); 4860af69d88dSmrg return; 486101e04c3fSmrg case GL_SHADER_STORAGE_BUFFER: 486201e04c3fSmrg bind_buffer_base_shader_storage_buffer(ctx, index, bufObj); 486301e04c3fSmrg return; 4864af69d88dSmrg case GL_ATOMIC_COUNTER_BUFFER: 486501e04c3fSmrg bind_buffer_base_atomic_buffer(ctx, index, bufObj); 4866af69d88dSmrg return; 4867af69d88dSmrg default: 4868af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)"); 4869af69d88dSmrg return; 4870af69d88dSmrg } 4871af69d88dSmrg} 4872af69d88dSmrg 4873af69d88dSmrgvoid GLAPIENTRY 4874af69d88dSmrg_mesa_BindBuffersRange(GLenum target, GLuint first, GLsizei count, 4875af69d88dSmrg const GLuint *buffers, 4876af69d88dSmrg const GLintptr *offsets, const GLsizeiptr *sizes) 4877af69d88dSmrg{ 4878af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 4879af69d88dSmrg 488001e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) { 488101e04c3fSmrg _mesa_debug(ctx, "glBindBuffersRange(%s, %u, %d, %p, %p, %p)\n", 488201e04c3fSmrg _mesa_enum_to_string(target), first, count, 488301e04c3fSmrg buffers, offsets, sizes); 488401e04c3fSmrg } 488501e04c3fSmrg 4886af69d88dSmrg switch (target) { 4887af69d88dSmrg case GL_TRANSFORM_FEEDBACK_BUFFER: 488801e04c3fSmrg bind_xfb_buffers(ctx, first, count, buffers, true, offsets, sizes, 488901e04c3fSmrg "glBindBuffersRange"); 4890af69d88dSmrg return; 4891af69d88dSmrg case GL_UNIFORM_BUFFER: 489201e04c3fSmrg bind_uniform_buffers(ctx, first, count, buffers, true, offsets, sizes, 489301e04c3fSmrg "glBindBuffersRange"); 489401e04c3fSmrg return; 489501e04c3fSmrg case GL_SHADER_STORAGE_BUFFER: 489601e04c3fSmrg bind_shader_storage_buffers(ctx, first, count, buffers, true, offsets, sizes, 489701e04c3fSmrg "glBindBuffersRange"); 4898af69d88dSmrg return; 4899af69d88dSmrg case GL_ATOMIC_COUNTER_BUFFER: 490001e04c3fSmrg bind_atomic_buffers(ctx, first, count, buffers, true, offsets, sizes, 490101e04c3fSmrg "glBindBuffersRange"); 4902af69d88dSmrg return; 4903af69d88dSmrg default: 4904af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindBuffersRange(target=%s)", 490501e04c3fSmrg _mesa_enum_to_string(target)); 4906af69d88dSmrg break; 4907af69d88dSmrg } 4908af69d88dSmrg} 4909af69d88dSmrg 4910af69d88dSmrgvoid GLAPIENTRY 4911af69d88dSmrg_mesa_BindBuffersBase(GLenum target, GLuint first, GLsizei count, 4912af69d88dSmrg const GLuint *buffers) 4913af69d88dSmrg{ 4914af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 4915af69d88dSmrg 491601e04c3fSmrg if (MESA_VERBOSE & VERBOSE_API) { 491701e04c3fSmrg _mesa_debug(ctx, "glBindBuffersBase(%s, %u, %d, %p)\n", 491801e04c3fSmrg _mesa_enum_to_string(target), first, count, buffers); 491901e04c3fSmrg } 492001e04c3fSmrg 4921af69d88dSmrg switch (target) { 4922af69d88dSmrg case GL_TRANSFORM_FEEDBACK_BUFFER: 492301e04c3fSmrg bind_xfb_buffers(ctx, first, count, buffers, false, NULL, NULL, 492401e04c3fSmrg "glBindBuffersBase"); 4925af69d88dSmrg return; 4926af69d88dSmrg case GL_UNIFORM_BUFFER: 492701e04c3fSmrg bind_uniform_buffers(ctx, first, count, buffers, false, NULL, NULL, 492801e04c3fSmrg "glBindBuffersBase"); 492901e04c3fSmrg return; 493001e04c3fSmrg case GL_SHADER_STORAGE_BUFFER: 493101e04c3fSmrg bind_shader_storage_buffers(ctx, first, count, buffers, false, NULL, NULL, 493201e04c3fSmrg "glBindBuffersBase"); 4933af69d88dSmrg return; 4934af69d88dSmrg case GL_ATOMIC_COUNTER_BUFFER: 493501e04c3fSmrg bind_atomic_buffers(ctx, first, count, buffers, false, NULL, NULL, 493601e04c3fSmrg "glBindBuffersBase"); 4937af69d88dSmrg return; 4938af69d88dSmrg default: 4939af69d88dSmrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindBuffersBase(target=%s)", 494001e04c3fSmrg _mesa_enum_to_string(target)); 4941af69d88dSmrg break; 4942af69d88dSmrg } 4943af69d88dSmrg} 4944af69d88dSmrg 494501e04c3fSmrgstatic ALWAYS_INLINE void 494601e04c3fSmrginvalidate_buffer_subdata(struct gl_context *ctx, 494701e04c3fSmrg struct gl_buffer_object *bufObj, GLintptr offset, 494801e04c3fSmrg GLsizeiptr length) 494901e04c3fSmrg{ 495001e04c3fSmrg if (ctx->Driver.InvalidateBufferSubData) 495101e04c3fSmrg ctx->Driver.InvalidateBufferSubData(ctx, bufObj, offset, length); 495201e04c3fSmrg} 495301e04c3fSmrg 495401e04c3fSmrgvoid GLAPIENTRY 495501e04c3fSmrg_mesa_InvalidateBufferSubData_no_error(GLuint buffer, GLintptr offset, 495601e04c3fSmrg GLsizeiptr length) 495701e04c3fSmrg{ 495801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 495901e04c3fSmrg 496001e04c3fSmrg struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, buffer); 496101e04c3fSmrg invalidate_buffer_subdata(ctx, bufObj, offset, length); 496201e04c3fSmrg} 496301e04c3fSmrg 4964af69d88dSmrgvoid GLAPIENTRY 4965af69d88dSmrg_mesa_InvalidateBufferSubData(GLuint buffer, GLintptr offset, 4966af69d88dSmrg GLsizeiptr length) 4967af69d88dSmrg{ 4968af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 4969af69d88dSmrg struct gl_buffer_object *bufObj; 4970af69d88dSmrg const GLintptr end = offset + length; 4971af69d88dSmrg 497201e04c3fSmrg /* Section 6.5 (Invalidating Buffer Data) of the OpenGL 4.5 (Compatibility 497301e04c3fSmrg * Profile) spec says: 497401e04c3fSmrg * 497501e04c3fSmrg * "An INVALID_VALUE error is generated if buffer is zero or is not the 497601e04c3fSmrg * name of an existing buffer object." 497701e04c3fSmrg */ 4978af69d88dSmrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 497901e04c3fSmrg if (!bufObj || bufObj == &DummyBufferObject) { 4980af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 498101e04c3fSmrg "glInvalidateBufferSubData(name = %u) invalid object", 4982af69d88dSmrg buffer); 4983af69d88dSmrg return; 4984af69d88dSmrg } 4985af69d88dSmrg 4986af69d88dSmrg /* The GL_ARB_invalidate_subdata spec says: 4987af69d88dSmrg * 4988af69d88dSmrg * "An INVALID_VALUE error is generated if <offset> or <length> is 4989af69d88dSmrg * negative, or if <offset> + <length> is greater than the value of 4990af69d88dSmrg * BUFFER_SIZE." 4991af69d88dSmrg */ 499201e04c3fSmrg if (offset < 0 || length < 0 || end > bufObj->Size) { 4993af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 4994af69d88dSmrg "glInvalidateBufferSubData(invalid offset or length)"); 4995af69d88dSmrg return; 4996af69d88dSmrg } 4997af69d88dSmrg 4998af69d88dSmrg /* The OpenGL 4.4 (Core Profile) spec says: 4999af69d88dSmrg * 5000af69d88dSmrg * "An INVALID_OPERATION error is generated if buffer is currently 5001af69d88dSmrg * mapped by MapBuffer or if the invalidate range intersects the range 5002af69d88dSmrg * currently mapped by MapBufferRange, unless it was mapped 5003af69d88dSmrg * with MAP_PERSISTENT_BIT set in the MapBufferRange access flags." 5004af69d88dSmrg */ 5005af69d88dSmrg if (!(bufObj->Mappings[MAP_USER].AccessFlags & GL_MAP_PERSISTENT_BIT) && 5006af69d88dSmrg bufferobj_range_mapped(bufObj, offset, length)) { 5007af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 5008af69d88dSmrg "glInvalidateBufferSubData(intersection with mapped " 5009af69d88dSmrg "range)"); 5010af69d88dSmrg return; 5011af69d88dSmrg } 5012af69d88dSmrg 501301e04c3fSmrg invalidate_buffer_subdata(ctx, bufObj, offset, length); 501401e04c3fSmrg} 501501e04c3fSmrg 501601e04c3fSmrgvoid GLAPIENTRY 501701e04c3fSmrg_mesa_InvalidateBufferData_no_error(GLuint buffer) 501801e04c3fSmrg{ 501901e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 502001e04c3fSmrg 502101e04c3fSmrg struct gl_buffer_object *bufObj =_mesa_lookup_bufferobj(ctx, buffer); 502201e04c3fSmrg invalidate_buffer_subdata(ctx, bufObj, 0, bufObj->Size); 5023af69d88dSmrg} 5024af69d88dSmrg 5025af69d88dSmrgvoid GLAPIENTRY 5026af69d88dSmrg_mesa_InvalidateBufferData(GLuint buffer) 5027af69d88dSmrg{ 5028af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 5029af69d88dSmrg struct gl_buffer_object *bufObj; 5030af69d88dSmrg 503101e04c3fSmrg /* Section 6.5 (Invalidating Buffer Data) of the OpenGL 4.5 (Compatibility 503201e04c3fSmrg * Profile) spec says: 503301e04c3fSmrg * 503401e04c3fSmrg * "An INVALID_VALUE error is generated if buffer is zero or is not the 503501e04c3fSmrg * name of an existing buffer object." 503601e04c3fSmrg */ 5037af69d88dSmrg bufObj = _mesa_lookup_bufferobj(ctx, buffer); 503801e04c3fSmrg if (!bufObj || bufObj == &DummyBufferObject) { 5039af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 504001e04c3fSmrg "glInvalidateBufferData(name = %u) invalid object", 5041af69d88dSmrg buffer); 5042af69d88dSmrg return; 5043af69d88dSmrg } 5044af69d88dSmrg 5045af69d88dSmrg /* The OpenGL 4.4 (Core Profile) spec says: 5046af69d88dSmrg * 5047af69d88dSmrg * "An INVALID_OPERATION error is generated if buffer is currently 5048af69d88dSmrg * mapped by MapBuffer or if the invalidate range intersects the range 5049af69d88dSmrg * currently mapped by MapBufferRange, unless it was mapped 5050af69d88dSmrg * with MAP_PERSISTENT_BIT set in the MapBufferRange access flags." 5051af69d88dSmrg */ 5052af69d88dSmrg if (_mesa_check_disallowed_mapping(bufObj)) { 5053af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 5054af69d88dSmrg "glInvalidateBufferData(intersection with mapped " 5055af69d88dSmrg "range)"); 5056af69d88dSmrg return; 5057af69d88dSmrg } 5058af69d88dSmrg 505901e04c3fSmrg invalidate_buffer_subdata(ctx, bufObj, 0, bufObj->Size); 506001e04c3fSmrg} 506101e04c3fSmrg 506201e04c3fSmrgstatic void 506301e04c3fSmrgbuffer_page_commitment(struct gl_context *ctx, 506401e04c3fSmrg struct gl_buffer_object *bufferObj, 506501e04c3fSmrg GLintptr offset, GLsizeiptr size, 506601e04c3fSmrg GLboolean commit, const char *func) 506701e04c3fSmrg{ 506801e04c3fSmrg if (!(bufferObj->StorageFlags & GL_SPARSE_STORAGE_BIT_ARB)) { 506901e04c3fSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "%s(not a sparse buffer object)", 507001e04c3fSmrg func); 507101e04c3fSmrg return; 507201e04c3fSmrg } 507301e04c3fSmrg 507401e04c3fSmrg if (size < 0 || size > bufferObj->Size || 507501e04c3fSmrg offset < 0 || offset > bufferObj->Size - size) { 507601e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(out of bounds)", 507701e04c3fSmrg func); 507801e04c3fSmrg return; 507901e04c3fSmrg } 508001e04c3fSmrg 508101e04c3fSmrg /* The GL_ARB_sparse_buffer extension specification says: 508201e04c3fSmrg * 508301e04c3fSmrg * "INVALID_VALUE is generated by BufferPageCommitmentARB if <offset> is 508401e04c3fSmrg * not an integer multiple of SPARSE_BUFFER_PAGE_SIZE_ARB, or if <size> 508501e04c3fSmrg * is not an integer multiple of SPARSE_BUFFER_PAGE_SIZE_ARB and does 508601e04c3fSmrg * not extend to the end of the buffer's data store." 5087af69d88dSmrg */ 508801e04c3fSmrg if (offset % ctx->Const.SparseBufferPageSize != 0) { 508901e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset not aligned to page size)", 509001e04c3fSmrg func); 509101e04c3fSmrg return; 509201e04c3fSmrg } 509301e04c3fSmrg 509401e04c3fSmrg if (size % ctx->Const.SparseBufferPageSize != 0 && 509501e04c3fSmrg offset + size != bufferObj->Size) { 509601e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(size not aligned to page size)", 509701e04c3fSmrg func); 509801e04c3fSmrg return; 509901e04c3fSmrg } 510001e04c3fSmrg 510101e04c3fSmrg ctx->Driver.BufferPageCommitment(ctx, bufferObj, offset, size, commit); 510201e04c3fSmrg} 510301e04c3fSmrg 510401e04c3fSmrgvoid GLAPIENTRY 510501e04c3fSmrg_mesa_BufferPageCommitmentARB(GLenum target, GLintptr offset, GLsizeiptr size, 510601e04c3fSmrg GLboolean commit) 510701e04c3fSmrg{ 510801e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 510901e04c3fSmrg struct gl_buffer_object *bufferObj; 511001e04c3fSmrg 511101e04c3fSmrg bufferObj = get_buffer(ctx, "glBufferPageCommitmentARB", target, 511201e04c3fSmrg GL_INVALID_ENUM); 511301e04c3fSmrg if (!bufferObj) 511401e04c3fSmrg return; 511501e04c3fSmrg 511601e04c3fSmrg buffer_page_commitment(ctx, bufferObj, offset, size, commit, 511701e04c3fSmrg "glBufferPageCommitmentARB"); 511801e04c3fSmrg} 511901e04c3fSmrg 512001e04c3fSmrgvoid GLAPIENTRY 512101e04c3fSmrg_mesa_NamedBufferPageCommitmentARB(GLuint buffer, GLintptr offset, 512201e04c3fSmrg GLsizeiptr size, GLboolean commit) 512301e04c3fSmrg{ 512401e04c3fSmrg GET_CURRENT_CONTEXT(ctx); 512501e04c3fSmrg struct gl_buffer_object *bufferObj; 512601e04c3fSmrg 512701e04c3fSmrg bufferObj = _mesa_lookup_bufferobj(ctx, buffer); 512801e04c3fSmrg if (!bufferObj || bufferObj == &DummyBufferObject) { 512901e04c3fSmrg /* Note: the extension spec is not clear about the excpected error value. */ 513001e04c3fSmrg _mesa_error(ctx, GL_INVALID_VALUE, 513101e04c3fSmrg "glNamedBufferPageCommitmentARB(name = %u) invalid object", 513201e04c3fSmrg buffer); 513301e04c3fSmrg return; 513401e04c3fSmrg } 513501e04c3fSmrg 513601e04c3fSmrg buffer_page_commitment(ctx, bufferObj, offset, size, commit, 513701e04c3fSmrg "glNamedBufferPageCommitmentARB"); 5138af69d88dSmrg} 51397ec681f3Smrg 51407ec681f3Smrgvoid GLAPIENTRY 51417ec681f3Smrg_mesa_NamedBufferPageCommitmentEXT(GLuint buffer, GLintptr offset, 51427ec681f3Smrg GLsizeiptr size, GLboolean commit) 51437ec681f3Smrg{ 51447ec681f3Smrg GET_CURRENT_CONTEXT(ctx); 51457ec681f3Smrg struct gl_buffer_object *bufferObj; 51467ec681f3Smrg 51477ec681f3Smrg /* Use NamedBuffer* functions logic from EXT_direct_state_access */ 51487ec681f3Smrg if (buffer != 0) { 51497ec681f3Smrg bufferObj = _mesa_lookup_bufferobj(ctx, buffer); 51507ec681f3Smrg if (!_mesa_handle_bind_buffer_gen(ctx, buffer, &bufferObj, 51517ec681f3Smrg "glNamedBufferPageCommitmentEXT")) 51527ec681f3Smrg return; 51537ec681f3Smrg } else { 51547ec681f3Smrg /* GL_EXT_direct_state_access says about NamedBuffer* functions: 51557ec681f3Smrg * 51567ec681f3Smrg * There is no buffer corresponding to the name zero, these commands 51577ec681f3Smrg * generate the INVALID_OPERATION error if the buffer parameter is 51587ec681f3Smrg * zero. 51597ec681f3Smrg */ 51607ec681f3Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 51617ec681f3Smrg "glNamedBufferPageCommitmentEXT(buffer = 0)"); 51627ec681f3Smrg return; 51637ec681f3Smrg } 51647ec681f3Smrg buffer_page_commitment(ctx, bufferObj, offset, size, commit, 51657ec681f3Smrg "glNamedBufferPageCommitmentEXT"); 51667ec681f3Smrg} 5167