17ec681f3Smrg/*
27ec681f3Smrg * Copyright © 2020 Advanced Micro Devices, Inc.
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice (including the next
127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg * Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
217ec681f3Smrg * IN THE SOFTWARE.
227ec681f3Smrg */
237ec681f3Smrg
247ec681f3Smrg/* This implements vertex array state tracking for glthread. It's separate
257ec681f3Smrg * from the rest of Mesa. Only minimum functionality is implemented here
267ec681f3Smrg * to serve glthread.
277ec681f3Smrg */
287ec681f3Smrg
297ec681f3Smrg#include "main/glthread.h"
307ec681f3Smrg#include "main/glformats.h"
317ec681f3Smrg#include "main/mtypes.h"
327ec681f3Smrg#include "main/hash.h"
337ec681f3Smrg#include "main/dispatch.h"
347ec681f3Smrg#include "main/varray.h"
357ec681f3Smrg
367ec681f3Smrg
377ec681f3Smrgvoid
387ec681f3Smrg_mesa_glthread_reset_vao(struct glthread_vao *vao)
397ec681f3Smrg{
407ec681f3Smrg   static unsigned default_elem_size[VERT_ATTRIB_MAX] = {
417ec681f3Smrg      [VERT_ATTRIB_NORMAL] = 12,
427ec681f3Smrg      [VERT_ATTRIB_COLOR1] = 12,
437ec681f3Smrg      [VERT_ATTRIB_FOG] = 4,
447ec681f3Smrg      [VERT_ATTRIB_COLOR_INDEX] = 4,
457ec681f3Smrg      [VERT_ATTRIB_EDGEFLAG] = 1,
467ec681f3Smrg      [VERT_ATTRIB_POINT_SIZE] = 4,
477ec681f3Smrg   };
487ec681f3Smrg
497ec681f3Smrg   vao->CurrentElementBufferName = 0;
507ec681f3Smrg   vao->UserEnabled = 0;
517ec681f3Smrg   vao->Enabled = 0;
527ec681f3Smrg   vao->BufferEnabled = 0;
537ec681f3Smrg   vao->UserPointerMask = 0;
547ec681f3Smrg   vao->NonZeroDivisorMask = 0;
557ec681f3Smrg
567ec681f3Smrg   for (unsigned i = 0; i < ARRAY_SIZE(vao->Attrib); i++) {
577ec681f3Smrg      unsigned elem_size = default_elem_size[i];
587ec681f3Smrg      if (!elem_size)
597ec681f3Smrg         elem_size = 16;
607ec681f3Smrg
617ec681f3Smrg      vao->Attrib[i].ElementSize = elem_size;
627ec681f3Smrg      vao->Attrib[i].RelativeOffset = 0;
637ec681f3Smrg      vao->Attrib[i].BufferIndex = i;
647ec681f3Smrg      vao->Attrib[i].Stride = elem_size;
657ec681f3Smrg      vao->Attrib[i].Divisor = 0;
667ec681f3Smrg      vao->Attrib[i].EnabledAttribCount = 0;
677ec681f3Smrg      vao->Attrib[i].Pointer = NULL;
687ec681f3Smrg   }
697ec681f3Smrg}
707ec681f3Smrg
717ec681f3Smrgstatic struct glthread_vao *
727ec681f3Smrglookup_vao(struct gl_context *ctx, GLuint id)
737ec681f3Smrg{
747ec681f3Smrg   struct glthread_state *glthread = &ctx->GLThread;
757ec681f3Smrg   struct glthread_vao *vao;
767ec681f3Smrg
777ec681f3Smrg   assert(id != 0);
787ec681f3Smrg
797ec681f3Smrg   if (glthread->LastLookedUpVAO &&
807ec681f3Smrg       glthread->LastLookedUpVAO->Name == id) {
817ec681f3Smrg      vao = glthread->LastLookedUpVAO;
827ec681f3Smrg   } else {
837ec681f3Smrg      vao = _mesa_HashLookupLocked(glthread->VAOs, id);
847ec681f3Smrg      if (!vao)
857ec681f3Smrg         return NULL;
867ec681f3Smrg
877ec681f3Smrg      glthread->LastLookedUpVAO = vao;
887ec681f3Smrg   }
897ec681f3Smrg
907ec681f3Smrg   return vao;
917ec681f3Smrg}
927ec681f3Smrg
937ec681f3Smrgvoid
947ec681f3Smrg_mesa_glthread_BindVertexArray(struct gl_context *ctx, GLuint id)
957ec681f3Smrg{
967ec681f3Smrg   struct glthread_state *glthread = &ctx->GLThread;
977ec681f3Smrg
987ec681f3Smrg   if (id == 0) {
997ec681f3Smrg      glthread->CurrentVAO = &glthread->DefaultVAO;
1007ec681f3Smrg   } else {
1017ec681f3Smrg      struct glthread_vao *vao = lookup_vao(ctx, id);
1027ec681f3Smrg
1037ec681f3Smrg      if (vao)
1047ec681f3Smrg         glthread->CurrentVAO = vao;
1057ec681f3Smrg   }
1067ec681f3Smrg}
1077ec681f3Smrg
1087ec681f3Smrgvoid
1097ec681f3Smrg_mesa_glthread_DeleteVertexArrays(struct gl_context *ctx,
1107ec681f3Smrg                                  GLsizei n, const GLuint *ids)
1117ec681f3Smrg{
1127ec681f3Smrg   struct glthread_state *glthread = &ctx->GLThread;
1137ec681f3Smrg
1147ec681f3Smrg   if (!ids)
1157ec681f3Smrg      return;
1167ec681f3Smrg
1177ec681f3Smrg   for (int i = 0; i < n; i++) {
1187ec681f3Smrg      /* IDs equal to 0 should be silently ignored. */
1197ec681f3Smrg      if (!ids[i])
1207ec681f3Smrg         continue;
1217ec681f3Smrg
1227ec681f3Smrg      struct glthread_vao *vao = lookup_vao(ctx, ids[i]);
1237ec681f3Smrg      if (!vao)
1247ec681f3Smrg         continue;
1257ec681f3Smrg
1267ec681f3Smrg      /* If the array object is currently bound, the spec says "the binding
1277ec681f3Smrg       * for that object reverts to zero and the default vertex array
1287ec681f3Smrg       * becomes current."
1297ec681f3Smrg       */
1307ec681f3Smrg      if (glthread->CurrentVAO == vao)
1317ec681f3Smrg         glthread->CurrentVAO = &glthread->DefaultVAO;
1327ec681f3Smrg
1337ec681f3Smrg      if (glthread->LastLookedUpVAO == vao)
1347ec681f3Smrg         glthread->LastLookedUpVAO = NULL;
1357ec681f3Smrg
1367ec681f3Smrg      /* The ID is immediately freed for re-use */
1377ec681f3Smrg      _mesa_HashRemoveLocked(glthread->VAOs, vao->Name);
1387ec681f3Smrg      free(vao);
1397ec681f3Smrg   }
1407ec681f3Smrg}
1417ec681f3Smrg
1427ec681f3Smrgvoid
1437ec681f3Smrg_mesa_glthread_GenVertexArrays(struct gl_context *ctx,
1447ec681f3Smrg                               GLsizei n, GLuint *arrays)
1457ec681f3Smrg{
1467ec681f3Smrg   struct glthread_state *glthread = &ctx->GLThread;
1477ec681f3Smrg
1487ec681f3Smrg   if (!arrays)
1497ec681f3Smrg      return;
1507ec681f3Smrg
1517ec681f3Smrg   /* The IDs have been generated at this point. Create VAOs for glthread. */
1527ec681f3Smrg   for (int i = 0; i < n; i++) {
1537ec681f3Smrg      GLuint id = arrays[i];
1547ec681f3Smrg      struct glthread_vao *vao;
1557ec681f3Smrg
1567ec681f3Smrg      vao = calloc(1, sizeof(*vao));
1577ec681f3Smrg      if (!vao)
1587ec681f3Smrg         continue; /* Is that all we can do? */
1597ec681f3Smrg
1607ec681f3Smrg      vao->Name = id;
1617ec681f3Smrg      _mesa_glthread_reset_vao(vao);
1627ec681f3Smrg      _mesa_HashInsertLocked(glthread->VAOs, id, vao, true);
1637ec681f3Smrg   }
1647ec681f3Smrg}
1657ec681f3Smrg
1667ec681f3Smrg/* If vaobj is NULL, use the currently-bound VAO. */
1677ec681f3Smrgstatic inline struct glthread_vao *
1687ec681f3Smrgget_vao(struct gl_context *ctx, const GLuint *vaobj)
1697ec681f3Smrg{
1707ec681f3Smrg   if (vaobj)
1717ec681f3Smrg      return lookup_vao(ctx, *vaobj);
1727ec681f3Smrg
1737ec681f3Smrg   return ctx->GLThread.CurrentVAO;
1747ec681f3Smrg}
1757ec681f3Smrg
1767ec681f3Smrgstatic void
1777ec681f3Smrgupdate_primitive_restart(struct gl_context *ctx)
1787ec681f3Smrg{
1797ec681f3Smrg   struct glthread_state *glthread = &ctx->GLThread;
1807ec681f3Smrg
1817ec681f3Smrg   glthread->_PrimitiveRestart = glthread->PrimitiveRestart ||
1827ec681f3Smrg                                 glthread->PrimitiveRestartFixedIndex;
1837ec681f3Smrg   glthread->_RestartIndex[0] =
1847ec681f3Smrg      _mesa_get_prim_restart_index(glthread->PrimitiveRestartFixedIndex,
1857ec681f3Smrg                                   glthread->RestartIndex, 1);
1867ec681f3Smrg   glthread->_RestartIndex[1] =
1877ec681f3Smrg      _mesa_get_prim_restart_index(glthread->PrimitiveRestartFixedIndex,
1887ec681f3Smrg                                   glthread->RestartIndex, 2);
1897ec681f3Smrg   glthread->_RestartIndex[3] =
1907ec681f3Smrg      _mesa_get_prim_restart_index(glthread->PrimitiveRestartFixedIndex,
1917ec681f3Smrg                                   glthread->RestartIndex, 4);
1927ec681f3Smrg}
1937ec681f3Smrg
1947ec681f3Smrgvoid
1957ec681f3Smrg_mesa_glthread_set_prim_restart(struct gl_context *ctx, GLenum cap, bool value)
1967ec681f3Smrg{
1977ec681f3Smrg   switch (cap) {
1987ec681f3Smrg   case GL_PRIMITIVE_RESTART:
1997ec681f3Smrg      ctx->GLThread.PrimitiveRestart = value;
2007ec681f3Smrg      break;
2017ec681f3Smrg   case GL_PRIMITIVE_RESTART_FIXED_INDEX:
2027ec681f3Smrg      ctx->GLThread.PrimitiveRestartFixedIndex = value;
2037ec681f3Smrg      break;
2047ec681f3Smrg   }
2057ec681f3Smrg
2067ec681f3Smrg   update_primitive_restart(ctx);
2077ec681f3Smrg}
2087ec681f3Smrg
2097ec681f3Smrgvoid
2107ec681f3Smrg_mesa_glthread_PrimitiveRestartIndex(struct gl_context *ctx, GLuint index)
2117ec681f3Smrg{
2127ec681f3Smrg   ctx->GLThread.RestartIndex = index;
2137ec681f3Smrg   update_primitive_restart(ctx);
2147ec681f3Smrg}
2157ec681f3Smrg
2167ec681f3Smrgstatic inline void
2177ec681f3Smrgenable_buffer(struct glthread_vao *vao, unsigned binding_index)
2187ec681f3Smrg{
2197ec681f3Smrg   int attrib_count = ++vao->Attrib[binding_index].EnabledAttribCount;
2207ec681f3Smrg
2217ec681f3Smrg   if (attrib_count == 1)
2227ec681f3Smrg      vao->BufferEnabled |= 1 << binding_index;
2237ec681f3Smrg   else if (attrib_count == 2)
2247ec681f3Smrg      vao->BufferInterleaved |= 1 << binding_index;
2257ec681f3Smrg}
2267ec681f3Smrg
2277ec681f3Smrgstatic inline void
2287ec681f3Smrgdisable_buffer(struct glthread_vao *vao, unsigned binding_index)
2297ec681f3Smrg{
2307ec681f3Smrg   int attrib_count = --vao->Attrib[binding_index].EnabledAttribCount;
2317ec681f3Smrg
2327ec681f3Smrg   if (attrib_count == 0)
2337ec681f3Smrg      vao->BufferEnabled &= ~(1 << binding_index);
2347ec681f3Smrg   else if (attrib_count == 1)
2357ec681f3Smrg      vao->BufferInterleaved &= ~(1 << binding_index);
2367ec681f3Smrg   else
2377ec681f3Smrg      assert(attrib_count >= 0);
2387ec681f3Smrg}
2397ec681f3Smrg
2407ec681f3Smrgvoid
2417ec681f3Smrg_mesa_glthread_ClientState(struct gl_context *ctx, GLuint *vaobj,
2427ec681f3Smrg                           gl_vert_attrib attrib, bool enable)
2437ec681f3Smrg{
2447ec681f3Smrg   /* The primitive restart client state uses a special value. */
2457ec681f3Smrg   if (attrib == VERT_ATTRIB_PRIMITIVE_RESTART_NV) {
2467ec681f3Smrg      ctx->GLThread.PrimitiveRestart = enable;
2477ec681f3Smrg      update_primitive_restart(ctx);
2487ec681f3Smrg      return;
2497ec681f3Smrg   }
2507ec681f3Smrg
2517ec681f3Smrg   if (attrib >= VERT_ATTRIB_MAX)
2527ec681f3Smrg      return;
2537ec681f3Smrg
2547ec681f3Smrg   struct glthread_vao *vao = get_vao(ctx, vaobj);
2557ec681f3Smrg   if (!vao)
2567ec681f3Smrg      return;
2577ec681f3Smrg
2587ec681f3Smrg   const unsigned attrib_bit = 1u << attrib;
2597ec681f3Smrg
2607ec681f3Smrg   if (enable && !(vao->UserEnabled & attrib_bit)) {
2617ec681f3Smrg      vao->UserEnabled |= attrib_bit;
2627ec681f3Smrg
2637ec681f3Smrg      /* The generic0 attribute supersedes the position attribute. We need to
2647ec681f3Smrg       * update BufferBindingEnabled accordingly.
2657ec681f3Smrg       */
2667ec681f3Smrg      if (attrib == VERT_ATTRIB_POS) {
2677ec681f3Smrg         if (!(vao->UserEnabled & VERT_BIT_GENERIC0))
2687ec681f3Smrg            enable_buffer(vao, vao->Attrib[VERT_ATTRIB_POS].BufferIndex);
2697ec681f3Smrg      } else {
2707ec681f3Smrg         enable_buffer(vao, vao->Attrib[attrib].BufferIndex);
2717ec681f3Smrg
2727ec681f3Smrg         if (attrib == VERT_ATTRIB_GENERIC0 && vao->UserEnabled & VERT_BIT_POS)
2737ec681f3Smrg            disable_buffer(vao, vao->Attrib[VERT_ATTRIB_POS].BufferIndex);
2747ec681f3Smrg      }
2757ec681f3Smrg   } else if (!enable && (vao->UserEnabled & attrib_bit)) {
2767ec681f3Smrg      vao->UserEnabled &= ~attrib_bit;
2777ec681f3Smrg
2787ec681f3Smrg      /* The generic0 attribute supersedes the position attribute. We need to
2797ec681f3Smrg       * update BufferBindingEnabled accordingly.
2807ec681f3Smrg       */
2817ec681f3Smrg      if (attrib == VERT_ATTRIB_POS) {
2827ec681f3Smrg         if (!(vao->UserEnabled & VERT_BIT_GENERIC0))
2837ec681f3Smrg            disable_buffer(vao, vao->Attrib[VERT_ATTRIB_POS].BufferIndex);
2847ec681f3Smrg      } else {
2857ec681f3Smrg         disable_buffer(vao, vao->Attrib[attrib].BufferIndex);
2867ec681f3Smrg
2877ec681f3Smrg         if (attrib == VERT_ATTRIB_GENERIC0 && vao->UserEnabled & VERT_BIT_POS)
2887ec681f3Smrg            enable_buffer(vao, vao->Attrib[VERT_ATTRIB_POS].BufferIndex);
2897ec681f3Smrg      }
2907ec681f3Smrg   }
2917ec681f3Smrg
2927ec681f3Smrg   /* The generic0 attribute supersedes the position attribute. */
2937ec681f3Smrg   vao->Enabled = vao->UserEnabled;
2947ec681f3Smrg   if (vao->Enabled & VERT_BIT_GENERIC0)
2957ec681f3Smrg      vao->Enabled &= ~VERT_BIT_POS;
2967ec681f3Smrg}
2977ec681f3Smrg
2987ec681f3Smrgstatic void
2997ec681f3Smrgset_attrib_binding(struct glthread_state *glthread, struct glthread_vao *vao,
3007ec681f3Smrg                   gl_vert_attrib attrib, unsigned new_binding_index)
3017ec681f3Smrg{
3027ec681f3Smrg   unsigned old_binding_index = vao->Attrib[attrib].BufferIndex;
3037ec681f3Smrg
3047ec681f3Smrg   if (old_binding_index != new_binding_index) {
3057ec681f3Smrg      vao->Attrib[attrib].BufferIndex = new_binding_index;
3067ec681f3Smrg
3077ec681f3Smrg      if (vao->Enabled & (1u << attrib)) {
3087ec681f3Smrg         /* Update BufferBindingEnabled. */
3097ec681f3Smrg         enable_buffer(vao, new_binding_index);
3107ec681f3Smrg         disable_buffer(vao, old_binding_index);
3117ec681f3Smrg      }
3127ec681f3Smrg   }
3137ec681f3Smrg}
3147ec681f3Smrg
3157ec681f3Smrgvoid _mesa_glthread_AttribDivisor(struct gl_context *ctx, const GLuint *vaobj,
3167ec681f3Smrg                                  gl_vert_attrib attrib, GLuint divisor)
3177ec681f3Smrg{
3187ec681f3Smrg   if (attrib >= VERT_ATTRIB_MAX)
3197ec681f3Smrg      return;
3207ec681f3Smrg
3217ec681f3Smrg   struct glthread_vao *vao = get_vao(ctx, vaobj);
3227ec681f3Smrg   if (!vao)
3237ec681f3Smrg      return;
3247ec681f3Smrg
3257ec681f3Smrg   vao->Attrib[attrib].Divisor = divisor;
3267ec681f3Smrg
3277ec681f3Smrg   set_attrib_binding(&ctx->GLThread, vao, attrib, attrib);
3287ec681f3Smrg
3297ec681f3Smrg   if (divisor)
3307ec681f3Smrg      vao->NonZeroDivisorMask |= 1u << attrib;
3317ec681f3Smrg   else
3327ec681f3Smrg      vao->NonZeroDivisorMask &= ~(1u << attrib);
3337ec681f3Smrg}
3347ec681f3Smrg
3357ec681f3Smrgstatic unsigned
3367ec681f3Smrgelement_size(GLint size, GLenum type)
3377ec681f3Smrg{
3387ec681f3Smrg   if (size == GL_BGRA)
3397ec681f3Smrg      size = 4;
3407ec681f3Smrg
3417ec681f3Smrg   return _mesa_bytes_per_vertex_attrib(size, type);
3427ec681f3Smrg}
3437ec681f3Smrg
3447ec681f3Smrgstatic void
3457ec681f3Smrgattrib_pointer(struct glthread_state *glthread, struct glthread_vao *vao,
3467ec681f3Smrg               GLuint buffer, gl_vert_attrib attrib,
3477ec681f3Smrg               GLint size, GLenum type, GLsizei stride,
3487ec681f3Smrg               const void *pointer)
3497ec681f3Smrg{
3507ec681f3Smrg   if (attrib >= VERT_ATTRIB_MAX)
3517ec681f3Smrg      return;
3527ec681f3Smrg
3537ec681f3Smrg   unsigned elem_size = element_size(size, type);
3547ec681f3Smrg
3557ec681f3Smrg   vao->Attrib[attrib].ElementSize = elem_size;
3567ec681f3Smrg   vao->Attrib[attrib].Stride = stride ? stride : elem_size;
3577ec681f3Smrg   vao->Attrib[attrib].Pointer = pointer;
3587ec681f3Smrg   vao->Attrib[attrib].RelativeOffset = 0;
3597ec681f3Smrg
3607ec681f3Smrg   set_attrib_binding(glthread, vao, attrib, attrib);
3617ec681f3Smrg
3627ec681f3Smrg   if (buffer != 0)
3637ec681f3Smrg      vao->UserPointerMask &= ~(1u << attrib);
3647ec681f3Smrg   else
3657ec681f3Smrg      vao->UserPointerMask |= 1u << attrib;
3667ec681f3Smrg}
3677ec681f3Smrg
3687ec681f3Smrgvoid
3697ec681f3Smrg_mesa_glthread_AttribPointer(struct gl_context *ctx, gl_vert_attrib attrib,
3707ec681f3Smrg                             GLint size, GLenum type, GLsizei stride,
3717ec681f3Smrg                             const void *pointer)
3727ec681f3Smrg{
3737ec681f3Smrg   struct glthread_state *glthread = &ctx->GLThread;
3747ec681f3Smrg
3757ec681f3Smrg   attrib_pointer(glthread, glthread->CurrentVAO,
3767ec681f3Smrg                  glthread->CurrentArrayBufferName,
3777ec681f3Smrg                  attrib, size, type, stride, pointer);
3787ec681f3Smrg}
3797ec681f3Smrg
3807ec681f3Smrgvoid
3817ec681f3Smrg_mesa_glthread_DSAAttribPointer(struct gl_context *ctx, GLuint vaobj,
3827ec681f3Smrg                                GLuint buffer, gl_vert_attrib attrib,
3837ec681f3Smrg                                GLint size, GLenum type, GLsizei stride,
3847ec681f3Smrg                                GLintptr offset)
3857ec681f3Smrg{
3867ec681f3Smrg   struct glthread_state *glthread = &ctx->GLThread;
3877ec681f3Smrg   struct glthread_vao *vao;
3887ec681f3Smrg
3897ec681f3Smrg   vao = lookup_vao(ctx, vaobj);
3907ec681f3Smrg   if (!vao)
3917ec681f3Smrg      return;
3927ec681f3Smrg
3937ec681f3Smrg   attrib_pointer(glthread, vao, buffer, attrib, size, type, stride,
3947ec681f3Smrg                  (const void*)offset);
3957ec681f3Smrg}
3967ec681f3Smrg
3977ec681f3Smrgstatic void
3987ec681f3Smrgattrib_format(struct glthread_state *glthread, struct glthread_vao *vao,
3997ec681f3Smrg              GLuint attribindex, GLint size, GLenum type,
4007ec681f3Smrg              GLuint relativeoffset)
4017ec681f3Smrg{
4027ec681f3Smrg   if (attribindex >= VERT_ATTRIB_GENERIC_MAX)
4037ec681f3Smrg      return;
4047ec681f3Smrg
4057ec681f3Smrg   unsigned elem_size = element_size(size, type);
4067ec681f3Smrg
4077ec681f3Smrg   unsigned i = VERT_ATTRIB_GENERIC(attribindex);
4087ec681f3Smrg   vao->Attrib[i].ElementSize = elem_size;
4097ec681f3Smrg   vao->Attrib[i].RelativeOffset = relativeoffset;
4107ec681f3Smrg}
4117ec681f3Smrg
4127ec681f3Smrgvoid
4137ec681f3Smrg_mesa_glthread_AttribFormat(struct gl_context *ctx, GLuint attribindex,
4147ec681f3Smrg                            GLint size, GLenum type, GLuint relativeoffset)
4157ec681f3Smrg{
4167ec681f3Smrg   struct glthread_state *glthread = &ctx->GLThread;
4177ec681f3Smrg
4187ec681f3Smrg   attrib_format(glthread, glthread->CurrentVAO, attribindex, size, type,
4197ec681f3Smrg                 relativeoffset);
4207ec681f3Smrg}
4217ec681f3Smrg
4227ec681f3Smrgvoid
4237ec681f3Smrg_mesa_glthread_DSAAttribFormat(struct gl_context *ctx, GLuint vaobj,
4247ec681f3Smrg                               GLuint attribindex, GLint size, GLenum type,
4257ec681f3Smrg                               GLuint relativeoffset)
4267ec681f3Smrg{
4277ec681f3Smrg   struct glthread_state *glthread = &ctx->GLThread;
4287ec681f3Smrg   struct glthread_vao *vao = lookup_vao(ctx, vaobj);
4297ec681f3Smrg
4307ec681f3Smrg   if (vao)
4317ec681f3Smrg      attrib_format(glthread, vao, attribindex, size, type, relativeoffset);
4327ec681f3Smrg}
4337ec681f3Smrg
4347ec681f3Smrgstatic void
4357ec681f3Smrgbind_vertex_buffer(struct glthread_state *glthread, struct glthread_vao *vao,
4367ec681f3Smrg                   GLuint bindingindex, GLuint buffer, GLintptr offset,
4377ec681f3Smrg                   GLsizei stride)
4387ec681f3Smrg{
4397ec681f3Smrg   if (bindingindex >= VERT_ATTRIB_GENERIC_MAX)
4407ec681f3Smrg      return;
4417ec681f3Smrg
4427ec681f3Smrg   unsigned i = VERT_ATTRIB_GENERIC(bindingindex);
4437ec681f3Smrg   vao->Attrib[i].Pointer = (const void*)offset;
4447ec681f3Smrg   vao->Attrib[i].Stride = stride;
4457ec681f3Smrg
4467ec681f3Smrg   if (buffer != 0)
4477ec681f3Smrg      vao->UserPointerMask &= ~(1u << i);
4487ec681f3Smrg   else
4497ec681f3Smrg      vao->UserPointerMask |= 1u << i;
4507ec681f3Smrg}
4517ec681f3Smrg
4527ec681f3Smrgvoid
4537ec681f3Smrg_mesa_glthread_VertexBuffer(struct gl_context *ctx, GLuint bindingindex,
4547ec681f3Smrg                            GLuint buffer, GLintptr offset, GLsizei stride)
4557ec681f3Smrg{
4567ec681f3Smrg   struct glthread_state *glthread = &ctx->GLThread;
4577ec681f3Smrg
4587ec681f3Smrg   bind_vertex_buffer(glthread, glthread->CurrentVAO, bindingindex, buffer,
4597ec681f3Smrg                      offset, stride);
4607ec681f3Smrg}
4617ec681f3Smrg
4627ec681f3Smrgvoid
4637ec681f3Smrg_mesa_glthread_DSAVertexBuffer(struct gl_context *ctx, GLuint vaobj,
4647ec681f3Smrg                               GLuint bindingindex, GLuint buffer,
4657ec681f3Smrg                               GLintptr offset, GLsizei stride)
4667ec681f3Smrg{
4677ec681f3Smrg   struct glthread_state *glthread = &ctx->GLThread;
4687ec681f3Smrg   struct glthread_vao *vao = lookup_vao(ctx, vaobj);
4697ec681f3Smrg
4707ec681f3Smrg   if (vao)
4717ec681f3Smrg      bind_vertex_buffer(glthread, vao, bindingindex, buffer, offset, stride);
4727ec681f3Smrg}
4737ec681f3Smrg
4747ec681f3Smrgvoid
4757ec681f3Smrg_mesa_glthread_DSAVertexBuffers(struct gl_context *ctx, GLuint vaobj,
4767ec681f3Smrg                                GLuint first, GLsizei count,
4777ec681f3Smrg                                const GLuint *buffers,
4787ec681f3Smrg                                const GLintptr *offsets,
4797ec681f3Smrg                                const GLsizei *strides)
4807ec681f3Smrg{
4817ec681f3Smrg   struct glthread_state *glthread = &ctx->GLThread;
4827ec681f3Smrg   struct glthread_vao *vao;
4837ec681f3Smrg
4847ec681f3Smrg   vao = lookup_vao(ctx, vaobj);
4857ec681f3Smrg   if (!vao)
4867ec681f3Smrg      return;
4877ec681f3Smrg
4887ec681f3Smrg   for (unsigned i = 0; i < count; i++) {
4897ec681f3Smrg      bind_vertex_buffer(glthread, vao, first + i, buffers[i], offsets[i],
4907ec681f3Smrg                         strides[i]);
4917ec681f3Smrg   }
4927ec681f3Smrg}
4937ec681f3Smrg
4947ec681f3Smrgstatic void
4957ec681f3Smrgbinding_divisor(struct glthread_state *glthread, struct glthread_vao *vao,
4967ec681f3Smrg                GLuint bindingindex, GLuint divisor)
4977ec681f3Smrg{
4987ec681f3Smrg   if (bindingindex >= VERT_ATTRIB_GENERIC_MAX)
4997ec681f3Smrg      return;
5007ec681f3Smrg
5017ec681f3Smrg   unsigned i = VERT_ATTRIB_GENERIC(bindingindex);
5027ec681f3Smrg   vao->Attrib[i].Divisor = divisor;
5037ec681f3Smrg
5047ec681f3Smrg   if (divisor)
5057ec681f3Smrg      vao->NonZeroDivisorMask |= 1u << i;
5067ec681f3Smrg   else
5077ec681f3Smrg      vao->NonZeroDivisorMask &= ~(1u << i);
5087ec681f3Smrg}
5097ec681f3Smrg
5107ec681f3Smrgvoid
5117ec681f3Smrg_mesa_glthread_BindingDivisor(struct gl_context *ctx, GLuint bindingindex,
5127ec681f3Smrg                              GLuint divisor)
5137ec681f3Smrg{
5147ec681f3Smrg   struct glthread_state *glthread = &ctx->GLThread;
5157ec681f3Smrg
5167ec681f3Smrg   binding_divisor(glthread, glthread->CurrentVAO, bindingindex, divisor);
5177ec681f3Smrg}
5187ec681f3Smrg
5197ec681f3Smrgvoid
5207ec681f3Smrg_mesa_glthread_DSABindingDivisor(struct gl_context *ctx, GLuint vaobj,
5217ec681f3Smrg                                 GLuint bindingindex, GLuint divisor)
5227ec681f3Smrg{
5237ec681f3Smrg   struct glthread_state *glthread = &ctx->GLThread;
5247ec681f3Smrg   struct glthread_vao *vao = lookup_vao(ctx, vaobj);
5257ec681f3Smrg
5267ec681f3Smrg   if (vao)
5277ec681f3Smrg      binding_divisor(glthread, vao, bindingindex, divisor);
5287ec681f3Smrg}
5297ec681f3Smrg
5307ec681f3Smrgvoid
5317ec681f3Smrg_mesa_glthread_AttribBinding(struct gl_context *ctx, GLuint attribindex,
5327ec681f3Smrg                             GLuint bindingindex)
5337ec681f3Smrg{
5347ec681f3Smrg   struct glthread_state *glthread = &ctx->GLThread;
5357ec681f3Smrg
5367ec681f3Smrg   if (attribindex >= VERT_ATTRIB_GENERIC_MAX ||
5377ec681f3Smrg       bindingindex >= VERT_ATTRIB_GENERIC_MAX)
5387ec681f3Smrg      return;
5397ec681f3Smrg
5407ec681f3Smrg   set_attrib_binding(glthread, glthread->CurrentVAO,
5417ec681f3Smrg                      VERT_ATTRIB_GENERIC(attribindex),
5427ec681f3Smrg                      VERT_ATTRIB_GENERIC(bindingindex));
5437ec681f3Smrg}
5447ec681f3Smrg
5457ec681f3Smrgvoid
5467ec681f3Smrg_mesa_glthread_DSAAttribBinding(struct gl_context *ctx, GLuint vaobj,
5477ec681f3Smrg                                GLuint attribindex, GLuint bindingindex)
5487ec681f3Smrg{
5497ec681f3Smrg   struct glthread_state *glthread = &ctx->GLThread;
5507ec681f3Smrg
5517ec681f3Smrg   if (attribindex >= VERT_ATTRIB_GENERIC_MAX ||
5527ec681f3Smrg       bindingindex >= VERT_ATTRIB_GENERIC_MAX)
5537ec681f3Smrg      return;
5547ec681f3Smrg
5557ec681f3Smrg   struct glthread_vao *vao = lookup_vao(ctx, vaobj);
5567ec681f3Smrg   if (vao) {
5577ec681f3Smrg      set_attrib_binding(glthread, vao,
5587ec681f3Smrg                         VERT_ATTRIB_GENERIC(attribindex),
5597ec681f3Smrg                         VERT_ATTRIB_GENERIC(bindingindex));
5607ec681f3Smrg   }
5617ec681f3Smrg}
5627ec681f3Smrg
5637ec681f3Smrgvoid
5647ec681f3Smrg_mesa_glthread_DSAElementBuffer(struct gl_context *ctx, GLuint vaobj,
5657ec681f3Smrg                                GLuint buffer)
5667ec681f3Smrg{
5677ec681f3Smrg   struct glthread_vao *vao = lookup_vao(ctx, vaobj);
5687ec681f3Smrg
5697ec681f3Smrg   if (vao)
5707ec681f3Smrg      vao->CurrentElementBufferName = buffer;
5717ec681f3Smrg}
5727ec681f3Smrg
5737ec681f3Smrgvoid
5747ec681f3Smrg_mesa_glthread_PushClientAttrib(struct gl_context *ctx, GLbitfield mask,
5757ec681f3Smrg                                bool set_default)
5767ec681f3Smrg{
5777ec681f3Smrg   struct glthread_state *glthread = &ctx->GLThread;
5787ec681f3Smrg
5797ec681f3Smrg   if (glthread->ClientAttribStackTop >= MAX_CLIENT_ATTRIB_STACK_DEPTH)
5807ec681f3Smrg      return;
5817ec681f3Smrg
5827ec681f3Smrg   struct glthread_client_attrib *top =
5837ec681f3Smrg      &glthread->ClientAttribStack[glthread->ClientAttribStackTop];
5847ec681f3Smrg
5857ec681f3Smrg   if (mask & GL_CLIENT_VERTEX_ARRAY_BIT) {
5867ec681f3Smrg      top->VAO = *glthread->CurrentVAO;
5877ec681f3Smrg      top->CurrentArrayBufferName = glthread->CurrentArrayBufferName;
5887ec681f3Smrg      top->ClientActiveTexture = glthread->ClientActiveTexture;
5897ec681f3Smrg      top->RestartIndex = glthread->RestartIndex;
5907ec681f3Smrg      top->PrimitiveRestart = glthread->PrimitiveRestart;
5917ec681f3Smrg      top->PrimitiveRestartFixedIndex = glthread->PrimitiveRestartFixedIndex;
5927ec681f3Smrg      top->Valid = true;
5937ec681f3Smrg   } else {
5947ec681f3Smrg      top->Valid = false;
5957ec681f3Smrg   }
5967ec681f3Smrg
5977ec681f3Smrg   glthread->ClientAttribStackTop++;
5987ec681f3Smrg
5997ec681f3Smrg   if (set_default)
6007ec681f3Smrg      _mesa_glthread_ClientAttribDefault(ctx, mask);
6017ec681f3Smrg}
6027ec681f3Smrg
6037ec681f3Smrgvoid
6047ec681f3Smrg_mesa_glthread_PopClientAttrib(struct gl_context *ctx)
6057ec681f3Smrg{
6067ec681f3Smrg   struct glthread_state *glthread = &ctx->GLThread;
6077ec681f3Smrg
6087ec681f3Smrg   if (glthread->ClientAttribStackTop == 0)
6097ec681f3Smrg      return;
6107ec681f3Smrg
6117ec681f3Smrg   glthread->ClientAttribStackTop--;
6127ec681f3Smrg
6137ec681f3Smrg   struct glthread_client_attrib *top =
6147ec681f3Smrg      &glthread->ClientAttribStack[glthread->ClientAttribStackTop];
6157ec681f3Smrg
6167ec681f3Smrg   if (!top->Valid)
6177ec681f3Smrg      return;
6187ec681f3Smrg
6197ec681f3Smrg   /* Popping a delete VAO is an error. */
6207ec681f3Smrg   struct glthread_vao *vao = NULL;
6217ec681f3Smrg   if (top->VAO.Name) {
6227ec681f3Smrg      vao = lookup_vao(ctx, top->VAO.Name);
6237ec681f3Smrg      if (!vao)
6247ec681f3Smrg         return;
6257ec681f3Smrg   }
6267ec681f3Smrg
6277ec681f3Smrg   /* Restore states. */
6287ec681f3Smrg   glthread->CurrentArrayBufferName = top->CurrentArrayBufferName;
6297ec681f3Smrg   glthread->ClientActiveTexture = top->ClientActiveTexture;
6307ec681f3Smrg   glthread->RestartIndex = top->RestartIndex;
6317ec681f3Smrg   glthread->PrimitiveRestart = top->PrimitiveRestart;
6327ec681f3Smrg   glthread->PrimitiveRestartFixedIndex = top->PrimitiveRestartFixedIndex;
6337ec681f3Smrg
6347ec681f3Smrg   if (!vao)
6357ec681f3Smrg      vao = &glthread->DefaultVAO;
6367ec681f3Smrg
6377ec681f3Smrg   assert(top->VAO.Name == vao->Name);
6387ec681f3Smrg   *vao = top->VAO; /* Copy all fields. */
6397ec681f3Smrg   glthread->CurrentVAO = vao;
6407ec681f3Smrg}
6417ec681f3Smrg
6427ec681f3Smrgvoid
6437ec681f3Smrg_mesa_glthread_ClientAttribDefault(struct gl_context *ctx, GLbitfield mask)
6447ec681f3Smrg{
6457ec681f3Smrg   struct glthread_state *glthread = &ctx->GLThread;
6467ec681f3Smrg
6477ec681f3Smrg   if (!(mask & GL_CLIENT_VERTEX_ARRAY_BIT))
6487ec681f3Smrg      return;
6497ec681f3Smrg
6507ec681f3Smrg   glthread->CurrentArrayBufferName = 0;
6517ec681f3Smrg   glthread->ClientActiveTexture = 0;
6527ec681f3Smrg   glthread->RestartIndex = 0;
6537ec681f3Smrg   glthread->PrimitiveRestart = false;
6547ec681f3Smrg   glthread->PrimitiveRestartFixedIndex = false;
6557ec681f3Smrg   glthread->CurrentVAO = &glthread->DefaultVAO;
6567ec681f3Smrg   _mesa_glthread_reset_vao(glthread->CurrentVAO);
6577ec681f3Smrg}
6587ec681f3Smrg
6597ec681f3Smrgvoid
6607ec681f3Smrg_mesa_glthread_InterleavedArrays(struct gl_context *ctx, GLenum format,
6617ec681f3Smrg                                 GLsizei stride, const GLvoid *pointer)
6627ec681f3Smrg{
6637ec681f3Smrg   struct gl_interleaved_layout layout;
6647ec681f3Smrg   unsigned tex = VERT_ATTRIB_TEX(ctx->GLThread.ClientActiveTexture);
6657ec681f3Smrg
6667ec681f3Smrg   if (stride < 0 || !_mesa_get_interleaved_layout(format, &layout))
6677ec681f3Smrg      return;
6687ec681f3Smrg
6697ec681f3Smrg   if (!stride)
6707ec681f3Smrg      stride = layout.defstride;
6717ec681f3Smrg
6727ec681f3Smrg   _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_EDGEFLAG, false);
6737ec681f3Smrg   _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_COLOR_INDEX, false);
6747ec681f3Smrg   /* XXX also disable secondary color and generic arrays? */
6757ec681f3Smrg
6767ec681f3Smrg   /* Texcoords */
6777ec681f3Smrg   if (layout.tflag) {
6787ec681f3Smrg      _mesa_glthread_ClientState(ctx, NULL, tex, true);
6797ec681f3Smrg      _mesa_glthread_AttribPointer(ctx, tex, layout.tcomps, GL_FLOAT, stride,
6807ec681f3Smrg                                   (GLubyte *) pointer + layout.toffset);
6817ec681f3Smrg   } else {
6827ec681f3Smrg      _mesa_glthread_ClientState(ctx, NULL, tex, false);
6837ec681f3Smrg   }
6847ec681f3Smrg
6857ec681f3Smrg   /* Color */
6867ec681f3Smrg   if (layout.cflag) {
6877ec681f3Smrg      _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_COLOR0, true);
6887ec681f3Smrg      _mesa_glthread_AttribPointer(ctx, VERT_ATTRIB_COLOR0, layout.ccomps,
6897ec681f3Smrg                                   layout.ctype, stride,
6907ec681f3Smrg                                   (GLubyte *) pointer + layout.coffset);
6917ec681f3Smrg   } else {
6927ec681f3Smrg      _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_COLOR0, false);
6937ec681f3Smrg   }
6947ec681f3Smrg
6957ec681f3Smrg   /* Normals */
6967ec681f3Smrg   if (layout.nflag) {
6977ec681f3Smrg      _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_NORMAL, true);
6987ec681f3Smrg      _mesa_glthread_AttribPointer(ctx, VERT_ATTRIB_NORMAL, 3, GL_FLOAT,
6997ec681f3Smrg                                   stride, (GLubyte *) pointer + layout.noffset);
7007ec681f3Smrg   } else {
7017ec681f3Smrg      _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_NORMAL, false);
7027ec681f3Smrg   }
7037ec681f3Smrg
7047ec681f3Smrg   /* Vertices */
7057ec681f3Smrg   _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_POS, true);
7067ec681f3Smrg   _mesa_glthread_AttribPointer(ctx, VERT_ATTRIB_POS, layout.vcomps, GL_FLOAT,
7077ec681f3Smrg                                stride, (GLubyte *) pointer + layout.voffset);
7087ec681f3Smrg}
709