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 <pierre-eric.pelloux-prayer@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5303>
<param name="index" type="GLuint" />
</function>
- <function name="VertexArrayElementBuffer" no_error="true">
+ <function name="VertexArrayElementBuffer" no_error="true"
+ marshal_call_after="if (COMPAT) _mesa_glthread_DSAElementBuffer(ctx, vaobj, buffer);">
<param name="vaobj" type="GLuint" />
<param name="buffer" type="GLuint" />
</function>
- <function name="VertexArrayVertexBuffer" no_error="true">
+ <function name="VertexArrayVertexBuffer" no_error="true"
+ marshal_call_after="if (COMPAT) _mesa_glthread_DSAVertexBuffer(ctx, vaobj, bindingindex, buffer, offset, stride);">
<param name="vaobj" type="GLuint" />
<param name="bindingindex" type="GLuint" />
<param name="buffer" type="GLuint" />
<param name="stride" type="GLsizei" />
</function>
- <function name="VertexArrayVertexBuffers" no_error="true">
+ <function name="VertexArrayVertexBuffers" no_error="true"
+ marshal_call_after="if (COMPAT) _mesa_glthread_DSAVertexBuffers(ctx, vaobj, first, count, buffers, offsets, strides);">
<param name="vaobj" type="GLuint" />
<param name="first" type="GLuint" />
<param name="count" type="GLsizei" />
<param name="strides" type="const GLsizei *" count="count"/>
</function>
- <function name="VertexArrayAttribFormat">
+ <function name="VertexArrayAttribFormat"
+ marshal_call_after="if (COMPAT) _mesa_glthread_DSAAttribFormat(ctx, vaobj, attribindex, size, type, relativeoffset);">
<param name="vaobj" type="GLuint" />
<param name="attribindex" type="GLuint" />
<param name="size" type="GLint" />
<param name="relativeoffset" type="GLuint" />
</function>
- <function name="VertexArrayAttribIFormat">
+ <function name="VertexArrayAttribIFormat"
+ marshal_call_after="if (COMPAT) _mesa_glthread_DSAAttribFormat(ctx, vaobj, attribindex, size, type, relativeoffset);">
<param name="vaobj" type="GLuint" />
<param name="attribindex" type="GLuint" />
<param name="size" type="GLint" />
<param name="relativeoffset" type="GLuint" />
</function>
- <function name="VertexArrayAttribLFormat">
+ <function name="VertexArrayAttribLFormat"
+ marshal_call_after="if (COMPAT) _mesa_glthread_DSAAttribFormat(ctx, vaobj, attribindex, size, type, relativeoffset);">
<param name="vaobj" type="GLuint" />
<param name="attribindex" type="GLuint" />
<param name="size" type="GLint" />
<param name="relativeoffset" type="GLuint" />
</function>
- <function name="VertexArrayAttribBinding" no_error="true">
+ <function name="VertexArrayAttribBinding" no_error="true"
+ marshal_call_after="if (COMPAT) _mesa_glthread_DSAAttribBinding(ctx, vaobj, attribindex, bindingindex);">
<param name="vaobj" type="GLuint" />
<param name="attribindex" type="GLuint" />
<param name="bindingindex" type="GLuint" />
</function>
- <function name="VertexArrayBindingDivisor" no_error="true">
+ <function name="VertexArrayBindingDivisor" no_error="true"
+ marshal_call_after="if (COMPAT) _mesa_glthread_DSABindingDivisor(ctx, vaobj, bindingindex, divisor);">
<param name="vaobj" type="GLuint" />
<param name="bindingindex" type="GLuint" />
<param name="divisor" type="GLuint" />
<category name="GL_ARB_vertex_attrib_binding" number="125">
- <function name="BindVertexBuffer" es2="3.1" no_error="true">
+ <function name="BindVertexBuffer" es2="3.1" no_error="true"
+ marshal_call_after="if (COMPAT) _mesa_glthread_VertexBuffer(ctx, bindingindex, buffer, offset, stride);">
<param name="bindingindex" type="GLuint"/>
<param name="buffer" type="GLuint"/>
<param name="offset" type="GLintptr"/>
<param name="stride" type="GLsizei"/>
</function>
- <function name="VertexAttribFormat" es2="3.1">
+ <function name="VertexAttribFormat" es2="3.1"
+ marshal_call_after="if (COMPAT) _mesa_glthread_AttribFormat(ctx, attribindex, size, type, relativeoffset);">
<param name="attribindex" type="GLuint"/>
<param name="size" type="GLint"/>
<param name="type" type="GLenum"/>
<param name="relativeoffset" type="GLuint"/>
</function>
- <function name="VertexAttribIFormat" es2="3.1">
+ <function name="VertexAttribIFormat" es2="3.1"
+ marshal_call_after="if (COMPAT) _mesa_glthread_AttribFormat(ctx, attribindex, size, type, relativeoffset);">
<param name="attribindex" type="GLuint"/>
<param name="size" type="GLint"/>
<param name="type" type="GLenum"/>
<param name="relativeoffset" type="GLuint"/>
</function>
- <function name="VertexAttribLFormat">
+ <function name="VertexAttribLFormat"
+ marshal_call_after="if (COMPAT) _mesa_glthread_AttribFormat(ctx, attribindex, size, type, relativeoffset);">
<param name="attribindex" type="GLuint"/>
<param name="size" type="GLint"/>
<param name="type" type="GLenum"/>
<param name="relativeoffset" type="GLuint"/>
</function>
- <function name="VertexAttribBinding" es2="3.1" no_error="true">
+ <function name="VertexAttribBinding" es2="3.1" no_error="true"
+ marshal_call_after="if (COMPAT) _mesa_glthread_AttribBinding(ctx, attribindex, bindingindex);">
<param name="attribindex" type="GLuint"/>
<param name="bindingindex" type="GLuint"/>
</function>
- <function name="VertexBindingDivisor" es2="3.1" no_error="true">
+ <function name="VertexBindingDivisor" es2="3.1" no_error="true"
+ marshal_call_after="if (COMPAT) _mesa_glthread_BindingDivisor(ctx, bindingindex, divisor);">
<param name="bindingindex" type="GLuint"/>
<param name="divisor" type="GLuint"/>
</function>
- <function name="VertexArrayBindVertexBufferEXT">
+ <function name="VertexArrayBindVertexBufferEXT"
+ marshal_call_after="if (COMPAT) _mesa_glthread_DSAVertexBuffer(ctx, vaobj, bindingindex, buffer, offset, stride);">
<param name="vaobj" type="GLuint"/>
<param name="bindingindex" type="GLuint"/>
<param name="buffer" type="GLuint"/>
<param name="stride" type="GLsizei"/>
</function>
- <function name="VertexArrayVertexAttribFormatEXT">
+ <function name="VertexArrayVertexAttribFormatEXT"
+ marshal_call_after="if (COMPAT) _mesa_glthread_DSAAttribFormat(ctx, vaobj, attribindex, size, type, relativeoffset);">
<param name="vaobj" type="GLuint"/>
<param name="attribindex" type="GLuint"/>
<param name="size" type="GLint"/>
<param name="relativeoffset" type="GLuint"/>
</function>
- <function name="VertexArrayVertexAttribIFormatEXT">
+ <function name="VertexArrayVertexAttribIFormatEXT"
+ marshal_call_after="if (COMPAT) _mesa_glthread_DSAAttribFormat(ctx, vaobj, attribindex, size, type, relativeoffset);">
<param name="vaobj" type="GLuint"/>
<param name="attribindex" type="GLuint"/>
<param name="size" type="GLint"/>
<param name="relativeoffset" type="GLuint"/>
</function>
- <function name="VertexArrayVertexAttribLFormatEXT">
+ <function name="VertexArrayVertexAttribLFormatEXT"
+ marshal_call_after="if (COMPAT) _mesa_glthread_DSAAttribFormat(ctx, vaobj, attribindex, size, type, relativeoffset);">
<param name="vaobj" type="GLuint"/>
<param name="attribindex" type="GLuint"/>
<param name="size" type="GLint"/>
<param name="relativeoffset" type="GLuint"/>
</function>
- <function name="VertexArrayVertexAttribBindingEXT">
+ <function name="VertexArrayVertexAttribBindingEXT"
+ marshal_call_after="if (COMPAT) _mesa_glthread_DSAAttribBinding(ctx, vaobj, attribindex, bindingindex);">
<param name="vaobj" type="GLuint"/>
<param name="attribindex" type="GLuint"/>
<param name="bindingindex" type="GLuint"/>
</function>
- <function name="VertexArrayVertexBindingDivisorEXT">
+ <function name="VertexArrayVertexBindingDivisorEXT"
+ marshal_call_after="if (COMPAT) _mesa_glthread_DSABindingDivisor(ctx, vaobj, bindingindex, divisor);">
<param name="vaobj" type="GLuint"/>
<param name="bindingindex" type="GLuint"/>
<param name="divisor" type="GLuint"/>
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];
};
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);
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. */
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);
buffers[num_buffers].original_pointer = ptr;
num_buffers++;
}
+
return true;
}
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");
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;
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)
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)
return ctx->API != API_OPENGL_CORE &&
(vao->CurrentElementBufferName == 0 ||
- (vao->UserPointerMask & vao->Enabled));
+ (vao->UserPointerMask & vao->BufferEnabled));
}
static inline bool
const struct glthread_vao *vao = glthread->CurrentVAO;
return ctx->API != API_OPENGL_CORE &&
- (vao->UserPointerMask & vao->Enabled);
+ (vao->UserPointerMask & vao->BufferEnabled);
}
static inline bool
return ctx->API != API_OPENGL_CORE &&
(glthread->CurrentDrawIndirectBufferName == 0 ||
- (vao->UserPointerMask & vao->Enabled));
+ (vao->UserPointerMask & vao->BufferEnabled));
}
static inline bool
return ctx->API != API_OPENGL_CORE &&
(glthread->CurrentDrawIndirectBufferName == 0 ||
vao->CurrentElementBufferName == 0 ||
- (vao->UserPointerMask & vao->Enabled));
+ (vao->UserPointerMask & vao->BufferEnabled));
}
#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)
vao->CurrentElementBufferName = 0;
vao->UserEnabled = 0;
vao->Enabled = 0;
+ vao->BufferEnabled = 0;
vao->UserPointerMask = 0;
vao->NonZeroDivisorMask = 0;
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;
}
}
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)
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)
{
vao->Attrib[attrib].Divisor = divisor;
+ set_attrib_binding(&ctx->GLThread, vao, attrib, attrib);
+
if (divisor)
vao->NonZeroDivisorMask |= 1u << attrib;
else
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);
(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)