From a2d7f4fe5a52d2968f8d0fbbf879368a6e7044aa Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marek=20Ol=C5=A1=C3=A1k?= Date: Sat, 30 May 2020 17:42:46 -0400 Subject: [PATCH] glthread: handle ARB_vertex_attrib_binding This handles ARB_vertex_attrib_binding for vertex uploads correctly. Before this, the extension might have led to crashes if non-VBO vertex attribs were present. Acked-by: Pierre-Eric Pelloux-Prayer Part-of: --- .../glapi/gen/ARB_direct_state_access.xml | 24 +- .../glapi/gen/ARB_vertex_attrib_binding.xml | 36 ++- src/mesa/main/glthread.h | 39 ++- src/mesa/main/glthread_draw.c | 114 +++++++- src/mesa/main/glthread_marshal.h | 8 +- src/mesa/main/glthread_varray.c | 268 +++++++++++++++++- 6 files changed, 443 insertions(+), 46 deletions(-) diff --git a/src/mapi/glapi/gen/ARB_direct_state_access.xml b/src/mapi/glapi/gen/ARB_direct_state_access.xml index cd0f51c4327..f06adc4cfc2 100644 --- a/src/mapi/glapi/gen/ARB_direct_state_access.xml +++ b/src/mapi/glapi/gen/ARB_direct_state_access.xml @@ -597,12 +597,14 @@ - + - + @@ -610,7 +612,8 @@ - + @@ -619,7 +622,8 @@ - + @@ -628,7 +632,8 @@ - + @@ -636,7 +641,8 @@ - + @@ -644,13 +650,15 @@ - + - + diff --git a/src/mapi/glapi/gen/ARB_vertex_attrib_binding.xml b/src/mapi/glapi/gen/ARB_vertex_attrib_binding.xml index ca9dd5a75c2..056cc345430 100644 --- a/src/mapi/glapi/gen/ARB_vertex_attrib_binding.xml +++ b/src/mapi/glapi/gen/ARB_vertex_attrib_binding.xml @@ -7,14 +7,16 @@ - + - + @@ -22,31 +24,36 @@ - + - + - + - + - + @@ -54,7 +61,8 @@ - + @@ -63,7 +71,8 @@ - + @@ -71,7 +80,8 @@ - + @@ -79,13 +89,15 @@ - + - + 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) -- 2.30.2