#include <stdbool.h>
#include <inttypes.h> /* for PRId64 macro */
+#include "util/debug.h"
#include "glheader.h"
#include "enums.h"
#include "hash.h"
#include "imports.h"
-#include "image.h"
#include "context.h"
#include "bufferobj.h"
-#include "fbobject.h"
#include "mtypes.h"
-#include "texobj.h"
#include "teximage.h"
#include "glformats.h"
#include "texstore.h"
#include "transformfeedback.h"
-#include "dispatch.h"
+#include "varray.h"
/* Debug flags */
/*#define BOUNDS_CHECK*/
+/**
+ * We count the number of buffer modification calls to check for
+ * inefficient buffer use. This is the number of such calls before we
+ * issue a warning.
+ */
+#define BUFFER_WARNING_CALL_COUNT 4
+
+
+/**
+ * Helper to warn of possible performance issues, such as frequently
+ * updating a buffer created with GL_STATIC_DRAW. Called via the macro
+ * below.
+ */
+static void
+buffer_usage_warning(struct gl_context *ctx, GLuint *id, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ _mesa_gl_vdebug(ctx, id,
+ MESA_DEBUG_SOURCE_API,
+ MESA_DEBUG_TYPE_PERFORMANCE,
+ MESA_DEBUG_SEVERITY_MEDIUM,
+ fmt, args);
+ va_end(args);
+}
+
+#define BUFFER_USAGE_WARNING(CTX, FMT, ...) \
+ do { \
+ static GLuint id = 0; \
+ buffer_usage_warning(CTX, &id, FMT, ##__VA_ARGS__); \
+ } while (0)
+
+
/**
* Used as a placeholder for buffer objects between glGenBuffers() and
* glBindBuffer() so that glIsBuffer() can work correctly.
return &ctx->CopyReadBuffer;
case GL_COPY_WRITE_BUFFER:
return &ctx->CopyWriteBuffer;
+ case GL_QUERY_BUFFER:
+ if (_mesa_has_ARB_query_buffer_object(ctx))
+ return &ctx->QueryBuffer;
+ break;
case GL_DRAW_INDIRECT_BUFFER:
- if (ctx->API == API_OPENGL_CORE &&
- ctx->Extensions.ARB_draw_indirect) {
+ if ((ctx->API == API_OPENGL_CORE &&
+ ctx->Extensions.ARB_draw_indirect) ||
+ _mesa_is_gles31(ctx)) {
return &ctx->DrawIndirectBuffer;
}
break;
+ case GL_PARAMETER_BUFFER_ARB:
+ if (_mesa_has_ARB_indirect_parameters(ctx)) {
+ return &ctx->ParameterBuffer;
+ }
+ break;
+ case GL_DISPATCH_INDIRECT_BUFFER:
+ if (_mesa_has_compute_shaders(ctx)) {
+ return &ctx->DispatchIndirectBuffer;
+ }
+ break;
case GL_TRANSFORM_FEEDBACK_BUFFER:
if (ctx->Extensions.EXT_transform_feedback) {
return &ctx->TransformFeedback.CurrentBuffer;
}
break;
case GL_TEXTURE_BUFFER:
- if (ctx->API == API_OPENGL_CORE &&
- ctx->Extensions.ARB_texture_buffer_object) {
+ if (_mesa_has_ARB_texture_buffer_object(ctx) ||
+ _mesa_has_OES_texture_buffer(ctx)) {
return &ctx->Texture.BufferObject;
}
break;
*/
static bool
buffer_object_subdata_range_good(struct gl_context *ctx,
- struct gl_buffer_object *bufObj,
+ const struct gl_buffer_object *bufObj,
GLintptr offset, GLsizeiptr size,
bool mappedRange, const char *caller)
{
/**
* Allocate and initialize a new buffer object.
- *
+ *
* Default callback for the \c dd_function_table::NewBufferObject() hook.
*/
static struct gl_buffer_object *
/**
* Delete a buffer object.
- *
+ *
* Default callback for the \c dd_function_table::DeleteBuffer() hook.
*/
-static void
+void
_mesa_delete_buffer_object(struct gl_context *ctx,
struct gl_buffer_object *bufObj)
{
(void) ctx;
+ vbo_delete_minmax_cache(bufObj);
_mesa_align_free(bufObj->Data);
/* assign strange values here to help w/ debugging */
mtx_lock(&oldObj->Mutex);
assert(oldObj->RefCount > 0);
oldObj->RefCount--;
-#if 0
- printf("BufferObj %p %d DECR to %d\n",
- (void *) oldObj, oldObj->Name, oldObj->RefCount);
-#endif
deleteFlag = (oldObj->RefCount == 0);
mtx_unlock(&oldObj->Mutex);
if (deleteFlag) {
-
- /* some sanity checking: don't delete a buffer still in use */
-#if 0
- /* unfortunately, these tests are invalid during context tear-down */
- assert(ctx->Array.ArrayBufferObj != bufObj);
- assert(ctx->Array.VAO->IndexBufferObj != bufObj);
- assert(ctx->Array.VAO->Vertex.BufferObj != bufObj);
-#endif
-
assert(ctx->Driver.DeleteBuffer);
ctx->Driver.DeleteBuffer(ctx, oldObj);
}
}
else {
bufObj->RefCount++;
-#if 0
- printf("BufferObj %p %d INCR to %d\n",
- (void *) bufObj, bufObj->Name, bufObj->RefCount);
-#endif
*ptr = bufObj;
}
mtx_unlock(&bufObj->Mutex);
}
+/**
+ * Get the value of MESA_NO_MINMAX_CACHE.
+ */
+static bool
+get_no_minmax_cache()
+{
+ static bool read = false;
+ static bool disable = false;
+
+ if (!read) {
+ disable = env_var_as_boolean("MESA_NO_MINMAX_CACHE", false);
+ read = true;
+ }
+
+ return disable;
+}
+
+
/**
* Initialize a buffer object to default values.
*/
obj->RefCount = 1;
obj->Name = name;
obj->Usage = GL_STATIC_DRAW_ARB;
+
+ if (get_no_minmax_cache())
+ obj->UsageHistory |= USAGE_DISABLE_MINMAX_CACHE;
}
(const struct gl_buffer_object *) data;
GLuint *total = (GLuint *) userData;
+ (void) key;
*total = *total + bufObj->Size;
}
(void) offset;
(void) length;
(void) obj;
+ (void) index;
/* no-op */
}
_mesa_reference_buffer_object(ctx, &ctx->DrawIndirectBuffer,
ctx->Shared->NullBufferObj);
+ _mesa_reference_buffer_object(ctx, &ctx->ParameterBuffer,
+ ctx->Shared->NullBufferObj);
+
+ _mesa_reference_buffer_object(ctx, &ctx->DispatchIndirectBuffer,
+ ctx->Shared->NullBufferObj);
+
+ _mesa_reference_buffer_object(ctx, &ctx->QueryBuffer,
+ ctx->Shared->NullBufferObj);
+
for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) {
_mesa_reference_buffer_object(ctx,
&ctx->UniformBufferBindings[i].BufferObject,
_mesa_reference_buffer_object(ctx,
&ctx->AtomicBufferBindings[i].BufferObject,
ctx->Shared->NullBufferObj);
- ctx->AtomicBufferBindings[i].Offset = -1;
- ctx->AtomicBufferBindings[i].Size = -1;
+ ctx->AtomicBufferBindings[i].Offset = 0;
+ ctx->AtomicBufferBindings[i].Size = 0;
}
}
_mesa_reference_buffer_object(ctx, &ctx->DrawIndirectBuffer, NULL);
+ _mesa_reference_buffer_object(ctx, &ctx->ParameterBuffer, NULL);
+
+ _mesa_reference_buffer_object(ctx, &ctx->DispatchIndirectBuffer, NULL);
+
+ _mesa_reference_buffer_object(ctx, &ctx->QueryBuffer, NULL);
+
for (i = 0; i < MAX_COMBINED_UNIFORM_BUFFERS; i++) {
_mesa_reference_buffer_object(ctx,
&ctx->UniformBufferBindings[i].BufferObject,
bool
_mesa_handle_bind_buffer_gen(struct gl_context *ctx,
- GLenum target,
GLuint buffer,
struct gl_buffer_object **buf_handle,
const char *caller)
{
struct gl_buffer_object *buf = *buf_handle;
- if (!buf && ctx->API == API_OPENGL_CORE) {
+ if (!buf && (ctx->API == API_OPENGL_CORE)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", caller);
return false;
}
bindTarget = get_buffer_target(ctx, target);
if (!bindTarget) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target 0x%x)", target);
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferARB(target %s)",
+ _mesa_enum_to_string(target));
return;
}
else {
/* non-default buffer object */
newBufObj = _mesa_lookup_bufferobj(ctx, buffer);
- if (!_mesa_handle_bind_buffer_gen(ctx, target, buffer,
+ if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
&newBufObj, "glBindBuffer"))
return;
}
-
+
+ /* record usage history */
+ switch (target) {
+ case GL_PIXEL_PACK_BUFFER:
+ newBufObj->UsageHistory |= USAGE_PIXEL_PACK_BUFFER;
+ break;
+ default:
+ break;
+ }
+
/* bind new buffer */
_mesa_reference_buffer_object(ctx, bindTarget, newBufObj);
}
/**
* Update the default buffer objects in the given context to reference those
- * specified in the shared state and release those referencing the old
+ * specified in the shared state and release those referencing the old
* shared state.
*/
void
struct gl_buffer_object *
_mesa_lookup_bufferobj_locked(struct gl_context *ctx, GLuint buffer)
{
- return (struct gl_buffer_object *)
- _mesa_HashLookupLocked(ctx->Shared->BufferObjects, buffer);
+ if (buffer == 0)
+ return NULL;
+ else
+ return (struct gl_buffer_object *)
+ _mesa_HashLookupLocked(ctx->Shared->BufferObjects, buffer);
}
/**
*/
static void
unbind(struct gl_context *ctx,
- struct gl_buffer_object **ptr,
+ struct gl_vertex_array_object *vao, unsigned index,
struct gl_buffer_object *obj)
{
- if (*ptr == obj) {
- _mesa_reference_buffer_object(ctx, ptr, ctx->Shared->NullBufferObj);
+ if (vao->VertexBinding[index].BufferObj == obj) {
+ _mesa_bind_vertex_buffer(ctx, vao, index, ctx->Shared->NullBufferObj,
+ vao->VertexBinding[index].Offset,
+ vao->VertexBinding[index].Stride);
}
}
{
GET_CURRENT_CONTEXT(ctx);
- if (MESA_VERBOSE & VERBOSE_API)
+ if (MESA_VERBOSE & VERBOSE_API) {
_mesa_debug(ctx, "glBindBuffer(%s, %u)\n",
- _mesa_lookup_enum_by_nr(target), buffer);
+ _mesa_enum_to_string(target), buffer);
+ }
bind_buffer_object(ctx, target, buffer);
}
/**
* Delete a set of buffer objects.
- *
+ *
* \param n Number of buffer objects to delete.
* \param ids Array of \c n buffer object IDs.
*/
return;
}
- mtx_lock(&ctx->Shared->Mutex);
+ _mesa_HashLockMutex(ctx->Shared->BufferObjects);
for (i = 0; i < n; i++) {
- struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, ids[i]);
+ struct gl_buffer_object *bufObj =
+ _mesa_lookup_bufferobj_locked(ctx, ids[i]);
if (bufObj) {
struct gl_vertex_array_object *vao = ctx->Array.VAO;
GLuint j;
/* unbind any vertex pointers bound to this buffer */
for (j = 0; j < ARRAY_SIZE(vao->VertexBinding); j++) {
- unbind(ctx, &vao->VertexBinding[j].BufferObj, bufObj);
+ unbind(ctx, vao, j, bufObj);
}
if (ctx->Array.ArrayBufferObj == bufObj) {
_mesa_BindBuffer( GL_DRAW_INDIRECT_BUFFER, 0 );
}
+ /* unbind ARB_indirect_parameters binding point */
+ if (ctx->ParameterBuffer == bufObj) {
+ _mesa_BindBuffer(GL_PARAMETER_BUFFER_ARB, 0);
+ }
+
+ /* unbind ARB_compute_shader binding point */
+ if (ctx->DispatchIndirectBuffer == bufObj) {
+ _mesa_BindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0);
+ }
+
/* unbind ARB_copy_buffer binding points */
if (ctx->CopyReadBuffer == bufObj) {
_mesa_BindBuffer( GL_COPY_READ_BUFFER, 0 );
_mesa_BindBuffer(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0);
}
+ /* unbind query buffer binding point */
+ if (ctx->QueryBuffer == bufObj) {
+ _mesa_BindBuffer(GL_QUERY_BUFFER, 0);
+ }
+
/* The ID is immediately freed for re-use */
- _mesa_HashRemove(ctx->Shared->BufferObjects, ids[i]);
+ _mesa_HashRemoveLocked(ctx->Shared->BufferObjects, ids[i]);
/* Make sure we do not run into the classic ABA problem on bind.
* We don't want to allow re-binding a buffer object that's been
* "deleted" by glDeleteBuffers().
}
}
- mtx_unlock(&ctx->Shared->Mutex);
+ _mesa_HashUnlockMutex(ctx->Shared->BufferObjects);
}
/*
* This must be atomic (generation and allocation of buffer object IDs)
*/
- mtx_lock(&ctx->Shared->Mutex);
+ _mesa_HashLockMutex(ctx->Shared->BufferObjects);
first = _mesa_HashFindFreeKeyBlock(ctx->Shared->BufferObjects, n);
buf = ctx->Driver.NewBufferObject(ctx, buffers[i]);
if (!buf) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
- mtx_unlock(&ctx->Shared->Mutex);
+ _mesa_HashUnlockMutex(ctx->Shared->BufferObjects);
return;
}
}
else
buf = &DummyBufferObject;
- _mesa_HashInsert(ctx->Shared->BufferObjects, buffers[i], buf);
+ _mesa_HashInsertLocked(ctx->Shared->BufferObjects, buffers[i], buf);
}
- mtx_unlock(&ctx->Shared->Mutex);
+ _mesa_HashUnlockMutex(ctx->Shared->BufferObjects);
}
/**
/**
* Determine if ID is the name of a buffer object.
- *
+ *
* \param id ID of the potential buffer object.
- * \return \c GL_TRUE if \c id is the name of a buffer object,
+ * \return \c GL_TRUE if \c id is the name of a buffer object,
* \c GL_FALSE otherwise.
*/
GLboolean GLAPIENTRY
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
- mtx_lock(&ctx->Shared->Mutex);
bufObj = _mesa_lookup_bufferobj(ctx, id);
- mtx_unlock(&ctx->Shared->Mutex);
return bufObj && bufObj != &DummyBufferObject;
}
bufObj->Written = GL_TRUE;
bufObj->Immutable = GL_TRUE;
+ bufObj->MinMaxCacheDirty = true;
assert(ctx->Driver.BufferData);
if (!ctx->Driver.BufferData(ctx, target, size, data, GL_DYNAMIC_DRAW,
{
bool valid_usage;
- if (MESA_VERBOSE & VERBOSE_API)
+ if (MESA_VERBOSE & VERBOSE_API) {
_mesa_debug(ctx, "%s(%s, %ld, %p, %s)\n",
func,
- _mesa_lookup_enum_by_nr(target),
+ _mesa_enum_to_string(target),
(long int) size, data,
- _mesa_lookup_enum_by_nr(usage));
+ _mesa_enum_to_string(usage));
+ }
if (size < 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "%s(size < 0)", func);
if (!valid_usage) {
_mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid usage: %s)", func,
- _mesa_lookup_enum_by_nr(usage));
+ _mesa_enum_to_string(usage));
return;
}
FLUSH_VERTICES(ctx, _NEW_BUFFER_OBJECT);
bufObj->Written = GL_TRUE;
+ bufObj->MinMaxCacheDirty = true;
#ifdef VBO_DEBUG
printf("glBufferDataARB(%u, sz %ld, from %p, usage 0x%x)\n",
const char *func)
{
if (!buffer_object_subdata_range_good(ctx, bufObj, offset, size,
- false, func)) {
+ true, func)) {
/* error already recorded */
return;
}
if (size == 0)
return;
+ bufObj->NumSubDataCalls++;
+
+ if ((bufObj->Usage == GL_STATIC_DRAW ||
+ bufObj->Usage == GL_STATIC_COPY) &&
+ bufObj->NumSubDataCalls >= BUFFER_WARNING_CALL_COUNT) {
+ /* If the application declared the buffer as static draw/copy or stream
+ * draw, it should not be frequently modified with glBufferSubData.
+ */
+ BUFFER_USAGE_WARNING(ctx,
+ "using %s(buffer %u, offset %u, size %u) to "
+ "update a %s buffer",
+ func, bufObj->Name, offset, size,
+ _mesa_enum_to_string(bufObj->Usage));
+ }
+
bufObj->Written = GL_TRUE;
+ bufObj->MinMaxCacheDirty = true;
assert(ctx->Driver.BufferSubData);
ctx->Driver.BufferSubData(ctx, offset, size, data, bufObj);
return;
}
+ /* Bail early. Negative size has already been checked. */
+ if (size == 0)
+ return;
+
+ bufObj->MinMaxCacheDirty = true;
+
if (data == NULL) {
/* clear to zeros, per the spec */
- if (size > 0) {
- ctx->Driver.ClearBufferSubData(ctx, offset, size,
- NULL, clearValueSize, bufObj);
- }
+ ctx->Driver.ClearBufferSubData(ctx, offset, size,
+ NULL, clearValueSize, bufObj);
return;
}
return;
}
- if (size > 0) {
- ctx->Driver.ClearBufferSubData(ctx, offset, size,
- clearValue, clearValueSize, bufObj);
- }
+ ctx->Driver.ClearBufferSubData(ctx, offset, size,
+ clearValue, clearValueSize, bufObj);
}
void GLAPIENTRY
invalid_pname:
_mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname: %s)", func,
- _mesa_lookup_enum_by_nr(pname));
+ _mesa_enum_to_string(pname));
return false;
}
}
}
+ dst->MinMaxCacheDirty = true;
+
ctx->Driver.CopyBufferSubData(ctx, src, dst, readOffset, writeOffset, size);
}
if (offset + length > bufObj->Size) {
_mesa_error(ctx, GL_INVALID_VALUE,
- "%s(offset %ld + length %ld > buffer_size %ld)", func,
- offset, length, bufObj->Size);
+ "%s(offset %lu + length %lu > buffer_size %lu)", func,
+ (unsigned long) offset, (unsigned long) length,
+ (unsigned long) bufObj->Size);
return NULL;
}
return NULL;
}
+ if (access & GL_MAP_WRITE_BIT) {
+ bufObj->NumMapBufferWriteCalls++;
+ if ((bufObj->Usage == GL_STATIC_DRAW ||
+ bufObj->Usage == GL_STATIC_COPY) &&
+ bufObj->NumMapBufferWriteCalls >= BUFFER_WARNING_CALL_COUNT) {
+ BUFFER_USAGE_WARNING(ctx,
+ "using %s(buffer %u, offset %u, length %u) to "
+ "update a %s buffer",
+ func, bufObj->Name, offset, length,
+ _mesa_enum_to_string(bufObj->Usage));
+ }
+ }
assert(ctx->Driver.MapBufferRange);
map = ctx->Driver.MapBufferRange(ctx, offset, length, access, bufObj,
assert(bufObj->Mappings[MAP_USER].AccessFlags == access);
}
- if (access & GL_MAP_WRITE_BIT)
+ if (access & GL_MAP_WRITE_BIT) {
bufObj->Written = GL_TRUE;
+ bufObj->MinMaxCacheDirty = true;
+ }
#ifdef VBO_DEBUG
if (strstr(func, "Range") == NULL) { /* If not MapRange */
}
-static GLenum
-buffer_object_purgeable(struct gl_context *ctx, GLuint name, GLenum option)
+/**
+ * Binds a buffer object to a uniform buffer binding point.
+ *
+ * The caller is responsible for flushing vertices and updating
+ * NewDriverState.
+ */
+static void
+set_ubo_binding(struct gl_context *ctx,
+ struct gl_uniform_buffer_binding *binding,
+ struct gl_buffer_object *bufObj,
+ GLintptr offset,
+ GLsizeiptr size,
+ GLboolean autoSize)
{
- struct gl_buffer_object *bufObj;
- GLenum retval;
+ _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj);
- bufObj = _mesa_lookup_bufferobj(ctx, name);
- if (!bufObj) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glObjectPurgeable(name = 0x%x)", name);
- return 0;
- }
- if (!_mesa_is_bufferobj(bufObj)) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glObjectPurgeable(buffer 0)" );
- return 0;
- }
+ binding->Offset = offset;
+ binding->Size = size;
+ binding->AutomaticSize = autoSize;
- if (bufObj->Purgeable) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glObjectPurgeable(name = 0x%x) is already purgeable", name);
- return GL_VOLATILE_APPLE;
- }
+ /* If this is a real buffer object, mark it has having been used
+ * at some point as a UBO.
+ */
+ if (size >= 0)
+ bufObj->UsageHistory |= USAGE_UNIFORM_BUFFER;
+}
- bufObj->Purgeable = GL_TRUE;
+/**
+ * Binds a buffer object to a shader storage buffer binding point.
+ *
+ * The caller is responsible for flushing vertices and updating
+ * NewDriverState.
+ */
+static void
+set_ssbo_binding(struct gl_context *ctx,
+ struct gl_shader_storage_buffer_binding *binding,
+ struct gl_buffer_object *bufObj,
+ GLintptr offset,
+ GLsizeiptr size,
+ GLboolean autoSize)
+{
+ _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj);
- retval = GL_VOLATILE_APPLE;
- if (ctx->Driver.BufferObjectPurgeable)
- retval = ctx->Driver.BufferObjectPurgeable(ctx, bufObj, option);
+ binding->Offset = offset;
+ binding->Size = size;
+ binding->AutomaticSize = autoSize;
- return retval;
+ /* If this is a real buffer object, mark it has having been used
+ * at some point as a SSBO.
+ */
+ if (size >= 0)
+ bufObj->UsageHistory |= USAGE_SHADER_STORAGE_BUFFER;
}
-
-static GLenum
-renderbuffer_purgeable(struct gl_context *ctx, GLuint name, GLenum option)
+/**
+ * Binds a buffer object to a uniform buffer binding point.
+ *
+ * Unlike set_ubo_binding(), this function also flushes vertices
+ * and updates NewDriverState. It also checks if the binding
+ * has actually changed before updating it.
+ */
+static void
+bind_uniform_buffer(struct gl_context *ctx,
+ GLuint index,
+ struct gl_buffer_object *bufObj,
+ GLintptr offset,
+ GLsizeiptr size,
+ GLboolean autoSize)
{
- struct gl_renderbuffer *bufObj;
- GLenum retval;
-
- bufObj = _mesa_lookup_renderbuffer(ctx, name);
- if (!bufObj) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glObjectUnpurgeable(name = 0x%x)", name);
- return 0;
- }
+ struct gl_uniform_buffer_binding *binding =
+ &ctx->UniformBufferBindings[index];
- if (bufObj->Purgeable) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glObjectPurgeable(name = 0x%x) is already purgeable", name);
- return GL_VOLATILE_APPLE;
+ if (binding->BufferObject == bufObj &&
+ binding->Offset == offset &&
+ binding->Size == size &&
+ binding->AutomaticSize == autoSize) {
+ return;
}
- bufObj->Purgeable = GL_TRUE;
-
- retval = GL_VOLATILE_APPLE;
- if (ctx->Driver.RenderObjectPurgeable)
- retval = ctx->Driver.RenderObjectPurgeable(ctx, bufObj, option);
+ FLUSH_VERTICES(ctx, 0);
+ ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer;
- return retval;
+ set_ubo_binding(ctx, binding, bufObj, offset, size, autoSize);
}
-
-static GLenum
-texture_object_purgeable(struct gl_context *ctx, GLuint name, GLenum option)
+/**
+ * Binds a buffer object to a shader storage buffer binding point.
+ *
+ * Unlike set_ssbo_binding(), this function also flushes vertices
+ * and updates NewDriverState. It also checks if the binding
+ * has actually changed before updating it.
+ */
+static void
+bind_shader_storage_buffer(struct gl_context *ctx,
+ GLuint index,
+ struct gl_buffer_object *bufObj,
+ GLintptr offset,
+ GLsizeiptr size,
+ GLboolean autoSize)
{
- struct gl_texture_object *bufObj;
- GLenum retval;
-
- bufObj = _mesa_lookup_texture(ctx, name);
- if (!bufObj) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glObjectPurgeable(name = 0x%x)", name);
- return 0;
- }
+ struct gl_shader_storage_buffer_binding *binding =
+ &ctx->ShaderStorageBufferBindings[index];
- if (bufObj->Purgeable) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glObjectPurgeable(name = 0x%x) is already purgeable", name);
- return GL_VOLATILE_APPLE;
+ if (binding->BufferObject == bufObj &&
+ binding->Offset == offset &&
+ binding->Size == size &&
+ binding->AutomaticSize == autoSize) {
+ return;
}
- bufObj->Purgeable = GL_TRUE;
-
- retval = GL_VOLATILE_APPLE;
- if (ctx->Driver.TextureObjectPurgeable)
- retval = ctx->Driver.TextureObjectPurgeable(ctx, bufObj, option);
+ FLUSH_VERTICES(ctx, 0);
+ ctx->NewDriverState |= ctx->DriverFlags.NewShaderStorageBuffer;
- return retval;
+ set_ssbo_binding(ctx, binding, bufObj, offset, size, autoSize);
}
-
-GLenum GLAPIENTRY
-_mesa_ObjectPurgeableAPPLE(GLenum objectType, GLuint name, GLenum option)
+/**
+ * Bind a region of a buffer object to a uniform block binding point.
+ * \param index the uniform buffer binding point index
+ * \param bufObj the buffer object
+ * \param offset offset to the start of buffer object region
+ * \param size size of the buffer object region
+ */
+static void
+bind_buffer_range_uniform_buffer(struct gl_context *ctx,
+ GLuint index,
+ struct gl_buffer_object *bufObj,
+ GLintptr offset,
+ GLsizeiptr size)
{
- GLenum retval;
-
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
-
- if (name == 0) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glObjectPurgeable(name = 0x%x)", name);
- return 0;
+ if (index >= ctx->Const.MaxUniformBufferBindings) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index);
+ return;
}
- switch (option) {
- case GL_VOLATILE_APPLE:
- case GL_RELEASED_APPLE:
- /* legal */
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glObjectPurgeable(name = 0x%x) invalid option: %d",
- name, option);
- return 0;
+ if (offset & (ctx->Const.UniformBufferOffsetAlignment - 1)) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glBindBufferRange(offset misaligned %d/%d)", (int) offset,
+ ctx->Const.UniformBufferOffsetAlignment);
+ return;
}
- switch (objectType) {
- case GL_TEXTURE:
- retval = texture_object_purgeable(ctx, name, option);
- break;
- case GL_RENDERBUFFER_EXT:
- retval = renderbuffer_purgeable(ctx, name, option);
- break;
- case GL_BUFFER_OBJECT_APPLE:
- retval = buffer_object_purgeable(ctx, name, option);
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glObjectPurgeable(name = 0x%x) invalid type: %d",
- name, objectType);
- return 0;
+ if (bufObj == ctx->Shared->NullBufferObj) {
+ offset = -1;
+ size = -1;
}
- /* In strict conformance to the spec, we must only return VOLATILE when
- * when passed the VOLATILE option. Madness.
- *
- * XXX First fix the spec, then fix me.
- */
- return option == GL_VOLATILE_APPLE ? GL_VOLATILE_APPLE : retval;
+ _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj);
+ bind_uniform_buffer(ctx, index, bufObj, offset, size, GL_FALSE);
}
-
-static GLenum
-buffer_object_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
+/**
+ * Bind a region of a buffer object to a shader storage block binding point.
+ * \param index the shader storage buffer binding point index
+ * \param bufObj the buffer object
+ * \param offset offset to the start of buffer object region
+ * \param size size of the buffer object region
+ */
+static void
+bind_buffer_range_shader_storage_buffer(struct gl_context *ctx,
+ GLuint index,
+ struct gl_buffer_object *bufObj,
+ GLintptr offset,
+ GLsizeiptr size)
{
- struct gl_buffer_object *bufObj;
- GLenum retval;
+ if (index >= ctx->Const.MaxShaderStorageBufferBindings) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index);
+ return;
+ }
- bufObj = _mesa_lookup_bufferobj(ctx, name);
- if (!bufObj) {
+ if (offset & (ctx->Const.ShaderStorageBufferOffsetAlignment - 1)) {
_mesa_error(ctx, GL_INVALID_VALUE,
- "glObjectUnpurgeable(name = 0x%x)", name);
- return 0;
- }
-
- if (! bufObj->Purgeable) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glObjectUnpurgeable(name = 0x%x) object is "
- " already \"unpurged\"", name);
- return 0;
- }
-
- bufObj->Purgeable = GL_FALSE;
-
- retval = option;
- if (ctx->Driver.BufferObjectUnpurgeable)
- retval = ctx->Driver.BufferObjectUnpurgeable(ctx, bufObj, option);
-
- return retval;
-}
-
-
-static GLenum
-renderbuffer_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
-{
- struct gl_renderbuffer *bufObj;
- GLenum retval;
-
- bufObj = _mesa_lookup_renderbuffer(ctx, name);
- if (!bufObj) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glObjectUnpurgeable(name = 0x%x)", name);
- return 0;
- }
-
- if (! bufObj->Purgeable) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glObjectUnpurgeable(name = 0x%x) object is "
- " already \"unpurged\"", name);
- return 0;
- }
-
- bufObj->Purgeable = GL_FALSE;
-
- retval = option;
- if (ctx->Driver.RenderObjectUnpurgeable)
- retval = ctx->Driver.RenderObjectUnpurgeable(ctx, bufObj, option);
-
- return retval;
-}
-
-
-static GLenum
-texture_object_unpurgeable(struct gl_context *ctx, GLuint name, GLenum option)
-{
- struct gl_texture_object *bufObj;
- GLenum retval;
-
- bufObj = _mesa_lookup_texture(ctx, name);
- if (!bufObj) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glObjectUnpurgeable(name = 0x%x)", name);
- return 0;
- }
-
- if (! bufObj->Purgeable) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glObjectUnpurgeable(name = 0x%x) object is"
- " already \"unpurged\"", name);
- return 0;
- }
-
- bufObj->Purgeable = GL_FALSE;
-
- retval = option;
- if (ctx->Driver.TextureObjectUnpurgeable)
- retval = ctx->Driver.TextureObjectUnpurgeable(ctx, bufObj, option);
-
- return retval;
-}
-
-
-GLenum GLAPIENTRY
-_mesa_ObjectUnpurgeableAPPLE(GLenum objectType, GLuint name, GLenum option)
-{
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
-
- if (name == 0) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glObjectUnpurgeable(name = 0x%x)", name);
- return 0;
- }
-
- switch (option) {
- case GL_RETAINED_APPLE:
- case GL_UNDEFINED_APPLE:
- /* legal */
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glObjectUnpurgeable(name = 0x%x) invalid option: %d",
- name, option);
- return 0;
- }
-
- switch (objectType) {
- case GL_BUFFER_OBJECT_APPLE:
- return buffer_object_unpurgeable(ctx, name, option);
- case GL_TEXTURE:
- return texture_object_unpurgeable(ctx, name, option);
- case GL_RENDERBUFFER_EXT:
- return renderbuffer_unpurgeable(ctx, name, option);
- default:
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glObjectUnpurgeable(name = 0x%x) invalid type: %d",
- name, objectType);
- return 0;
- }
-}
-
-
-static void
-get_buffer_object_parameteriv(struct gl_context *ctx, GLuint name,
- GLenum pname, GLint *params)
-{
- struct gl_buffer_object *bufObj = _mesa_lookup_bufferobj(ctx, name);
- if (!bufObj) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glGetObjectParameteriv(name = 0x%x) invalid object", name);
- return;
- }
-
- switch (pname) {
- case GL_PURGEABLE_APPLE:
- *params = bufObj->Purgeable;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
- name, pname);
- break;
- }
-}
-
-
-static void
-get_renderbuffer_parameteriv(struct gl_context *ctx, GLuint name,
- GLenum pname, GLint *params)
-{
- struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name);
- if (!rb) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glObjectUnpurgeable(name = 0x%x)", name);
- return;
- }
-
- switch (pname) {
- case GL_PURGEABLE_APPLE:
- *params = rb->Purgeable;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
- name, pname);
- break;
- }
-}
-
-
-static void
-get_texture_object_parameteriv(struct gl_context *ctx, GLuint name,
- GLenum pname, GLint *params)
-{
- struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name);
- if (!texObj) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glObjectUnpurgeable(name = 0x%x)", name);
- return;
- }
-
- switch (pname) {
- case GL_PURGEABLE_APPLE:
- *params = texObj->Purgeable;
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetObjectParameteriv(name = 0x%x) invalid enum: %d",
- name, pname);
- break;
- }
-}
-
-
-void GLAPIENTRY
-_mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname,
- GLint *params)
-{
- GET_CURRENT_CONTEXT(ctx);
-
- if (name == 0) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glGetObjectParameteriv(name = 0x%x)", name);
- return;
- }
-
- switch (objectType) {
- case GL_TEXTURE:
- get_texture_object_parameteriv(ctx, name, pname, params);
- break;
- case GL_BUFFER_OBJECT_APPLE:
- get_buffer_object_parameteriv(ctx, name, pname, params);
- break;
- case GL_RENDERBUFFER_EXT:
- get_renderbuffer_parameteriv(ctx, name, pname, params);
- break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glGetObjectParameteriv(name = 0x%x) invalid type: %d",
- name, objectType);
- }
-}
-
-/**
- * Binds a buffer object to a uniform buffer binding point.
- *
- * The caller is responsible for flushing vertices and updating
- * NewDriverState.
- */
-static void
-set_ubo_binding(struct gl_context *ctx,
- struct gl_uniform_buffer_binding *binding,
- struct gl_buffer_object *bufObj,
- GLintptr offset,
- GLsizeiptr size,
- GLboolean autoSize)
-{
- _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj);
-
- binding->Offset = offset;
- binding->Size = size;
- binding->AutomaticSize = autoSize;
-
- /* If this is a real buffer object, mark it has having been used
- * at some point as a UBO.
- */
- if (size >= 0)
- bufObj->UsageHistory |= USAGE_UNIFORM_BUFFER;
-}
-
-/**
- * Binds a buffer object to a shader storage buffer binding point.
- *
- * The caller is responsible for flushing vertices and updating
- * NewDriverState.
- */
-static void
-set_ssbo_binding(struct gl_context *ctx,
- struct gl_shader_storage_buffer_binding *binding,
- struct gl_buffer_object *bufObj,
- GLintptr offset,
- GLsizeiptr size,
- GLboolean autoSize)
-{
- _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj);
-
- binding->Offset = offset;
- binding->Size = size;
- binding->AutomaticSize = autoSize;
-
- /* If this is a real buffer object, mark it has having been used
- * at some point as a SSBO.
- */
- if (size >= 0)
- bufObj->UsageHistory |= USAGE_SHADER_STORAGE_BUFFER;
-}
-
-/**
- * Binds a buffer object to a uniform buffer binding point.
- *
- * Unlike set_ubo_binding(), this function also flushes vertices
- * and updates NewDriverState. It also checks if the binding
- * has actually changed before updating it.
- */
-static void
-bind_uniform_buffer(struct gl_context *ctx,
- GLuint index,
- struct gl_buffer_object *bufObj,
- GLintptr offset,
- GLsizeiptr size,
- GLboolean autoSize)
-{
- struct gl_uniform_buffer_binding *binding =
- &ctx->UniformBufferBindings[index];
-
- if (binding->BufferObject == bufObj &&
- binding->Offset == offset &&
- binding->Size == size &&
- binding->AutomaticSize == autoSize) {
- return;
- }
-
- FLUSH_VERTICES(ctx, 0);
- ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer;
-
- set_ubo_binding(ctx, binding, bufObj, offset, size, autoSize);
-}
-
-/**
- * Bind a region of a buffer object to a uniform block binding point.
- * \param index the uniform buffer binding point index
- * \param bufObj the buffer object
- * \param offset offset to the start of buffer object region
- * \param size size of the buffer object region
- */
-static void
-bind_buffer_range_uniform_buffer(struct gl_context *ctx,
- GLuint index,
- struct gl_buffer_object *bufObj,
- GLintptr offset,
- GLsizeiptr size)
-{
- if (index >= ctx->Const.MaxUniformBufferBindings) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferRange(index=%d)", index);
- return;
- }
-
- if (offset & (ctx->Const.UniformBufferOffsetAlignment - 1)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glBindBufferRange(offset misaligned %d/%d)", (int) offset,
- ctx->Const.UniformBufferOffsetAlignment);
- return;
+ "glBindBufferRange(offset misaligned %d/%d)", (int) offset,
+ ctx->Const.ShaderStorageBufferOffsetAlignment);
+ return;
}
if (bufObj == ctx->Shared->NullBufferObj) {
size = -1;
}
- _mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj);
- bind_uniform_buffer(ctx, index, bufObj, offset, size, GL_FALSE);
+ _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer, bufObj);
+ bind_shader_storage_buffer(ctx, index, bufObj, offset, size, GL_FALSE);
}
-
/**
* Bind a buffer object to a uniform block binding point.
* As above, but offset = 0.
bind_uniform_buffer(ctx, index, bufObj, 0, 0, GL_TRUE);
}
+/**
+ * Bind a buffer object to a shader storage block binding point.
+ * As above, but offset = 0.
+ */
+static void
+bind_buffer_base_shader_storage_buffer(struct gl_context *ctx,
+ GLuint index,
+ struct gl_buffer_object *bufObj)
+{
+ if (index >= ctx->Const.MaxShaderStorageBufferBindings) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glBindBufferBase(index=%d)", index);
+ return;
+ }
+
+ _mesa_reference_buffer_object(ctx, &ctx->ShaderStorageBuffer, bufObj);
+
+ if (bufObj == ctx->Shared->NullBufferObj)
+ bind_shader_storage_buffer(ctx, index, bufObj, -1, -1, GL_TRUE);
+ else
+ bind_shader_storage_buffer(ctx, index, bufObj, 0, 0, GL_TRUE);
+}
+
/**
* Binds a buffer object to an atomic buffer binding point.
*
_mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj);
if (bufObj == ctx->Shared->NullBufferObj) {
- binding->Offset = -1;
- binding->Size = -1;
+ binding->Offset = 0;
+ binding->Size = 0;
} else {
binding->Offset = offset;
binding->Size = size;
if (first + count > ctx->Const.MaxShaderStorageBufferBindings) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"%s(first=%u + count=%d > the value of "
- "GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS=%u)",
- caller, first, count,
- ctx->Const.MaxShaderStorageBufferBindings);
- return false;
- }
-
- return true;
-}
-
-/**
- * Unbind all uniform buffers in the range
- * <first> through <first>+<count>-1
- */
-static void
-unbind_uniform_buffers(struct gl_context *ctx, GLuint first, GLsizei count)
-{
- struct gl_buffer_object *bufObj = ctx->Shared->NullBufferObj;
- GLint i;
-
- for (i = 0; i < count; i++)
- set_ubo_binding(ctx, &ctx->UniformBufferBindings[first + i],
- bufObj, -1, -1, GL_TRUE);
-}
-
-/**
- * Unbind all shader storage buffers in the range
- * <first> through <first>+<count>-1
- */
-static void
-unbind_shader_storage_buffers(struct gl_context *ctx, GLuint first,
- GLsizei count)
-{
- struct gl_buffer_object *bufObj = ctx->Shared->NullBufferObj;
- GLint i;
-
- for (i = 0; i < count; i++)
- set_ssbo_binding(ctx, &ctx->ShaderStorageBufferBindings[first + i],
- bufObj, -1, -1, GL_TRUE);
-}
-
-static void
-bind_uniform_buffers_base(struct gl_context *ctx, GLuint first, GLsizei count,
- const GLuint *buffers)
-{
- GLint i;
-
- if (!error_check_bind_uniform_buffers(ctx, first, count, "glBindBuffersBase"))
- return;
-
- /* Assume that at least one binding will be changed */
- FLUSH_VERTICES(ctx, 0);
- ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer;
-
- if (!buffers) {
- /* The ARB_multi_bind spec says:
- *
- * "If <buffers> is NULL, all bindings from <first> through
- * <first>+<count>-1 are reset to their unbound (zero) state."
- */
- unbind_uniform_buffers(ctx, first, count);
- return;
- }
-
- /* Note that the error semantics for multi-bind commands differ from
- * those of other GL commands.
- *
- * The Issues section in the ARB_multi_bind spec says:
- *
- * "(11) Typically, OpenGL specifies that if an error is generated by a
- * command, that command has no effect. This is somewhat
- * unfortunate for multi-bind commands, because it would require a
- * first pass to scan the entire list of bound objects for errors
- * and then a second pass to actually perform the bindings.
- * Should we have different error semantics?
- *
- * RESOLVED: Yes. In this specification, when the parameters for
- * one of the <count> binding points are invalid, that binding point
- * is not updated and an error will be generated. However, other
- * binding points in the same command will be updated if their
- * parameters are valid and no other error occurs."
- */
-
- _mesa_begin_bufferobj_lookups(ctx);
-
- for (i = 0; i < count; i++) {
- struct gl_uniform_buffer_binding *binding =
- &ctx->UniformBufferBindings[first + i];
- struct gl_buffer_object *bufObj;
-
- if (binding->BufferObject && binding->BufferObject->Name == buffers[i])
- bufObj = binding->BufferObject;
- else
- bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
- "glBindBuffersBase");
-
- if (bufObj) {
- if (bufObj == ctx->Shared->NullBufferObj)
- set_ubo_binding(ctx, binding, bufObj, -1, -1, GL_TRUE);
- else
- set_ubo_binding(ctx, binding, bufObj, 0, 0, GL_TRUE);
- }
+ "GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS=%u)",
+ caller, first, count,
+ ctx->Const.MaxShaderStorageBufferBindings);
+ return false;
}
- _mesa_end_bufferobj_lookups(ctx);
+ return true;
}
+/**
+ * Unbind all uniform buffers in the range
+ * <first> through <first>+<count>-1
+ */
static void
-bind_shader_storage_buffers_base(struct gl_context *ctx, GLuint first,
- GLsizei count, const GLuint *buffers)
+unbind_uniform_buffers(struct gl_context *ctx, GLuint first, GLsizei count)
{
+ struct gl_buffer_object *bufObj = ctx->Shared->NullBufferObj;
GLint i;
- if (!error_check_bind_shader_storage_buffers(ctx, first, count,
- "glBindBuffersBase"))
- return;
-
- /* Assume that at least one binding will be changed */
- FLUSH_VERTICES(ctx, 0);
- ctx->NewDriverState |= ctx->DriverFlags.NewShaderStorageBuffer;
-
- if (!buffers) {
- /* The ARB_multi_bind spec says:
- *
- * "If <buffers> is NULL, all bindings from <first> through
- * <first>+<count>-1 are reset to their unbound (zero) state."
- */
- unbind_shader_storage_buffers(ctx, first, count);
- return;
- }
-
- /* Note that the error semantics for multi-bind commands differ from
- * those of other GL commands.
- *
- * The Issues section in the ARB_multi_bind spec says:
- *
- * "(11) Typically, OpenGL specifies that if an error is generated by a
- * command, that command has no effect. This is somewhat
- * unfortunate for multi-bind commands, because it would require a
- * first pass to scan the entire list of bound objects for errors
- * and then a second pass to actually perform the bindings.
- * Should we have different error semantics?
- *
- * RESOLVED: Yes. In this specification, when the parameters for
- * one of the <count> binding points are invalid, that binding point
- * is not updated and an error will be generated. However, other
- * binding points in the same command will be updated if their
- * parameters are valid and no other error occurs."
- */
-
- _mesa_begin_bufferobj_lookups(ctx);
-
- for (i = 0; i < count; i++) {
- struct gl_shader_storage_buffer_binding *binding =
- &ctx->ShaderStorageBufferBindings[first + i];
- struct gl_buffer_object *bufObj;
-
- if (binding->BufferObject && binding->BufferObject->Name == buffers[i])
- bufObj = binding->BufferObject;
- else
- bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
- "glBindBuffersBase");
+ for (i = 0; i < count; i++)
+ set_ubo_binding(ctx, &ctx->UniformBufferBindings[first + i],
+ bufObj, -1, -1, GL_TRUE);
+}
- if (bufObj) {
- if (bufObj == ctx->Shared->NullBufferObj)
- set_ssbo_binding(ctx, binding, bufObj, -1, -1, GL_TRUE);
- else
- set_ssbo_binding(ctx, binding, bufObj, 0, 0, GL_TRUE);
- }
- }
+/**
+ * Unbind all shader storage buffers in the range
+ * <first> through <first>+<count>-1
+ */
+static void
+unbind_shader_storage_buffers(struct gl_context *ctx, GLuint first,
+ GLsizei count)
+{
+ struct gl_buffer_object *bufObj = ctx->Shared->NullBufferObj;
+ GLint i;
- _mesa_end_bufferobj_lookups(ctx);
+ for (i = 0; i < count; i++)
+ set_ssbo_binding(ctx, &ctx->ShaderStorageBufferBindings[first + i],
+ bufObj, -1, -1, GL_TRUE);
}
static void
-bind_uniform_buffers_range(struct gl_context *ctx, GLuint first, GLsizei count,
- const GLuint *buffers,
- const GLintptr *offsets, const GLsizeiptr *sizes)
+bind_uniform_buffers(struct gl_context *ctx, GLuint first, GLsizei count,
+ const GLuint *buffers,
+ bool range,
+ const GLintptr *offsets, const GLsizeiptr *sizes,
+ const char *caller)
{
GLint i;
- if (!error_check_bind_uniform_buffers(ctx, first, count,
- "glBindBuffersRange"))
+ if (!error_check_bind_uniform_buffers(ctx, first, count, caller))
return;
/* Assume that at least one binding will be changed */
struct gl_uniform_buffer_binding *binding =
&ctx->UniformBufferBindings[first + i];
struct gl_buffer_object *bufObj;
+ GLintptr offset = 0;
+ GLsizeiptr size = 0;
- if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
- continue;
+ if (range) {
+ if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
+ continue;
- /* The ARB_multi_bind spec says:
- *
- * "An INVALID_VALUE error is generated by BindBuffersRange if any
- * pair of values in <offsets> and <sizes> does not respectively
- * satisfy the constraints described for those parameters for the
- * specified target, as described in section 6.7.1 (per binding)."
- *
- * Section 6.7.1 refers to table 6.5, which says:
- *
- * "┌───────────────────────────────────────────────────────────────┐
- * │ Uniform buffer array bindings (see sec. 7.6) │
- * ├─────────────────────┬─────────────────────────────────────────┤
- * │ ... │ ... │
- * │ offset restriction │ multiple of value of UNIFORM_BUFFER_- │
- * │ │ OFFSET_ALIGNMENT │
- * │ ... │ ... │
- * │ size restriction │ none │
- * └─────────────────────┴─────────────────────────────────────────┘"
- */
- if (offsets[i] & (ctx->Const.UniformBufferOffsetAlignment - 1)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glBindBuffersRange(offsets[%u]=%" PRId64
- " is misaligned; it must be a multiple of the value of "
- "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT=%u when "
- "target=GL_UNIFORM_BUFFER)",
- i, (int64_t) offsets[i],
- ctx->Const.UniformBufferOffsetAlignment);
- continue;
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_VALUE error is generated by BindBuffersRange if any
+ * pair of values in <offsets> and <sizes> does not respectively
+ * satisfy the constraints described for those parameters for the
+ * specified target, as described in section 6.7.1 (per binding)."
+ *
+ * Section 6.7.1 refers to table 6.5, which says:
+ *
+ * "┌───────────────────────────────────────────────────────────────┐
+ * │ Uniform buffer array bindings (see sec. 7.6) │
+ * ├─────────────────────┬─────────────────────────────────────────┤
+ * │ ... │ ... │
+ * │ offset restriction │ multiple of value of UNIFORM_BUFFER_- │
+ * │ │ OFFSET_ALIGNMENT │
+ * │ ... │ ... │
+ * │ size restriction │ none │
+ * └─────────────────────┴─────────────────────────────────────────┘"
+ */
+ if (offsets[i] & (ctx->Const.UniformBufferOffsetAlignment - 1)) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glBindBuffersRange(offsets[%u]=%" PRId64
+ " is misaligned; it must be a multiple of the value of "
+ "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT=%u when "
+ "target=GL_UNIFORM_BUFFER)",
+ i, (int64_t) offsets[i],
+ ctx->Const.UniformBufferOffsetAlignment);
+ continue;
+ }
+
+ offset = offsets[i];
+ size = sizes[i];
}
if (binding->BufferObject && binding->BufferObject->Name == buffers[i])
bufObj = binding->BufferObject;
else
- bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
- "glBindBuffersRange");
+ bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, caller);
if (bufObj) {
if (bufObj == ctx->Shared->NullBufferObj)
- set_ubo_binding(ctx, binding, bufObj, -1, -1, GL_FALSE);
+ set_ubo_binding(ctx, binding, bufObj, -1, -1, !range);
else
- set_ubo_binding(ctx, binding, bufObj,
- offsets[i], sizes[i], GL_FALSE);
+ set_ubo_binding(ctx, binding, bufObj, offset, size, !range);
}
}
}
static void
-bind_shader_storage_buffers_range(struct gl_context *ctx, GLuint first,
- GLsizei count, const GLuint *buffers,
- const GLintptr *offsets,
- const GLsizeiptr *sizes)
+bind_shader_storage_buffers(struct gl_context *ctx, GLuint first,
+ GLsizei count, const GLuint *buffers,
+ bool range,
+ const GLintptr *offsets,
+ const GLsizeiptr *sizes,
+ const char *caller)
{
GLint i;
- if (!error_check_bind_shader_storage_buffers(ctx, first, count,
- "glBindBuffersRange"))
+ if (!error_check_bind_shader_storage_buffers(ctx, first, count, caller))
return;
/* Assume that at least one binding will be changed */
struct gl_shader_storage_buffer_binding *binding =
&ctx->ShaderStorageBufferBindings[first + i];
struct gl_buffer_object *bufObj;
+ GLintptr offset = 0;
+ GLsizeiptr size = 0;
+
+ if (range) {
+ if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
+ continue;
+
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_VALUE error is generated by BindBuffersRange if any
+ * pair of values in <offsets> and <sizes> does not respectively
+ * satisfy the constraints described for those parameters for the
+ * specified target, as described in section 6.7.1 (per binding)."
+ *
+ * Section 6.7.1 refers to table 6.5, which says:
+ *
+ * "┌───────────────────────────────────────────────────────────────┐
+ * │ Shader storage buffer array bindings (see sec. 7.8) │
+ * ├─────────────────────┬─────────────────────────────────────────┤
+ * │ ... │ ... │
+ * │ offset restriction │ multiple of value of SHADER_STORAGE_- │
+ * │ │ BUFFER_OFFSET_ALIGNMENT │
+ * │ ... │ ... │
+ * │ size restriction │ none │
+ * └─────────────────────┴─────────────────────────────────────────┘"
+ */
+ if (offsets[i] & (ctx->Const.ShaderStorageBufferOffsetAlignment - 1)) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glBindBuffersRange(offsets[%u]=%" PRId64
+ " is misaligned; it must be a multiple of the value of "
+ "GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT=%u when "
+ "target=GL_SHADER_STORAGE_BUFFER)",
+ i, (int64_t) offsets[i],
+ ctx->Const.ShaderStorageBufferOffsetAlignment);
+ continue;
+ }
- if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
- continue;
-
- /* The ARB_multi_bind spec says:
- *
- * "An INVALID_VALUE error is generated by BindBuffersRange if any
- * pair of values in <offsets> and <sizes> does not respectively
- * satisfy the constraints described for those parameters for the
- * specified target, as described in section 6.7.1 (per binding)."
- *
- * Section 6.7.1 refers to table 6.5, which says:
- *
- * "┌───────────────────────────────────────────────────────────────┐
- * │ Shader storage buffer array bindings (see sec. 7.8) │
- * ├─────────────────────┬─────────────────────────────────────────┤
- * │ ... │ ... │
- * │ offset restriction │ multiple of value of SHADER_STORAGE_- │
- * │ │ BUFFER_OFFSET_ALIGNMENT │
- * │ ... │ ... │
- * │ size restriction │ none │
- * └─────────────────────┴─────────────────────────────────────────┘"
- */
- if (offsets[i] & (ctx->Const.ShaderStorageBufferOffsetAlignment - 1)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glBindBuffersRange(offsets[%u]=%" PRId64
- " is misaligned; it must be a multiple of the value of "
- "GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT=%u when "
- "target=GL_SHADER_STORAGE_BUFFER)",
- i, (int64_t) offsets[i],
- ctx->Const.ShaderStorageBufferOffsetAlignment);
- continue;
+ offset = offsets[i];
+ size = sizes[i];
}
if (binding->BufferObject && binding->BufferObject->Name == buffers[i])
bufObj = binding->BufferObject;
else
- bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
- "glBindBuffersRange");
+ bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, caller);
if (bufObj) {
if (bufObj == ctx->Shared->NullBufferObj)
- set_ssbo_binding(ctx, binding, bufObj, -1, -1, GL_FALSE);
+ set_ssbo_binding(ctx, binding, bufObj, -1, -1, !range);
else
- set_ssbo_binding(ctx, binding, bufObj,
- offsets[i], sizes[i], GL_FALSE);
+ set_ssbo_binding(ctx, binding, bufObj, offset, size, !range);
}
}
}
static void
-bind_xfb_buffers_base(struct gl_context *ctx,
- GLuint first, GLsizei count,
- const GLuint *buffers)
-{
- struct gl_transform_feedback_object *tfObj =
- ctx->TransformFeedback.CurrentObject;
- GLint i;
-
- if (!error_check_bind_xfb_buffers(ctx, tfObj, first, count,
- "glBindBuffersBase"))
- return;
-
- /* Assume that at least one binding will be changed */
- FLUSH_VERTICES(ctx, 0);
- ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
-
- if (!buffers) {
- /* The ARB_multi_bind spec says:
- *
- * "If <buffers> is NULL, all bindings from <first> through
- * <first>+<count>-1 are reset to their unbound (zero) state."
- */
- unbind_xfb_buffers(ctx, tfObj, first, count);
- return;
- }
-
- /* Note that the error semantics for multi-bind commands differ from
- * those of other GL commands.
- *
- * The Issues section in the ARB_multi_bind spec says:
- *
- * "(11) Typically, OpenGL specifies that if an error is generated by a
- * command, that command has no effect. This is somewhat
- * unfortunate for multi-bind commands, because it would require a
- * first pass to scan the entire list of bound objects for errors
- * and then a second pass to actually perform the bindings.
- * Should we have different error semantics?
- *
- * RESOLVED: Yes. In this specification, when the parameters for
- * one of the <count> binding points are invalid, that binding point
- * is not updated and an error will be generated. However, other
- * binding points in the same command will be updated if their
- * parameters are valid and no other error occurs."
- */
-
- _mesa_begin_bufferobj_lookups(ctx);
-
- for (i = 0; i < count; i++) {
- struct gl_buffer_object * const boundBufObj = tfObj->Buffers[first + i];
- struct gl_buffer_object *bufObj;
-
- if (boundBufObj && boundBufObj->Name == buffers[i])
- bufObj = boundBufObj;
- else
- bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
- "glBindBuffersBase");
-
- if (bufObj)
- _mesa_set_transform_feedback_binding(ctx, tfObj, first + i,
- bufObj, 0, 0);
- }
-
- _mesa_end_bufferobj_lookups(ctx);
-}
-
-static void
-bind_xfb_buffers_range(struct gl_context *ctx,
- GLuint first, GLsizei count,
- const GLuint *buffers,
- const GLintptr *offsets,
- const GLsizeiptr *sizes)
+bind_xfb_buffers(struct gl_context *ctx,
+ GLuint first, GLsizei count,
+ const GLuint *buffers,
+ bool range,
+ const GLintptr *offsets,
+ const GLsizeiptr *sizes,
+ const char *caller)
{
struct gl_transform_feedback_object *tfObj =
ctx->TransformFeedback.CurrentObject;
GLint i;
- if (!error_check_bind_xfb_buffers(ctx, tfObj, first, count,
- "glBindBuffersRange"))
+ if (!error_check_bind_xfb_buffers(ctx, tfObj, first, count, caller))
return;
/* Assume that at least one binding will be changed */
const GLuint index = first + i;
struct gl_buffer_object * const boundBufObj = tfObj->Buffers[index];
struct gl_buffer_object *bufObj;
+ GLintptr offset = 0;
+ GLsizeiptr size = 0;
- if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
- continue;
+ if (range) {
+ offset = offsets[i];
+ size = sizes[i];
- /* The ARB_multi_bind spec says:
- *
- * "An INVALID_VALUE error is generated by BindBuffersRange if any
- * pair of values in <offsets> and <sizes> does not respectively
- * satisfy the constraints described for those parameters for the
- * specified target, as described in section 6.7.1 (per binding)."
- *
- * Section 6.7.1 refers to table 6.5, which says:
- *
- * "┌───────────────────────────────────────────────────────────────┐
- * │ Transform feedback array bindings (see sec. 13.2.2) │
- * ├───────────────────────┬───────────────────────────────────────┤
- * │ ... │ ... │
- * │ offset restriction │ multiple of 4 │
- * │ ... │ ... │
- * │ size restriction │ multiple of 4 │
- * └───────────────────────┴───────────────────────────────────────┘"
- */
- if (offsets[i] & 0x3) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glBindBuffersRange(offsets[%u]=%" PRId64
- " is misaligned; it must be a multiple of 4 when "
- "target=GL_TRANSFORM_FEEDBACK_BUFFER)",
- i, (int64_t) offsets[i]);
- continue;
- }
+ if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
+ continue;
- if (sizes[i] & 0x3) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glBindBuffersRange(sizes[%u]=%" PRId64
- " is misaligned; it must be a multiple of 4 when "
- "target=GL_TRANSFORM_FEEDBACK_BUFFER)",
- i, (int64_t) sizes[i]);
- continue;
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_VALUE error is generated by BindBuffersRange if any
+ * pair of values in <offsets> and <sizes> does not respectively
+ * satisfy the constraints described for those parameters for the
+ * specified target, as described in section 6.7.1 (per binding)."
+ *
+ * Section 6.7.1 refers to table 6.5, which says:
+ *
+ * "┌───────────────────────────────────────────────────────────────┐
+ * │ Transform feedback array bindings (see sec. 13.2.2) │
+ * ├───────────────────────┬───────────────────────────────────────┤
+ * │ ... │ ... │
+ * │ offset restriction │ multiple of 4 │
+ * │ ... │ ... │
+ * │ size restriction │ multiple of 4 │
+ * └───────────────────────┴───────────────────────────────────────┘"
+ */
+ if (offsets[i] & 0x3) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glBindBuffersRange(offsets[%u]=%" PRId64
+ " is misaligned; it must be a multiple of 4 when "
+ "target=GL_TRANSFORM_FEEDBACK_BUFFER)",
+ i, (int64_t) offsets[i]);
+ continue;
+ }
+
+ if (sizes[i] & 0x3) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glBindBuffersRange(sizes[%u]=%" PRId64
+ " is misaligned; it must be a multiple of 4 when "
+ "target=GL_TRANSFORM_FEEDBACK_BUFFER)",
+ i, (int64_t) sizes[i]);
+ continue;
+ }
+
+ offset = offsets[i];
+ size = sizes[i];
}
if (boundBufObj && boundBufObj->Name == buffers[i])
bufObj = boundBufObj;
else
- bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
- "glBindBuffersRange");
+ bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, caller);
if (bufObj)
_mesa_set_transform_feedback_binding(ctx, tfObj, index, bufObj,
- offsets[i], sizes[i]);
+ offset, size);
}
_mesa_end_bufferobj_lookups(ctx);
}
static void
-bind_atomic_buffers_base(struct gl_context *ctx,
- GLuint first,
- GLsizei count,
- const GLuint *buffers)
-{
- GLint i;
-
- if (!error_check_bind_atomic_buffers(ctx, first, count,
- "glBindBuffersBase"))
- return;
-
- /* Assume that at least one binding will be changed */
- FLUSH_VERTICES(ctx, 0);
- ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer;
-
- if (!buffers) {
- /* The ARB_multi_bind spec says:
- *
- * "If <buffers> is NULL, all bindings from <first> through
- * <first>+<count>-1 are reset to their unbound (zero) state."
- */
- unbind_atomic_buffers(ctx, first, count);
- return;
- }
-
- /* Note that the error semantics for multi-bind commands differ from
- * those of other GL commands.
- *
- * The Issues section in the ARB_multi_bind spec says:
- *
- * "(11) Typically, OpenGL specifies that if an error is generated by a
- * command, that command has no effect. This is somewhat
- * unfortunate for multi-bind commands, because it would require a
- * first pass to scan the entire list of bound objects for errors
- * and then a second pass to actually perform the bindings.
- * Should we have different error semantics?
- *
- * RESOLVED: Yes. In this specification, when the parameters for
- * one of the <count> binding points are invalid, that binding point
- * is not updated and an error will be generated. However, other
- * binding points in the same command will be updated if their
- * parameters are valid and no other error occurs."
- */
-
- _mesa_begin_bufferobj_lookups(ctx);
-
- for (i = 0; i < count; i++) {
- struct gl_atomic_buffer_binding *binding =
- &ctx->AtomicBufferBindings[first + i];
- struct gl_buffer_object *bufObj;
-
- if (binding->BufferObject && binding->BufferObject->Name == buffers[i])
- bufObj = binding->BufferObject;
- else
- bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
- "glBindBuffersBase");
-
- if (bufObj)
- set_atomic_buffer_binding(ctx, binding, bufObj, 0, 0);
- }
-
- _mesa_end_bufferobj_lookups(ctx);
-}
-
-static void
-bind_atomic_buffers_range(struct gl_context *ctx,
- GLuint first,
- GLsizei count,
- const GLuint *buffers,
- const GLintptr *offsets,
- const GLsizeiptr *sizes)
+bind_atomic_buffers(struct gl_context *ctx,
+ GLuint first,
+ GLsizei count,
+ const GLuint *buffers,
+ bool range,
+ const GLintptr *offsets,
+ const GLsizeiptr *sizes,
+ const char *caller)
{
GLint i;
- if (!error_check_bind_atomic_buffers(ctx, first, count,
- "glBindBuffersRange"))
+ if (!error_check_bind_atomic_buffers(ctx, first, count, caller))
return;
/* Assume that at least one binding will be changed */
struct gl_atomic_buffer_binding *binding =
&ctx->AtomicBufferBindings[first + i];
struct gl_buffer_object *bufObj;
+ GLintptr offset = 0;
+ GLsizeiptr size = 0;
- if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
- continue;
+ if (range) {
+ if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
+ continue;
- /* The ARB_multi_bind spec says:
- *
- * "An INVALID_VALUE error is generated by BindBuffersRange if any
- * pair of values in <offsets> and <sizes> does not respectively
- * satisfy the constraints described for those parameters for the
- * specified target, as described in section 6.7.1 (per binding)."
- *
- * Section 6.7.1 refers to table 6.5, which says:
- *
- * "┌───────────────────────────────────────────────────────────────┐
- * │ Atomic counter array bindings (see sec. 7.7.2) │
- * ├───────────────────────┬───────────────────────────────────────┤
- * │ ... │ ... │
- * │ offset restriction │ multiple of 4 │
- * │ ... │ ... │
- * │ size restriction │ none │
- * └───────────────────────┴───────────────────────────────────────┘"
- */
- if (offsets[i] & (ATOMIC_COUNTER_SIZE - 1)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glBindBuffersRange(offsets[%u]=%" PRId64
- " is misaligned; it must be a multiple of %d when "
- "target=GL_ATOMIC_COUNTER_BUFFER)",
- i, (int64_t) offsets[i], ATOMIC_COUNTER_SIZE);
- continue;
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_VALUE error is generated by BindBuffersRange if any
+ * pair of values in <offsets> and <sizes> does not respectively
+ * satisfy the constraints described for those parameters for the
+ * specified target, as described in section 6.7.1 (per binding)."
+ *
+ * Section 6.7.1 refers to table 6.5, which says:
+ *
+ * "┌───────────────────────────────────────────────────────────────┐
+ * │ Atomic counter array bindings (see sec. 7.7.2) │
+ * ├───────────────────────┬───────────────────────────────────────┤
+ * │ ... │ ... │
+ * │ offset restriction │ multiple of 4 │
+ * │ ... │ ... │
+ * │ size restriction │ none │
+ * └───────────────────────┴───────────────────────────────────────┘"
+ */
+ if (offsets[i] & (ATOMIC_COUNTER_SIZE - 1)) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glBindBuffersRange(offsets[%u]=%" PRId64
+ " is misaligned; it must be a multiple of %d when "
+ "target=GL_ATOMIC_COUNTER_BUFFER)",
+ i, (int64_t) offsets[i], ATOMIC_COUNTER_SIZE);
+ continue;
+ }
+
+ offset = offsets[i];
+ size = sizes[i];
}
if (binding->BufferObject && binding->BufferObject->Name == buffers[i])
bufObj = binding->BufferObject;
else
- bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
- "glBindBuffersRange");
+ bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, caller);
if (bufObj)
- set_atomic_buffer_binding(ctx, binding, bufObj, offsets[i], sizes[i]);
+ set_atomic_buffer_binding(ctx, binding, bufObj, offset, size);
}
_mesa_end_bufferobj_lookups(ctx);
GET_CURRENT_CONTEXT(ctx);
struct gl_buffer_object *bufObj;
+ if (MESA_VERBOSE & VERBOSE_API) {
+ _mesa_debug(ctx, "glBindBufferRange(%s, %u, %u, %lu, %lu)\n",
+ _mesa_enum_to_string(target), index, buffer,
+ (unsigned long) offset, (unsigned long) size);
+ }
+
if (buffer == 0) {
bufObj = ctx->Shared->NullBufferObj;
} else {
bufObj = _mesa_lookup_bufferobj(ctx, buffer);
}
- if (!_mesa_handle_bind_buffer_gen(ctx, target, buffer,
+ if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
&bufObj, "glBindBufferRange"))
return;
case GL_UNIFORM_BUFFER:
bind_buffer_range_uniform_buffer(ctx, index, bufObj, offset, size);
return;
+ case GL_SHADER_STORAGE_BUFFER:
+ bind_buffer_range_shader_storage_buffer(ctx, index, bufObj, offset, size);
+ return;
case GL_ATOMIC_COUNTER_BUFFER:
bind_atomic_buffer(ctx, index, bufObj, offset, size,
"glBindBufferRange");
GET_CURRENT_CONTEXT(ctx);
struct gl_buffer_object *bufObj;
+ if (MESA_VERBOSE & VERBOSE_API) {
+ _mesa_debug(ctx, "glBindBufferBase(%s, %u, %u)\n",
+ _mesa_enum_to_string(target), index, buffer);
+ }
+
if (buffer == 0) {
bufObj = ctx->Shared->NullBufferObj;
} else {
bufObj = _mesa_lookup_bufferobj(ctx, buffer);
}
- if (!_mesa_handle_bind_buffer_gen(ctx, target, buffer,
+ if (!_mesa_handle_bind_buffer_gen(ctx, buffer,
&bufObj, "glBindBufferBase"))
return;
case GL_UNIFORM_BUFFER:
bind_buffer_base_uniform_buffer(ctx, index, bufObj);
return;
+ case GL_SHADER_STORAGE_BUFFER:
+ bind_buffer_base_shader_storage_buffer(ctx, index, bufObj);
+ return;
case GL_ATOMIC_COUNTER_BUFFER:
bind_atomic_buffer(ctx, index, bufObj, 0, 0,
"glBindBufferBase");
{
GET_CURRENT_CONTEXT(ctx);
+ if (MESA_VERBOSE & VERBOSE_API) {
+ _mesa_debug(ctx, "glBindBuffersRange(%s, %u, %d, %p, %p, %p)\n",
+ _mesa_enum_to_string(target), first, count,
+ buffers, offsets, sizes);
+ }
+
switch (target) {
case GL_TRANSFORM_FEEDBACK_BUFFER:
- bind_xfb_buffers_range(ctx, first, count, buffers, offsets, sizes);
+ bind_xfb_buffers(ctx, first, count, buffers, true, offsets, sizes,
+ "glBindBuffersRange");
return;
case GL_UNIFORM_BUFFER:
- bind_uniform_buffers_range(ctx, first, count, buffers, offsets, sizes);
+ bind_uniform_buffers(ctx, first, count, buffers, true, offsets, sizes,
+ "glBindBuffersRange");
return;
case GL_SHADER_STORAGE_BUFFER:
- bind_shader_storage_buffers_range(ctx, first, count, buffers, offsets,
- sizes);
+ bind_shader_storage_buffers(ctx, first, count, buffers, true, offsets, sizes,
+ "glBindBuffersRange");
return;
case GL_ATOMIC_COUNTER_BUFFER:
- bind_atomic_buffers_range(ctx, first, count, buffers,
- offsets, sizes);
+ bind_atomic_buffers(ctx, first, count, buffers, true, offsets, sizes,
+ "glBindBuffersRange");
return;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glBindBuffersRange(target=%s)",
- _mesa_lookup_enum_by_nr(target));
+ _mesa_enum_to_string(target));
break;
}
}
{
GET_CURRENT_CONTEXT(ctx);
+ if (MESA_VERBOSE & VERBOSE_API) {
+ _mesa_debug(ctx, "glBindBuffersBase(%s, %u, %d, %p)\n",
+ _mesa_enum_to_string(target), first, count, buffers);
+ }
+
switch (target) {
case GL_TRANSFORM_FEEDBACK_BUFFER:
- bind_xfb_buffers_base(ctx, first, count, buffers);
+ bind_xfb_buffers(ctx, first, count, buffers, false, NULL, NULL,
+ "glBindBuffersBase");
return;
case GL_UNIFORM_BUFFER:
- bind_uniform_buffers_base(ctx, first, count, buffers);
+ bind_uniform_buffers(ctx, first, count, buffers, false, NULL, NULL,
+ "glBindBuffersBase");
return;
case GL_SHADER_STORAGE_BUFFER:
- bind_shader_storage_buffers_base(ctx, first, count, buffers);
+ bind_shader_storage_buffers(ctx, first, count, buffers, false, NULL, NULL,
+ "glBindBuffersBase");
return;
case GL_ATOMIC_COUNTER_BUFFER:
- bind_atomic_buffers_base(ctx, first, count, buffers);
+ bind_atomic_buffers(ctx, first, count, buffers, false, NULL, NULL,
+ "glBindBuffersBase");
return;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glBindBuffersBase(target=%s)",
- _mesa_lookup_enum_by_nr(target));
+ _mesa_enum_to_string(target));
break;
}
}
struct gl_buffer_object *bufObj;
const GLintptr end = offset + length;
+ /* Section 6.5 (Invalidating Buffer Data) of the OpenGL 4.5 (Compatibility
+ * Profile) spec says:
+ *
+ * "An INVALID_VALUE error is generated if buffer is zero or is not the
+ * name of an existing buffer object."
+ */
bufObj = _mesa_lookup_bufferobj(ctx, buffer);
- if (!bufObj) {
+ if (!bufObj || bufObj == &DummyBufferObject) {
_mesa_error(ctx, GL_INVALID_VALUE,
- "glInvalidateBufferSubData(name = 0x%x) invalid object",
+ "glInvalidateBufferSubData(name = %u) invalid object",
buffer);
return;
}
* negative, or if <offset> + <length> is greater than the value of
* BUFFER_SIZE."
*/
- if (end < 0 || end > bufObj->Size) {
+ if (offset < 0 || length < 0 || end > bufObj->Size) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glInvalidateBufferSubData(invalid offset or length)");
return;
return;
}
- /* We don't actually do anything for this yet. Just return after
- * validating the parameters and generating the required errors.
- */
- return;
+ if (ctx->Driver.InvalidateBufferSubData)
+ ctx->Driver.InvalidateBufferSubData(ctx, bufObj, offset, length);
}
void GLAPIENTRY
GET_CURRENT_CONTEXT(ctx);
struct gl_buffer_object *bufObj;
+ /* Section 6.5 (Invalidating Buffer Data) of the OpenGL 4.5 (Compatibility
+ * Profile) spec says:
+ *
+ * "An INVALID_VALUE error is generated if buffer is zero or is not the
+ * name of an existing buffer object."
+ */
bufObj = _mesa_lookup_bufferobj(ctx, buffer);
- if (!bufObj) {
+ if (!bufObj || bufObj == &DummyBufferObject) {
_mesa_error(ctx, GL_INVALID_VALUE,
- "glInvalidateBufferData(name = 0x%x) invalid object",
+ "glInvalidateBufferData(name = %u) invalid object",
buffer);
return;
}
return;
}
- /* We don't actually do anything for this yet. Just return after
- * validating the parameters and generating the required errors.
- */
- return;
+ if (ctx->Driver.InvalidateBufferSubData)
+ ctx->Driver.InvalidateBufferSubData(ctx, bufObj, 0, bufObj->Size);
}