aboutsummaryrefslogtreecommitdiffstats
path: root/src/mesa/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/main')
-rw-r--r--src/mesa/main/glthread.h39
-rw-r--r--src/mesa/main/glthread_draw.c114
-rw-r--r--src/mesa/main/glthread_marshal.h8
-rw-r--r--src/mesa/main/glthread_varray.c268
4 files changed, 403 insertions, 26 deletions
diff --git a/src/mesa/main/glthread.h b/src/mesa/main/glthread.h
index 34a5443a6da..b07169e334c 100644
--- a/src/mesa/main/glthread.h
+++ b/src/mesa/main/glthread.h
@@ -66,15 +66,23 @@ struct glthread_attrib_binding {
struct glthread_vao {
GLuint Name;
GLuint CurrentElementBufferName;
- GLbitfield UserEnabled; /**< Vertex attrib arrays enabled by the user. */
+ GLbitfield UserEnabled; /**< Vertex attribs enabled by the user. */
GLbitfield Enabled; /**< UserEnabled with POS vs GENERIC0 aliasing resolved. */
- GLbitfield UserPointerMask;
- GLbitfield NonZeroDivisorMask;
+ GLbitfield BufferEnabled; /**< "Enabled" converted to buffer bindings. */
+ GLbitfield BufferInterleaved; /**< Bitmask of buffers used by multiple attribs. */
+ GLbitfield UserPointerMask; /**< Bitmask of buffer bindings. */
+ GLbitfield NonZeroDivisorMask; /**< Bitmask of buffer bindings. */
struct {
+ /* Per attrib: */
GLuint ElementSize;
+ GLuint RelativeOffset;
+ GLuint BufferIndex; /**< Referring to Attrib[BufferIndex]. */
+
+ /* Per buffer binding: */
GLsizei Stride;
GLuint Divisor;
+ int EnabledAttribCount; /**< Number of enabled attribs using this buffer. */
const void *Pointer;
} Attrib[VERT_ATTRIB_MAX];
};
@@ -207,6 +215,31 @@ void _mesa_glthread_DSAAttribPointer(struct gl_context *ctx, GLuint vao,
GLuint buffer, gl_vert_attrib attrib,
GLint size, GLenum type, GLsizei stride,
GLintptr offset);
+void _mesa_glthread_AttribFormat(struct gl_context *ctx, GLuint attribindex,
+ GLint size, GLenum type, GLuint relativeoffset);
+void _mesa_glthread_DSAAttribFormat(struct gl_context *ctx, GLuint vaobj,
+ GLuint attribindex, GLint size, GLenum type,
+ GLuint relativeoffset);
+void _mesa_glthread_VertexBuffer(struct gl_context *ctx, GLuint bindingindex,
+ GLuint buffer, GLintptr offset, GLsizei stride);
+void _mesa_glthread_DSAVertexBuffer(struct gl_context *ctx, GLuint vaobj,
+ GLuint bindingindex, GLuint buffer,
+ GLintptr offset, GLsizei stride);
+void _mesa_glthread_DSAVertexBuffers(struct gl_context *ctx, GLuint vaobj,
+ GLuint first, GLsizei count,
+ const GLuint *buffers,
+ const GLintptr *offsets,
+ const GLsizei *strides);
+void _mesa_glthread_BindingDivisor(struct gl_context *ctx, GLuint bindingindex,
+ GLuint divisor);
+void _mesa_glthread_DSABindingDivisor(struct gl_context *ctx, GLuint vaobj,
+ GLuint bindingindex, GLuint divisor);
+void _mesa_glthread_AttribBinding(struct gl_context *ctx, GLuint attribindex,
+ GLuint bindingindex);
+void _mesa_glthread_DSAAttribBinding(struct gl_context *ctx, GLuint vaobj,
+ GLuint attribindex, GLuint bindingindex);
+void _mesa_glthread_DSAElementBuffer(struct gl_context *ctx, GLuint vaobj,
+ GLuint buffer);
void _mesa_glthread_PushClientAttrib(struct gl_context *ctx, GLbitfield mask,
bool set_default);
void _mesa_glthread_PopClientAttrib(struct gl_context *ctx);
diff --git a/src/mesa/main/glthread_draw.c b/src/mesa/main/glthread_draw.c
index ed27cb14bff..1fd6828e1f6 100644
--- a/src/mesa/main/glthread_draw.c
+++ b/src/mesa/main/glthread_draw.c
@@ -113,20 +113,111 @@ upload_vertices(struct gl_context *ctx, unsigned user_buffer_mask,
struct glthread_attrib_binding *buffers)
{
struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
- unsigned attrib_mask_iter = user_buffer_mask;
+ unsigned attrib_mask_iter = vao->Enabled;
unsigned num_buffers = 0;
assert((num_vertices || !(user_buffer_mask & ~vao->NonZeroDivisorMask)) &&
(num_instances || !(user_buffer_mask & vao->NonZeroDivisorMask)));
+ if (unlikely(vao->BufferInterleaved & user_buffer_mask)) {
+ /* Slower upload path where some buffers reference multiple attribs,
+ * so we have to use 2 while loops instead of 1.
+ */
+ unsigned start_offset[VERT_ATTRIB_MAX];
+ unsigned end_offset[VERT_ATTRIB_MAX];
+ uint32_t buffer_mask = 0;
+
+ while (attrib_mask_iter) {
+ unsigned i = u_bit_scan(&attrib_mask_iter);
+ unsigned binding_index = vao->Attrib[i].BufferIndex;
+
+ if (!(user_buffer_mask & (1 << binding_index)))
+ continue;
+
+ unsigned stride = vao->Attrib[binding_index].Stride;
+ unsigned instance_div = vao->Attrib[binding_index].Divisor;
+ unsigned element_size = vao->Attrib[i].ElementSize;
+ unsigned offset = vao->Attrib[i].RelativeOffset;
+ unsigned size;
+
+ if (instance_div) {
+ /* Per-instance attrib. */
+
+ /* Figure out how many instances we'll render given instance_div. We
+ * can't use the typical div_round_up() pattern because the CTS uses
+ * instance_div = ~0 for a test, which overflows div_round_up()'s
+ * addition.
+ */
+ unsigned count = num_instances / instance_div;
+ if (count * instance_div != num_instances)
+ count++;
+
+ offset += stride * start_instance;
+ size = stride * (count - 1) + element_size;
+ } else {
+ /* Per-vertex attrib. */
+ offset += stride * start_vertex;
+ size = stride * (num_vertices - 1) + element_size;
+ }
+
+ unsigned binding_index_bit = 1u << binding_index;
+
+ /* Update upload offsets. */
+ if (!(buffer_mask & binding_index_bit)) {
+ start_offset[binding_index] = offset;
+ end_offset[binding_index] = offset + size;
+ } else {
+ if (offset < start_offset[binding_index])
+ start_offset[binding_index] = offset;
+ if (offset + size > end_offset[binding_index])
+ end_offset[binding_index] = offset + size;
+ }
+
+ buffer_mask |= binding_index_bit;
+ }
+
+ /* Upload buffers. */
+ while (buffer_mask) {
+ struct gl_buffer_object *upload_buffer = NULL;
+ unsigned upload_offset = 0;
+ unsigned start, end;
+
+ unsigned binding_index = u_bit_scan(&buffer_mask);
+
+ start = start_offset[binding_index];
+ end = end_offset[binding_index];
+ assert(start < end);
+
+ const void *ptr = vao->Attrib[binding_index].Pointer;
+ _mesa_glthread_upload(ctx, (uint8_t*)ptr + start,
+ end - start, &upload_offset,
+ &upload_buffer, NULL);
+ assert(upload_buffer);
+
+ buffers[num_buffers].buffer = upload_buffer;
+ buffers[num_buffers].offset = upload_offset - start;
+ buffers[num_buffers].original_pointer = ptr;
+ num_buffers++;
+ }
+
+ return true;
+ }
+
+ /* Faster path where all attribs are separate. */
while (attrib_mask_iter) {
unsigned i = u_bit_scan(&attrib_mask_iter);
+ unsigned binding_index = vao->Attrib[i].BufferIndex;
+
+ if (!(user_buffer_mask & (1 << binding_index)))
+ continue;
+
struct gl_buffer_object *upload_buffer = NULL;
unsigned upload_offset = 0;
- unsigned stride = vao->Attrib[i].Stride;
- unsigned instance_div = vao->Attrib[i].Divisor;
+ unsigned stride = vao->Attrib[binding_index].Stride;
+ unsigned instance_div = vao->Attrib[binding_index].Divisor;
unsigned element_size = vao->Attrib[i].ElementSize;
- unsigned offset, size;
+ unsigned offset = vao->Attrib[i].RelativeOffset;
+ unsigned size;
if (instance_div) {
/* Per-instance attrib. */
@@ -140,15 +231,15 @@ upload_vertices(struct gl_context *ctx, unsigned user_buffer_mask,
if (count * instance_div != num_instances)
count++;
- offset = stride * start_instance;
+ offset += stride * start_instance;
size = stride * (count - 1) + element_size;
} else {
/* Per-vertex attrib. */
- offset = stride * start_vertex;
+ offset += stride * start_vertex;
size = stride * (num_vertices - 1) + element_size;
}
- const void *ptr = vao->Attrib[i].Pointer;
+ const void *ptr = vao->Attrib[binding_index].Pointer;
_mesa_glthread_upload(ctx, (uint8_t*)ptr + offset,
size, &upload_offset, &upload_buffer, NULL);
assert(upload_buffer);
@@ -158,6 +249,7 @@ upload_vertices(struct gl_context *ctx, unsigned user_buffer_mask,
buffers[num_buffers].original_pointer = ptr;
num_buffers++;
}
+
return true;
}
@@ -233,7 +325,7 @@ draw_arrays(GLenum mode, GLint first, GLsizei count, GLsizei instance_count,
GET_CURRENT_CONTEXT(ctx);
struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
- unsigned user_buffer_mask = vao->UserPointerMask & vao->Enabled;
+ unsigned user_buffer_mask = vao->UserPointerMask & vao->BufferEnabled;
if (compiled_into_dlist && ctx->GLThread.inside_dlist) {
_mesa_glthread_finish_before(ctx, "DrawArrays");
@@ -347,7 +439,7 @@ _mesa_marshal_MultiDrawArrays(GLenum mode, const GLint *first,
GET_CURRENT_CONTEXT(ctx);
struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
- unsigned user_buffer_mask = vao->UserPointerMask & vao->Enabled;
+ unsigned user_buffer_mask = vao->UserPointerMask & vao->BufferEnabled;
if (ctx->GLThread.inside_dlist)
goto sync;
@@ -511,7 +603,7 @@ draw_elements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
GET_CURRENT_CONTEXT(ctx);
struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
- unsigned user_buffer_mask = vao->UserPointerMask & vao->Enabled;
+ unsigned user_buffer_mask = vao->UserPointerMask & vao->BufferEnabled;
bool has_user_indices = vao->CurrentElementBufferName == 0;
if (compiled_into_dlist && ctx->GLThread.inside_dlist)
@@ -724,7 +816,7 @@ _mesa_marshal_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
GET_CURRENT_CONTEXT(ctx);
struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
- unsigned user_buffer_mask = vao->UserPointerMask & vao->Enabled;
+ unsigned user_buffer_mask = vao->UserPointerMask & vao->BufferEnabled;
bool has_user_indices = vao->CurrentElementBufferName == 0;
if (ctx->GLThread.inside_dlist)
diff --git a/src/mesa/main/glthread_marshal.h b/src/mesa/main/glthread_marshal.h
index c8cf733f9ce..5acc36716d9 100644
--- a/src/mesa/main/glthread_marshal.h
+++ b/src/mesa/main/glthread_marshal.h
@@ -85,7 +85,7 @@ _mesa_glthread_has_non_vbo_vertices_or_indices(const struct gl_context *ctx)
return ctx->API != API_OPENGL_CORE &&
(vao->CurrentElementBufferName == 0 ||
- (vao->UserPointerMask & vao->Enabled));
+ (vao->UserPointerMask & vao->BufferEnabled));
}
static inline bool
@@ -95,7 +95,7 @@ _mesa_glthread_has_non_vbo_vertices(const struct gl_context *ctx)
const struct glthread_vao *vao = glthread->CurrentVAO;
return ctx->API != API_OPENGL_CORE &&
- (vao->UserPointerMask & vao->Enabled);
+ (vao->UserPointerMask & vao->BufferEnabled);
}
static inline bool
@@ -106,7 +106,7 @@ _mesa_glthread_has_non_vbo_vertices_or_indirect(const struct gl_context *ctx)
return ctx->API != API_OPENGL_CORE &&
(glthread->CurrentDrawIndirectBufferName == 0 ||
- (vao->UserPointerMask & vao->Enabled));
+ (vao->UserPointerMask & vao->BufferEnabled));
}
static inline bool
@@ -118,7 +118,7 @@ _mesa_glthread_has_non_vbo_vertices_or_indices_or_indirect(const struct gl_conte
return ctx->API != API_OPENGL_CORE &&
(glthread->CurrentDrawIndirectBufferName == 0 ||
vao->CurrentElementBufferName == 0 ||
- (vao->UserPointerMask & vao->Enabled));
+ (vao->UserPointerMask & vao->BufferEnabled));
}
diff --git a/src/mesa/main/glthread_varray.c b/src/mesa/main/glthread_varray.c
index 8fae4af3123..664e4644351 100644
--- a/src/mesa/main/glthread_varray.c
+++ b/src/mesa/main/glthread_varray.c
@@ -33,9 +33,6 @@
#include "main/dispatch.h"
#include "main/varray.h"
-/* TODO:
- * - Handle ARB_vertex_attrib_binding (incl. EXT_dsa and ARB_dsa)
- */
void
_mesa_glthread_reset_vao(struct glthread_vao *vao)
@@ -52,6 +49,7 @@ _mesa_glthread_reset_vao(struct glthread_vao *vao)
vao->CurrentElementBufferName = 0;
vao->UserEnabled = 0;
vao->Enabled = 0;
+ vao->BufferEnabled = 0;
vao->UserPointerMask = 0;
vao->NonZeroDivisorMask = 0;
@@ -61,8 +59,11 @@ _mesa_glthread_reset_vao(struct glthread_vao *vao)
elem_size = 16;
vao->Attrib[i].ElementSize = elem_size;
+ vao->Attrib[i].RelativeOffset = 0;
+ vao->Attrib[i].BufferIndex = i;
vao->Attrib[i].Stride = elem_size;
vao->Attrib[i].Divisor = 0;
+ vao->Attrib[i].EnabledAttribCount = 0;
vao->Attrib[i].Pointer = NULL;
}
}
@@ -212,6 +213,30 @@ _mesa_glthread_PrimitiveRestartIndex(struct gl_context *ctx, GLuint index)
update_primitive_restart(ctx);
}
+static inline void
+enable_buffer(struct glthread_vao *vao, unsigned binding_index)
+{
+ int attrib_count = ++vao->Attrib[binding_index].EnabledAttribCount;
+
+ if (attrib_count == 1)
+ vao->BufferEnabled |= 1 << binding_index;
+ else if (attrib_count == 2)
+ vao->BufferInterleaved |= 1 << binding_index;
+}
+
+static inline void
+disable_buffer(struct glthread_vao *vao, unsigned binding_index)
+{
+ int attrib_count = --vao->Attrib[binding_index].EnabledAttribCount;
+
+ if (attrib_count == 0)
+ vao->BufferEnabled &= ~(1 << binding_index);
+ else if (attrib_count == 1)
+ vao->BufferInterleaved &= ~(1 << binding_index);
+ else
+ assert(attrib_count >= 0);
+}
+
void
_mesa_glthread_ClientState(struct gl_context *ctx, GLuint *vaobj,
gl_vert_attrib attrib, bool enable)
@@ -230,17 +255,63 @@ _mesa_glthread_ClientState(struct gl_context *ctx, GLuint *vaobj,
if (!vao)
return;
- if (enable)
- vao->UserEnabled |= 1u << attrib;
- else
- vao->UserEnabled &= ~(1u << attrib);
+ const unsigned attrib_bit = 1u << attrib;
+
+ if (enable && !(vao->UserEnabled & attrib_bit)) {
+ vao->UserEnabled |= attrib_bit;
+
+ /* The generic0 attribute supersedes the position attribute. We need to
+ * update BufferBindingEnabled accordingly.
+ */
+ if (attrib == VERT_ATTRIB_POS) {
+ if (!(vao->UserEnabled & VERT_BIT_GENERIC0))
+ enable_buffer(vao, vao->Attrib[VERT_ATTRIB_POS].BufferIndex);
+ } else {
+ enable_buffer(vao, vao->Attrib[attrib].BufferIndex);
+
+ if (attrib == VERT_ATTRIB_GENERIC0 && vao->UserEnabled & VERT_BIT_POS)
+ disable_buffer(vao, vao->Attrib[VERT_ATTRIB_POS].BufferIndex);
+ }
+ } else if (!enable && (vao->UserEnabled & attrib_bit)) {
+ vao->UserEnabled &= ~attrib_bit;
+
+ /* The generic0 attribute supersedes the position attribute. We need to
+ * update BufferBindingEnabled accordingly.
+ */
+ if (attrib == VERT_ATTRIB_POS) {
+ if (!(vao->UserEnabled & VERT_BIT_GENERIC0))
+ disable_buffer(vao, vao->Attrib[VERT_ATTRIB_POS].BufferIndex);
+ } else {
+ disable_buffer(vao, vao->Attrib[attrib].BufferIndex);
+
+ if (attrib == VERT_ATTRIB_GENERIC0 && vao->UserEnabled & VERT_BIT_POS)
+ enable_buffer(vao, vao->Attrib[VERT_ATTRIB_POS].BufferIndex);
+ }
+ }
- /* The generic0 attribute superseeds the position attribute */
+ /* The generic0 attribute supersedes the position attribute. */
vao->Enabled = vao->UserEnabled;
if (vao->Enabled & VERT_BIT_GENERIC0)
vao->Enabled &= ~VERT_BIT_POS;
}
+static void
+set_attrib_binding(struct glthread_state *glthread, struct glthread_vao *vao,
+ gl_vert_attrib attrib, unsigned new_binding_index)
+{
+ unsigned old_binding_index = vao->Attrib[attrib].BufferIndex;
+
+ if (old_binding_index != new_binding_index) {
+ vao->Attrib[attrib].BufferIndex = new_binding_index;
+
+ if (vao->Enabled & (1u << attrib)) {
+ /* Update BufferBindingEnabled. */
+ enable_buffer(vao, new_binding_index);
+ disable_buffer(vao, old_binding_index);
+ }
+ }
+}
+
void _mesa_glthread_AttribDivisor(struct gl_context *ctx, const GLuint *vaobj,
gl_vert_attrib attrib, GLuint divisor)
{
@@ -253,6 +324,8 @@ void _mesa_glthread_AttribDivisor(struct gl_context *ctx, const GLuint *vaobj,
vao->Attrib[attrib].Divisor = divisor;
+ set_attrib_binding(&ctx->GLThread, vao, attrib, attrib);
+
if (divisor)
vao->NonZeroDivisorMask |= 1u << attrib;
else
@@ -273,6 +346,9 @@ attrib_pointer(struct glthread_state *glthread, struct glthread_vao *vao,
vao->Attrib[attrib].ElementSize = elem_size;
vao->Attrib[attrib].Stride = stride ? stride : elem_size;
vao->Attrib[attrib].Pointer = pointer;
+ vao->Attrib[attrib].RelativeOffset = 0;
+
+ set_attrib_binding(glthread, vao, attrib, attrib);
if (buffer != 0)
vao->UserPointerMask &= ~(1u << attrib);
@@ -309,6 +385,182 @@ _mesa_glthread_DSAAttribPointer(struct gl_context *ctx, GLuint vaobj,
(const void*)offset);
}
+static void
+attrib_format(struct glthread_state *glthread, struct glthread_vao *vao,
+ GLuint attribindex, GLint size, GLenum type,
+ GLuint relativeoffset)
+{
+ if (attribindex >= VERT_ATTRIB_GENERIC_MAX)
+ return;
+
+ unsigned elem_size = _mesa_bytes_per_vertex_attrib(size, type);
+
+ unsigned i = VERT_ATTRIB_GENERIC(attribindex);
+ vao->Attrib[i].ElementSize = elem_size;
+ vao->Attrib[i].RelativeOffset = relativeoffset;
+}
+
+void
+_mesa_glthread_AttribFormat(struct gl_context *ctx, GLuint attribindex,
+ GLint size, GLenum type, GLuint relativeoffset)
+{
+ struct glthread_state *glthread = &ctx->GLThread;
+
+ attrib_format(glthread, glthread->CurrentVAO, attribindex, size, type,
+ relativeoffset);
+}
+
+void
+_mesa_glthread_DSAAttribFormat(struct gl_context *ctx, GLuint vaobj,
+ GLuint attribindex, GLint size, GLenum type,
+ GLuint relativeoffset)
+{
+ struct glthread_state *glthread = &ctx->GLThread;
+ struct glthread_vao *vao = lookup_vao(ctx, vaobj);
+
+ if (vao)
+ attrib_format(glthread, vao, attribindex, size, type, relativeoffset);
+}
+
+static void
+bind_vertex_buffer(struct glthread_state *glthread, struct glthread_vao *vao,
+ GLuint bindingindex, GLuint buffer, GLintptr offset,
+ GLsizei stride)
+{
+ if (bindingindex >= VERT_ATTRIB_GENERIC_MAX)
+ return;
+
+ unsigned i = VERT_ATTRIB_GENERIC(bindingindex);
+ vao->Attrib[i].Pointer = (const void*)offset;
+ vao->Attrib[i].Stride = stride;
+
+ if (buffer != 0)
+ vao->UserPointerMask &= ~(1u << i);
+ else
+ vao->UserPointerMask |= 1u << i;
+}
+
+void
+_mesa_glthread_VertexBuffer(struct gl_context *ctx, GLuint bindingindex,
+ GLuint buffer, GLintptr offset, GLsizei stride)
+{
+ struct glthread_state *glthread = &ctx->GLThread;
+
+ bind_vertex_buffer(glthread, glthread->CurrentVAO, bindingindex, buffer,
+ offset, stride);
+}
+
+void
+_mesa_glthread_DSAVertexBuffer(struct gl_context *ctx, GLuint vaobj,
+ GLuint bindingindex, GLuint buffer,
+ GLintptr offset, GLsizei stride)
+{
+ struct glthread_state *glthread = &ctx->GLThread;
+ struct glthread_vao *vao = lookup_vao(ctx, vaobj);
+
+ if (vao)
+ bind_vertex_buffer(glthread, vao, bindingindex, buffer, offset, stride);
+}
+
+void
+_mesa_glthread_DSAVertexBuffers(struct gl_context *ctx, GLuint vaobj,
+ GLuint first, GLsizei count,
+ const GLuint *buffers,
+ const GLintptr *offsets,
+ const GLsizei *strides)
+{
+ struct glthread_state *glthread = &ctx->GLThread;
+ struct glthread_vao *vao;
+
+ vao = lookup_vao(ctx, vaobj);
+ if (!vao)
+ return;
+
+ for (unsigned i = 0; i < count; i++) {
+ bind_vertex_buffer(glthread, vao, first + i, buffers[i], offsets[i],
+ strides[i]);
+ }
+}
+
+static void
+binding_divisor(struct glthread_state *glthread, struct glthread_vao *vao,
+ GLuint bindingindex, GLuint divisor)
+{
+ if (bindingindex >= VERT_ATTRIB_GENERIC_MAX)
+ return;
+
+ unsigned i = VERT_ATTRIB_GENERIC(bindingindex);
+ vao->Attrib[i].Divisor = divisor;
+
+ if (divisor)
+ vao->NonZeroDivisorMask |= 1u << i;
+ else
+ vao->NonZeroDivisorMask &= ~(1u << i);
+}
+
+void
+_mesa_glthread_BindingDivisor(struct gl_context *ctx, GLuint bindingindex,
+ GLuint divisor)
+{
+ struct glthread_state *glthread = &ctx->GLThread;
+
+ binding_divisor(glthread, glthread->CurrentVAO, bindingindex, divisor);
+}
+
+void
+_mesa_glthread_DSABindingDivisor(struct gl_context *ctx, GLuint vaobj,
+ GLuint bindingindex, GLuint divisor)
+{
+ struct glthread_state *glthread = &ctx->GLThread;
+ struct glthread_vao *vao = lookup_vao(ctx, vaobj);
+
+ if (vao)
+ binding_divisor(glthread, vao, bindingindex, divisor);
+}
+
+void
+_mesa_glthread_AttribBinding(struct gl_context *ctx, GLuint attribindex,
+ GLuint bindingindex)
+{
+ struct glthread_state *glthread = &ctx->GLThread;
+
+ if (attribindex >= VERT_ATTRIB_GENERIC_MAX ||
+ bindingindex >= VERT_ATTRIB_GENERIC_MAX)
+ return;
+
+ set_attrib_binding(glthread, glthread->CurrentVAO,
+ VERT_ATTRIB_GENERIC(attribindex),
+ VERT_ATTRIB_GENERIC(bindingindex));
+}
+
+void
+_mesa_glthread_DSAAttribBinding(struct gl_context *ctx, GLuint vaobj,
+ GLuint attribindex, GLuint bindingindex)
+{
+ struct glthread_state *glthread = &ctx->GLThread;
+
+ if (attribindex >= VERT_ATTRIB_GENERIC_MAX ||
+ bindingindex >= VERT_ATTRIB_GENERIC_MAX)
+ return;
+
+ struct glthread_vao *vao = lookup_vao(ctx, vaobj);
+ if (vao) {
+ set_attrib_binding(glthread, vao,
+ VERT_ATTRIB_GENERIC(attribindex),
+ VERT_ATTRIB_GENERIC(bindingindex));
+ }
+}
+
+void
+_mesa_glthread_DSAElementBuffer(struct gl_context *ctx, GLuint vaobj,
+ GLuint buffer)
+{
+ struct glthread_vao *vao = lookup_vao(ctx, vaobj);
+
+ if (vao)
+ vao->CurrentElementBufferName = buffer;
+}
+
void
_mesa_glthread_PushClientAttrib(struct gl_context *ctx, GLbitfield mask,
bool set_default)