1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2020 Advanced Micro Devices, Inc.
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci/* This implements vertex array state tracking for glthread. It's separate
25bf215546Sopenharmony_ci * from the rest of Mesa. Only minimum functionality is implemented here
26bf215546Sopenharmony_ci * to serve glthread.
27bf215546Sopenharmony_ci */
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci#include "main/glthread.h"
30bf215546Sopenharmony_ci#include "main/glformats.h"
31bf215546Sopenharmony_ci#include "main/mtypes.h"
32bf215546Sopenharmony_ci#include "main/hash.h"
33bf215546Sopenharmony_ci#include "main/dispatch.h"
34bf215546Sopenharmony_ci#include "main/varray.h"
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_civoid
38bf215546Sopenharmony_ci_mesa_glthread_reset_vao(struct glthread_vao *vao)
39bf215546Sopenharmony_ci{
40bf215546Sopenharmony_ci   static unsigned default_elem_size[VERT_ATTRIB_MAX] = {
41bf215546Sopenharmony_ci      [VERT_ATTRIB_NORMAL] = 12,
42bf215546Sopenharmony_ci      [VERT_ATTRIB_COLOR1] = 12,
43bf215546Sopenharmony_ci      [VERT_ATTRIB_FOG] = 4,
44bf215546Sopenharmony_ci      [VERT_ATTRIB_COLOR_INDEX] = 4,
45bf215546Sopenharmony_ci      [VERT_ATTRIB_EDGEFLAG] = 1,
46bf215546Sopenharmony_ci      [VERT_ATTRIB_POINT_SIZE] = 4,
47bf215546Sopenharmony_ci   };
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_ci   vao->CurrentElementBufferName = 0;
50bf215546Sopenharmony_ci   vao->UserEnabled = 0;
51bf215546Sopenharmony_ci   vao->Enabled = 0;
52bf215546Sopenharmony_ci   vao->BufferEnabled = 0;
53bf215546Sopenharmony_ci   vao->UserPointerMask = 0;
54bf215546Sopenharmony_ci   vao->NonZeroDivisorMask = 0;
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_ci   for (unsigned i = 0; i < ARRAY_SIZE(vao->Attrib); i++) {
57bf215546Sopenharmony_ci      unsigned elem_size = default_elem_size[i];
58bf215546Sopenharmony_ci      if (!elem_size)
59bf215546Sopenharmony_ci         elem_size = 16;
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci      vao->Attrib[i].ElementSize = elem_size;
62bf215546Sopenharmony_ci      vao->Attrib[i].RelativeOffset = 0;
63bf215546Sopenharmony_ci      vao->Attrib[i].BufferIndex = i;
64bf215546Sopenharmony_ci      vao->Attrib[i].Stride = elem_size;
65bf215546Sopenharmony_ci      vao->Attrib[i].Divisor = 0;
66bf215546Sopenharmony_ci      vao->Attrib[i].EnabledAttribCount = 0;
67bf215546Sopenharmony_ci      vao->Attrib[i].Pointer = NULL;
68bf215546Sopenharmony_ci   }
69bf215546Sopenharmony_ci}
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_cistatic struct glthread_vao *
72bf215546Sopenharmony_cilookup_vao(struct gl_context *ctx, GLuint id)
73bf215546Sopenharmony_ci{
74bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
75bf215546Sopenharmony_ci   struct glthread_vao *vao;
76bf215546Sopenharmony_ci
77bf215546Sopenharmony_ci   assert(id != 0);
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_ci   if (glthread->LastLookedUpVAO &&
80bf215546Sopenharmony_ci       glthread->LastLookedUpVAO->Name == id) {
81bf215546Sopenharmony_ci      vao = glthread->LastLookedUpVAO;
82bf215546Sopenharmony_ci   } else {
83bf215546Sopenharmony_ci      vao = _mesa_HashLookupLocked(glthread->VAOs, id);
84bf215546Sopenharmony_ci      if (!vao)
85bf215546Sopenharmony_ci         return NULL;
86bf215546Sopenharmony_ci
87bf215546Sopenharmony_ci      glthread->LastLookedUpVAO = vao;
88bf215546Sopenharmony_ci   }
89bf215546Sopenharmony_ci
90bf215546Sopenharmony_ci   return vao;
91bf215546Sopenharmony_ci}
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_civoid
94bf215546Sopenharmony_ci_mesa_glthread_BindVertexArray(struct gl_context *ctx, GLuint id)
95bf215546Sopenharmony_ci{
96bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_ci   if (id == 0) {
99bf215546Sopenharmony_ci      glthread->CurrentVAO = &glthread->DefaultVAO;
100bf215546Sopenharmony_ci   } else {
101bf215546Sopenharmony_ci      struct glthread_vao *vao = lookup_vao(ctx, id);
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_ci      if (vao)
104bf215546Sopenharmony_ci         glthread->CurrentVAO = vao;
105bf215546Sopenharmony_ci   }
106bf215546Sopenharmony_ci}
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_civoid
109bf215546Sopenharmony_ci_mesa_glthread_DeleteVertexArrays(struct gl_context *ctx,
110bf215546Sopenharmony_ci                                  GLsizei n, const GLuint *ids)
111bf215546Sopenharmony_ci{
112bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
113bf215546Sopenharmony_ci
114bf215546Sopenharmony_ci   if (!ids)
115bf215546Sopenharmony_ci      return;
116bf215546Sopenharmony_ci
117bf215546Sopenharmony_ci   for (int i = 0; i < n; i++) {
118bf215546Sopenharmony_ci      /* IDs equal to 0 should be silently ignored. */
119bf215546Sopenharmony_ci      if (!ids[i])
120bf215546Sopenharmony_ci         continue;
121bf215546Sopenharmony_ci
122bf215546Sopenharmony_ci      struct glthread_vao *vao = lookup_vao(ctx, ids[i]);
123bf215546Sopenharmony_ci      if (!vao)
124bf215546Sopenharmony_ci         continue;
125bf215546Sopenharmony_ci
126bf215546Sopenharmony_ci      /* If the array object is currently bound, the spec says "the binding
127bf215546Sopenharmony_ci       * for that object reverts to zero and the default vertex array
128bf215546Sopenharmony_ci       * becomes current."
129bf215546Sopenharmony_ci       */
130bf215546Sopenharmony_ci      if (glthread->CurrentVAO == vao)
131bf215546Sopenharmony_ci         glthread->CurrentVAO = &glthread->DefaultVAO;
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_ci      if (glthread->LastLookedUpVAO == vao)
134bf215546Sopenharmony_ci         glthread->LastLookedUpVAO = NULL;
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ci      /* The ID is immediately freed for re-use */
137bf215546Sopenharmony_ci      _mesa_HashRemoveLocked(glthread->VAOs, vao->Name);
138bf215546Sopenharmony_ci      free(vao);
139bf215546Sopenharmony_ci   }
140bf215546Sopenharmony_ci}
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_civoid
143bf215546Sopenharmony_ci_mesa_glthread_GenVertexArrays(struct gl_context *ctx,
144bf215546Sopenharmony_ci                               GLsizei n, GLuint *arrays)
145bf215546Sopenharmony_ci{
146bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_ci   if (!arrays)
149bf215546Sopenharmony_ci      return;
150bf215546Sopenharmony_ci
151bf215546Sopenharmony_ci   /* The IDs have been generated at this point. Create VAOs for glthread. */
152bf215546Sopenharmony_ci   for (int i = 0; i < n; i++) {
153bf215546Sopenharmony_ci      GLuint id = arrays[i];
154bf215546Sopenharmony_ci      struct glthread_vao *vao;
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_ci      vao = calloc(1, sizeof(*vao));
157bf215546Sopenharmony_ci      if (!vao)
158bf215546Sopenharmony_ci         continue; /* Is that all we can do? */
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci      vao->Name = id;
161bf215546Sopenharmony_ci      _mesa_glthread_reset_vao(vao);
162bf215546Sopenharmony_ci      _mesa_HashInsertLocked(glthread->VAOs, id, vao, true);
163bf215546Sopenharmony_ci   }
164bf215546Sopenharmony_ci}
165bf215546Sopenharmony_ci
166bf215546Sopenharmony_ci/* If vaobj is NULL, use the currently-bound VAO. */
167bf215546Sopenharmony_cistatic inline struct glthread_vao *
168bf215546Sopenharmony_ciget_vao(struct gl_context *ctx, const GLuint *vaobj)
169bf215546Sopenharmony_ci{
170bf215546Sopenharmony_ci   if (vaobj)
171bf215546Sopenharmony_ci      return lookup_vao(ctx, *vaobj);
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ci   return ctx->GLThread.CurrentVAO;
174bf215546Sopenharmony_ci}
175bf215546Sopenharmony_ci
176bf215546Sopenharmony_cistatic void
177bf215546Sopenharmony_ciupdate_primitive_restart(struct gl_context *ctx)
178bf215546Sopenharmony_ci{
179bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
180bf215546Sopenharmony_ci
181bf215546Sopenharmony_ci   glthread->_PrimitiveRestart = glthread->PrimitiveRestart ||
182bf215546Sopenharmony_ci                                 glthread->PrimitiveRestartFixedIndex;
183bf215546Sopenharmony_ci   glthread->_RestartIndex[0] =
184bf215546Sopenharmony_ci      _mesa_get_prim_restart_index(glthread->PrimitiveRestartFixedIndex,
185bf215546Sopenharmony_ci                                   glthread->RestartIndex, 1);
186bf215546Sopenharmony_ci   glthread->_RestartIndex[1] =
187bf215546Sopenharmony_ci      _mesa_get_prim_restart_index(glthread->PrimitiveRestartFixedIndex,
188bf215546Sopenharmony_ci                                   glthread->RestartIndex, 2);
189bf215546Sopenharmony_ci   glthread->_RestartIndex[3] =
190bf215546Sopenharmony_ci      _mesa_get_prim_restart_index(glthread->PrimitiveRestartFixedIndex,
191bf215546Sopenharmony_ci                                   glthread->RestartIndex, 4);
192bf215546Sopenharmony_ci}
193bf215546Sopenharmony_ci
194bf215546Sopenharmony_civoid
195bf215546Sopenharmony_ci_mesa_glthread_set_prim_restart(struct gl_context *ctx, GLenum cap, bool value)
196bf215546Sopenharmony_ci{
197bf215546Sopenharmony_ci   switch (cap) {
198bf215546Sopenharmony_ci   case GL_PRIMITIVE_RESTART:
199bf215546Sopenharmony_ci      ctx->GLThread.PrimitiveRestart = value;
200bf215546Sopenharmony_ci      break;
201bf215546Sopenharmony_ci   case GL_PRIMITIVE_RESTART_FIXED_INDEX:
202bf215546Sopenharmony_ci      ctx->GLThread.PrimitiveRestartFixedIndex = value;
203bf215546Sopenharmony_ci      break;
204bf215546Sopenharmony_ci   }
205bf215546Sopenharmony_ci
206bf215546Sopenharmony_ci   update_primitive_restart(ctx);
207bf215546Sopenharmony_ci}
208bf215546Sopenharmony_ci
209bf215546Sopenharmony_civoid
210bf215546Sopenharmony_ci_mesa_glthread_PrimitiveRestartIndex(struct gl_context *ctx, GLuint index)
211bf215546Sopenharmony_ci{
212bf215546Sopenharmony_ci   ctx->GLThread.RestartIndex = index;
213bf215546Sopenharmony_ci   update_primitive_restart(ctx);
214bf215546Sopenharmony_ci}
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_cistatic inline void
217bf215546Sopenharmony_cienable_buffer(struct glthread_vao *vao, unsigned binding_index)
218bf215546Sopenharmony_ci{
219bf215546Sopenharmony_ci   int attrib_count = ++vao->Attrib[binding_index].EnabledAttribCount;
220bf215546Sopenharmony_ci
221bf215546Sopenharmony_ci   if (attrib_count == 1)
222bf215546Sopenharmony_ci      vao->BufferEnabled |= 1 << binding_index;
223bf215546Sopenharmony_ci   else if (attrib_count == 2)
224bf215546Sopenharmony_ci      vao->BufferInterleaved |= 1 << binding_index;
225bf215546Sopenharmony_ci}
226bf215546Sopenharmony_ci
227bf215546Sopenharmony_cistatic inline void
228bf215546Sopenharmony_cidisable_buffer(struct glthread_vao *vao, unsigned binding_index)
229bf215546Sopenharmony_ci{
230bf215546Sopenharmony_ci   int attrib_count = --vao->Attrib[binding_index].EnabledAttribCount;
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_ci   if (attrib_count == 0)
233bf215546Sopenharmony_ci      vao->BufferEnabled &= ~(1 << binding_index);
234bf215546Sopenharmony_ci   else if (attrib_count == 1)
235bf215546Sopenharmony_ci      vao->BufferInterleaved &= ~(1 << binding_index);
236bf215546Sopenharmony_ci   else
237bf215546Sopenharmony_ci      assert(attrib_count >= 0);
238bf215546Sopenharmony_ci}
239bf215546Sopenharmony_ci
240bf215546Sopenharmony_civoid
241bf215546Sopenharmony_ci_mesa_glthread_ClientState(struct gl_context *ctx, GLuint *vaobj,
242bf215546Sopenharmony_ci                           gl_vert_attrib attrib, bool enable)
243bf215546Sopenharmony_ci{
244bf215546Sopenharmony_ci   /* The primitive restart client state uses a special value. */
245bf215546Sopenharmony_ci   if (attrib == VERT_ATTRIB_PRIMITIVE_RESTART_NV) {
246bf215546Sopenharmony_ci      ctx->GLThread.PrimitiveRestart = enable;
247bf215546Sopenharmony_ci      update_primitive_restart(ctx);
248bf215546Sopenharmony_ci      return;
249bf215546Sopenharmony_ci   }
250bf215546Sopenharmony_ci
251bf215546Sopenharmony_ci   if (attrib >= VERT_ATTRIB_MAX)
252bf215546Sopenharmony_ci      return;
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci   struct glthread_vao *vao = get_vao(ctx, vaobj);
255bf215546Sopenharmony_ci   if (!vao)
256bf215546Sopenharmony_ci      return;
257bf215546Sopenharmony_ci
258bf215546Sopenharmony_ci   const unsigned attrib_bit = 1u << attrib;
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ci   if (enable && !(vao->UserEnabled & attrib_bit)) {
261bf215546Sopenharmony_ci      vao->UserEnabled |= attrib_bit;
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_ci      /* The generic0 attribute supersedes the position attribute. We need to
264bf215546Sopenharmony_ci       * update BufferBindingEnabled accordingly.
265bf215546Sopenharmony_ci       */
266bf215546Sopenharmony_ci      if (attrib == VERT_ATTRIB_POS) {
267bf215546Sopenharmony_ci         if (!(vao->UserEnabled & VERT_BIT_GENERIC0))
268bf215546Sopenharmony_ci            enable_buffer(vao, vao->Attrib[VERT_ATTRIB_POS].BufferIndex);
269bf215546Sopenharmony_ci      } else {
270bf215546Sopenharmony_ci         enable_buffer(vao, vao->Attrib[attrib].BufferIndex);
271bf215546Sopenharmony_ci
272bf215546Sopenharmony_ci         if (attrib == VERT_ATTRIB_GENERIC0 && vao->UserEnabled & VERT_BIT_POS)
273bf215546Sopenharmony_ci            disable_buffer(vao, vao->Attrib[VERT_ATTRIB_POS].BufferIndex);
274bf215546Sopenharmony_ci      }
275bf215546Sopenharmony_ci   } else if (!enable && (vao->UserEnabled & attrib_bit)) {
276bf215546Sopenharmony_ci      vao->UserEnabled &= ~attrib_bit;
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_ci      /* The generic0 attribute supersedes the position attribute. We need to
279bf215546Sopenharmony_ci       * update BufferBindingEnabled accordingly.
280bf215546Sopenharmony_ci       */
281bf215546Sopenharmony_ci      if (attrib == VERT_ATTRIB_POS) {
282bf215546Sopenharmony_ci         if (!(vao->UserEnabled & VERT_BIT_GENERIC0))
283bf215546Sopenharmony_ci            disable_buffer(vao, vao->Attrib[VERT_ATTRIB_POS].BufferIndex);
284bf215546Sopenharmony_ci      } else {
285bf215546Sopenharmony_ci         disable_buffer(vao, vao->Attrib[attrib].BufferIndex);
286bf215546Sopenharmony_ci
287bf215546Sopenharmony_ci         if (attrib == VERT_ATTRIB_GENERIC0 && vao->UserEnabled & VERT_BIT_POS)
288bf215546Sopenharmony_ci            enable_buffer(vao, vao->Attrib[VERT_ATTRIB_POS].BufferIndex);
289bf215546Sopenharmony_ci      }
290bf215546Sopenharmony_ci   }
291bf215546Sopenharmony_ci
292bf215546Sopenharmony_ci   /* The generic0 attribute supersedes the position attribute. */
293bf215546Sopenharmony_ci   vao->Enabled = vao->UserEnabled;
294bf215546Sopenharmony_ci   if (vao->Enabled & VERT_BIT_GENERIC0)
295bf215546Sopenharmony_ci      vao->Enabled &= ~VERT_BIT_POS;
296bf215546Sopenharmony_ci}
297bf215546Sopenharmony_ci
298bf215546Sopenharmony_cistatic void
299bf215546Sopenharmony_ciset_attrib_binding(struct glthread_state *glthread, struct glthread_vao *vao,
300bf215546Sopenharmony_ci                   gl_vert_attrib attrib, unsigned new_binding_index)
301bf215546Sopenharmony_ci{
302bf215546Sopenharmony_ci   unsigned old_binding_index = vao->Attrib[attrib].BufferIndex;
303bf215546Sopenharmony_ci
304bf215546Sopenharmony_ci   if (old_binding_index != new_binding_index) {
305bf215546Sopenharmony_ci      vao->Attrib[attrib].BufferIndex = new_binding_index;
306bf215546Sopenharmony_ci
307bf215546Sopenharmony_ci      if (vao->Enabled & (1u << attrib)) {
308bf215546Sopenharmony_ci         /* Update BufferBindingEnabled. */
309bf215546Sopenharmony_ci         enable_buffer(vao, new_binding_index);
310bf215546Sopenharmony_ci         disable_buffer(vao, old_binding_index);
311bf215546Sopenharmony_ci      }
312bf215546Sopenharmony_ci   }
313bf215546Sopenharmony_ci}
314bf215546Sopenharmony_ci
315bf215546Sopenharmony_civoid _mesa_glthread_AttribDivisor(struct gl_context *ctx, const GLuint *vaobj,
316bf215546Sopenharmony_ci                                  gl_vert_attrib attrib, GLuint divisor)
317bf215546Sopenharmony_ci{
318bf215546Sopenharmony_ci   if (attrib >= VERT_ATTRIB_MAX)
319bf215546Sopenharmony_ci      return;
320bf215546Sopenharmony_ci
321bf215546Sopenharmony_ci   struct glthread_vao *vao = get_vao(ctx, vaobj);
322bf215546Sopenharmony_ci   if (!vao)
323bf215546Sopenharmony_ci      return;
324bf215546Sopenharmony_ci
325bf215546Sopenharmony_ci   vao->Attrib[attrib].Divisor = divisor;
326bf215546Sopenharmony_ci
327bf215546Sopenharmony_ci   set_attrib_binding(&ctx->GLThread, vao, attrib, attrib);
328bf215546Sopenharmony_ci
329bf215546Sopenharmony_ci   if (divisor)
330bf215546Sopenharmony_ci      vao->NonZeroDivisorMask |= 1u << attrib;
331bf215546Sopenharmony_ci   else
332bf215546Sopenharmony_ci      vao->NonZeroDivisorMask &= ~(1u << attrib);
333bf215546Sopenharmony_ci}
334bf215546Sopenharmony_ci
335bf215546Sopenharmony_cistatic unsigned
336bf215546Sopenharmony_cielement_size(GLint size, GLenum type)
337bf215546Sopenharmony_ci{
338bf215546Sopenharmony_ci   if (size == GL_BGRA)
339bf215546Sopenharmony_ci      size = 4;
340bf215546Sopenharmony_ci
341bf215546Sopenharmony_ci   return _mesa_bytes_per_vertex_attrib(size, type);
342bf215546Sopenharmony_ci}
343bf215546Sopenharmony_ci
344bf215546Sopenharmony_cistatic void
345bf215546Sopenharmony_ciattrib_pointer(struct glthread_state *glthread, struct glthread_vao *vao,
346bf215546Sopenharmony_ci               GLuint buffer, gl_vert_attrib attrib,
347bf215546Sopenharmony_ci               GLint size, GLenum type, GLsizei stride,
348bf215546Sopenharmony_ci               const void *pointer)
349bf215546Sopenharmony_ci{
350bf215546Sopenharmony_ci   if (attrib >= VERT_ATTRIB_MAX)
351bf215546Sopenharmony_ci      return;
352bf215546Sopenharmony_ci
353bf215546Sopenharmony_ci   unsigned elem_size = element_size(size, type);
354bf215546Sopenharmony_ci
355bf215546Sopenharmony_ci   vao->Attrib[attrib].ElementSize = elem_size;
356bf215546Sopenharmony_ci   vao->Attrib[attrib].Stride = stride ? stride : elem_size;
357bf215546Sopenharmony_ci   vao->Attrib[attrib].Pointer = pointer;
358bf215546Sopenharmony_ci   vao->Attrib[attrib].RelativeOffset = 0;
359bf215546Sopenharmony_ci
360bf215546Sopenharmony_ci   set_attrib_binding(glthread, vao, attrib, attrib);
361bf215546Sopenharmony_ci
362bf215546Sopenharmony_ci   if (buffer != 0)
363bf215546Sopenharmony_ci      vao->UserPointerMask &= ~(1u << attrib);
364bf215546Sopenharmony_ci   else
365bf215546Sopenharmony_ci      vao->UserPointerMask |= 1u << attrib;
366bf215546Sopenharmony_ci}
367bf215546Sopenharmony_ci
368bf215546Sopenharmony_civoid
369bf215546Sopenharmony_ci_mesa_glthread_AttribPointer(struct gl_context *ctx, gl_vert_attrib attrib,
370bf215546Sopenharmony_ci                             GLint size, GLenum type, GLsizei stride,
371bf215546Sopenharmony_ci                             const void *pointer)
372bf215546Sopenharmony_ci{
373bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
374bf215546Sopenharmony_ci
375bf215546Sopenharmony_ci   attrib_pointer(glthread, glthread->CurrentVAO,
376bf215546Sopenharmony_ci                  glthread->CurrentArrayBufferName,
377bf215546Sopenharmony_ci                  attrib, size, type, stride, pointer);
378bf215546Sopenharmony_ci}
379bf215546Sopenharmony_ci
380bf215546Sopenharmony_civoid
381bf215546Sopenharmony_ci_mesa_glthread_DSAAttribPointer(struct gl_context *ctx, GLuint vaobj,
382bf215546Sopenharmony_ci                                GLuint buffer, gl_vert_attrib attrib,
383bf215546Sopenharmony_ci                                GLint size, GLenum type, GLsizei stride,
384bf215546Sopenharmony_ci                                GLintptr offset)
385bf215546Sopenharmony_ci{
386bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
387bf215546Sopenharmony_ci   struct glthread_vao *vao;
388bf215546Sopenharmony_ci
389bf215546Sopenharmony_ci   vao = lookup_vao(ctx, vaobj);
390bf215546Sopenharmony_ci   if (!vao)
391bf215546Sopenharmony_ci      return;
392bf215546Sopenharmony_ci
393bf215546Sopenharmony_ci   attrib_pointer(glthread, vao, buffer, attrib, size, type, stride,
394bf215546Sopenharmony_ci                  (const void*)offset);
395bf215546Sopenharmony_ci}
396bf215546Sopenharmony_ci
397bf215546Sopenharmony_cistatic void
398bf215546Sopenharmony_ciattrib_format(struct glthread_state *glthread, struct glthread_vao *vao,
399bf215546Sopenharmony_ci              GLuint attribindex, GLint size, GLenum type,
400bf215546Sopenharmony_ci              GLuint relativeoffset)
401bf215546Sopenharmony_ci{
402bf215546Sopenharmony_ci   if (attribindex >= VERT_ATTRIB_GENERIC_MAX)
403bf215546Sopenharmony_ci      return;
404bf215546Sopenharmony_ci
405bf215546Sopenharmony_ci   unsigned elem_size = element_size(size, type);
406bf215546Sopenharmony_ci
407bf215546Sopenharmony_ci   unsigned i = VERT_ATTRIB_GENERIC(attribindex);
408bf215546Sopenharmony_ci   vao->Attrib[i].ElementSize = elem_size;
409bf215546Sopenharmony_ci   vao->Attrib[i].RelativeOffset = relativeoffset;
410bf215546Sopenharmony_ci}
411bf215546Sopenharmony_ci
412bf215546Sopenharmony_civoid
413bf215546Sopenharmony_ci_mesa_glthread_AttribFormat(struct gl_context *ctx, GLuint attribindex,
414bf215546Sopenharmony_ci                            GLint size, GLenum type, GLuint relativeoffset)
415bf215546Sopenharmony_ci{
416bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
417bf215546Sopenharmony_ci
418bf215546Sopenharmony_ci   attrib_format(glthread, glthread->CurrentVAO, attribindex, size, type,
419bf215546Sopenharmony_ci                 relativeoffset);
420bf215546Sopenharmony_ci}
421bf215546Sopenharmony_ci
422bf215546Sopenharmony_civoid
423bf215546Sopenharmony_ci_mesa_glthread_DSAAttribFormat(struct gl_context *ctx, GLuint vaobj,
424bf215546Sopenharmony_ci                               GLuint attribindex, GLint size, GLenum type,
425bf215546Sopenharmony_ci                               GLuint relativeoffset)
426bf215546Sopenharmony_ci{
427bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
428bf215546Sopenharmony_ci   struct glthread_vao *vao = lookup_vao(ctx, vaobj);
429bf215546Sopenharmony_ci
430bf215546Sopenharmony_ci   if (vao)
431bf215546Sopenharmony_ci      attrib_format(glthread, vao, attribindex, size, type, relativeoffset);
432bf215546Sopenharmony_ci}
433bf215546Sopenharmony_ci
434bf215546Sopenharmony_cistatic void
435bf215546Sopenharmony_cibind_vertex_buffer(struct glthread_state *glthread, struct glthread_vao *vao,
436bf215546Sopenharmony_ci                   GLuint bindingindex, GLuint buffer, GLintptr offset,
437bf215546Sopenharmony_ci                   GLsizei stride)
438bf215546Sopenharmony_ci{
439bf215546Sopenharmony_ci   if (bindingindex >= VERT_ATTRIB_GENERIC_MAX)
440bf215546Sopenharmony_ci      return;
441bf215546Sopenharmony_ci
442bf215546Sopenharmony_ci   unsigned i = VERT_ATTRIB_GENERIC(bindingindex);
443bf215546Sopenharmony_ci   vao->Attrib[i].Pointer = (const void*)offset;
444bf215546Sopenharmony_ci   vao->Attrib[i].Stride = stride;
445bf215546Sopenharmony_ci
446bf215546Sopenharmony_ci   if (buffer != 0)
447bf215546Sopenharmony_ci      vao->UserPointerMask &= ~(1u << i);
448bf215546Sopenharmony_ci   else
449bf215546Sopenharmony_ci      vao->UserPointerMask |= 1u << i;
450bf215546Sopenharmony_ci}
451bf215546Sopenharmony_ci
452bf215546Sopenharmony_civoid
453bf215546Sopenharmony_ci_mesa_glthread_VertexBuffer(struct gl_context *ctx, GLuint bindingindex,
454bf215546Sopenharmony_ci                            GLuint buffer, GLintptr offset, GLsizei stride)
455bf215546Sopenharmony_ci{
456bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
457bf215546Sopenharmony_ci
458bf215546Sopenharmony_ci   bind_vertex_buffer(glthread, glthread->CurrentVAO, bindingindex, buffer,
459bf215546Sopenharmony_ci                      offset, stride);
460bf215546Sopenharmony_ci}
461bf215546Sopenharmony_ci
462bf215546Sopenharmony_civoid
463bf215546Sopenharmony_ci_mesa_glthread_DSAVertexBuffer(struct gl_context *ctx, GLuint vaobj,
464bf215546Sopenharmony_ci                               GLuint bindingindex, GLuint buffer,
465bf215546Sopenharmony_ci                               GLintptr offset, GLsizei stride)
466bf215546Sopenharmony_ci{
467bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
468bf215546Sopenharmony_ci   struct glthread_vao *vao = lookup_vao(ctx, vaobj);
469bf215546Sopenharmony_ci
470bf215546Sopenharmony_ci   if (vao)
471bf215546Sopenharmony_ci      bind_vertex_buffer(glthread, vao, bindingindex, buffer, offset, stride);
472bf215546Sopenharmony_ci}
473bf215546Sopenharmony_ci
474bf215546Sopenharmony_civoid
475bf215546Sopenharmony_ci_mesa_glthread_DSAVertexBuffers(struct gl_context *ctx, GLuint vaobj,
476bf215546Sopenharmony_ci                                GLuint first, GLsizei count,
477bf215546Sopenharmony_ci                                const GLuint *buffers,
478bf215546Sopenharmony_ci                                const GLintptr *offsets,
479bf215546Sopenharmony_ci                                const GLsizei *strides)
480bf215546Sopenharmony_ci{
481bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
482bf215546Sopenharmony_ci   struct glthread_vao *vao;
483bf215546Sopenharmony_ci
484bf215546Sopenharmony_ci   vao = lookup_vao(ctx, vaobj);
485bf215546Sopenharmony_ci   if (!vao)
486bf215546Sopenharmony_ci      return;
487bf215546Sopenharmony_ci
488bf215546Sopenharmony_ci   for (unsigned i = 0; i < count; i++) {
489bf215546Sopenharmony_ci      bind_vertex_buffer(glthread, vao, first + i, buffers[i], offsets[i],
490bf215546Sopenharmony_ci                         strides[i]);
491bf215546Sopenharmony_ci   }
492bf215546Sopenharmony_ci}
493bf215546Sopenharmony_ci
494bf215546Sopenharmony_cistatic void
495bf215546Sopenharmony_cibinding_divisor(struct glthread_state *glthread, struct glthread_vao *vao,
496bf215546Sopenharmony_ci                GLuint bindingindex, GLuint divisor)
497bf215546Sopenharmony_ci{
498bf215546Sopenharmony_ci   if (bindingindex >= VERT_ATTRIB_GENERIC_MAX)
499bf215546Sopenharmony_ci      return;
500bf215546Sopenharmony_ci
501bf215546Sopenharmony_ci   unsigned i = VERT_ATTRIB_GENERIC(bindingindex);
502bf215546Sopenharmony_ci   vao->Attrib[i].Divisor = divisor;
503bf215546Sopenharmony_ci
504bf215546Sopenharmony_ci   if (divisor)
505bf215546Sopenharmony_ci      vao->NonZeroDivisorMask |= 1u << i;
506bf215546Sopenharmony_ci   else
507bf215546Sopenharmony_ci      vao->NonZeroDivisorMask &= ~(1u << i);
508bf215546Sopenharmony_ci}
509bf215546Sopenharmony_ci
510bf215546Sopenharmony_civoid
511bf215546Sopenharmony_ci_mesa_glthread_BindingDivisor(struct gl_context *ctx, GLuint bindingindex,
512bf215546Sopenharmony_ci                              GLuint divisor)
513bf215546Sopenharmony_ci{
514bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
515bf215546Sopenharmony_ci
516bf215546Sopenharmony_ci   binding_divisor(glthread, glthread->CurrentVAO, bindingindex, divisor);
517bf215546Sopenharmony_ci}
518bf215546Sopenharmony_ci
519bf215546Sopenharmony_civoid
520bf215546Sopenharmony_ci_mesa_glthread_DSABindingDivisor(struct gl_context *ctx, GLuint vaobj,
521bf215546Sopenharmony_ci                                 GLuint bindingindex, GLuint divisor)
522bf215546Sopenharmony_ci{
523bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
524bf215546Sopenharmony_ci   struct glthread_vao *vao = lookup_vao(ctx, vaobj);
525bf215546Sopenharmony_ci
526bf215546Sopenharmony_ci   if (vao)
527bf215546Sopenharmony_ci      binding_divisor(glthread, vao, bindingindex, divisor);
528bf215546Sopenharmony_ci}
529bf215546Sopenharmony_ci
530bf215546Sopenharmony_civoid
531bf215546Sopenharmony_ci_mesa_glthread_AttribBinding(struct gl_context *ctx, GLuint attribindex,
532bf215546Sopenharmony_ci                             GLuint bindingindex)
533bf215546Sopenharmony_ci{
534bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
535bf215546Sopenharmony_ci
536bf215546Sopenharmony_ci   if (attribindex >= VERT_ATTRIB_GENERIC_MAX ||
537bf215546Sopenharmony_ci       bindingindex >= VERT_ATTRIB_GENERIC_MAX)
538bf215546Sopenharmony_ci      return;
539bf215546Sopenharmony_ci
540bf215546Sopenharmony_ci   set_attrib_binding(glthread, glthread->CurrentVAO,
541bf215546Sopenharmony_ci                      VERT_ATTRIB_GENERIC(attribindex),
542bf215546Sopenharmony_ci                      VERT_ATTRIB_GENERIC(bindingindex));
543bf215546Sopenharmony_ci}
544bf215546Sopenharmony_ci
545bf215546Sopenharmony_civoid
546bf215546Sopenharmony_ci_mesa_glthread_DSAAttribBinding(struct gl_context *ctx, GLuint vaobj,
547bf215546Sopenharmony_ci                                GLuint attribindex, GLuint bindingindex)
548bf215546Sopenharmony_ci{
549bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
550bf215546Sopenharmony_ci
551bf215546Sopenharmony_ci   if (attribindex >= VERT_ATTRIB_GENERIC_MAX ||
552bf215546Sopenharmony_ci       bindingindex >= VERT_ATTRIB_GENERIC_MAX)
553bf215546Sopenharmony_ci      return;
554bf215546Sopenharmony_ci
555bf215546Sopenharmony_ci   struct glthread_vao *vao = lookup_vao(ctx, vaobj);
556bf215546Sopenharmony_ci   if (vao) {
557bf215546Sopenharmony_ci      set_attrib_binding(glthread, vao,
558bf215546Sopenharmony_ci                         VERT_ATTRIB_GENERIC(attribindex),
559bf215546Sopenharmony_ci                         VERT_ATTRIB_GENERIC(bindingindex));
560bf215546Sopenharmony_ci   }
561bf215546Sopenharmony_ci}
562bf215546Sopenharmony_ci
563bf215546Sopenharmony_civoid
564bf215546Sopenharmony_ci_mesa_glthread_DSAElementBuffer(struct gl_context *ctx, GLuint vaobj,
565bf215546Sopenharmony_ci                                GLuint buffer)
566bf215546Sopenharmony_ci{
567bf215546Sopenharmony_ci   struct glthread_vao *vao = lookup_vao(ctx, vaobj);
568bf215546Sopenharmony_ci
569bf215546Sopenharmony_ci   if (vao)
570bf215546Sopenharmony_ci      vao->CurrentElementBufferName = buffer;
571bf215546Sopenharmony_ci}
572bf215546Sopenharmony_ci
573bf215546Sopenharmony_civoid
574bf215546Sopenharmony_ci_mesa_glthread_PushClientAttrib(struct gl_context *ctx, GLbitfield mask,
575bf215546Sopenharmony_ci                                bool set_default)
576bf215546Sopenharmony_ci{
577bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
578bf215546Sopenharmony_ci
579bf215546Sopenharmony_ci   if (glthread->ClientAttribStackTop >= MAX_CLIENT_ATTRIB_STACK_DEPTH)
580bf215546Sopenharmony_ci      return;
581bf215546Sopenharmony_ci
582bf215546Sopenharmony_ci   struct glthread_client_attrib *top =
583bf215546Sopenharmony_ci      &glthread->ClientAttribStack[glthread->ClientAttribStackTop];
584bf215546Sopenharmony_ci
585bf215546Sopenharmony_ci   if (mask & GL_CLIENT_VERTEX_ARRAY_BIT) {
586bf215546Sopenharmony_ci      top->VAO = *glthread->CurrentVAO;
587bf215546Sopenharmony_ci      top->CurrentArrayBufferName = glthread->CurrentArrayBufferName;
588bf215546Sopenharmony_ci      top->ClientActiveTexture = glthread->ClientActiveTexture;
589bf215546Sopenharmony_ci      top->RestartIndex = glthread->RestartIndex;
590bf215546Sopenharmony_ci      top->PrimitiveRestart = glthread->PrimitiveRestart;
591bf215546Sopenharmony_ci      top->PrimitiveRestartFixedIndex = glthread->PrimitiveRestartFixedIndex;
592bf215546Sopenharmony_ci      top->Valid = true;
593bf215546Sopenharmony_ci   } else {
594bf215546Sopenharmony_ci      top->Valid = false;
595bf215546Sopenharmony_ci   }
596bf215546Sopenharmony_ci
597bf215546Sopenharmony_ci   glthread->ClientAttribStackTop++;
598bf215546Sopenharmony_ci
599bf215546Sopenharmony_ci   if (set_default)
600bf215546Sopenharmony_ci      _mesa_glthread_ClientAttribDefault(ctx, mask);
601bf215546Sopenharmony_ci}
602bf215546Sopenharmony_ci
603bf215546Sopenharmony_civoid
604bf215546Sopenharmony_ci_mesa_glthread_PopClientAttrib(struct gl_context *ctx)
605bf215546Sopenharmony_ci{
606bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
607bf215546Sopenharmony_ci
608bf215546Sopenharmony_ci   if (glthread->ClientAttribStackTop == 0)
609bf215546Sopenharmony_ci      return;
610bf215546Sopenharmony_ci
611bf215546Sopenharmony_ci   glthread->ClientAttribStackTop--;
612bf215546Sopenharmony_ci
613bf215546Sopenharmony_ci   struct glthread_client_attrib *top =
614bf215546Sopenharmony_ci      &glthread->ClientAttribStack[glthread->ClientAttribStackTop];
615bf215546Sopenharmony_ci
616bf215546Sopenharmony_ci   if (!top->Valid)
617bf215546Sopenharmony_ci      return;
618bf215546Sopenharmony_ci
619bf215546Sopenharmony_ci   /* Popping a delete VAO is an error. */
620bf215546Sopenharmony_ci   struct glthread_vao *vao = NULL;
621bf215546Sopenharmony_ci   if (top->VAO.Name) {
622bf215546Sopenharmony_ci      vao = lookup_vao(ctx, top->VAO.Name);
623bf215546Sopenharmony_ci      if (!vao)
624bf215546Sopenharmony_ci         return;
625bf215546Sopenharmony_ci   }
626bf215546Sopenharmony_ci
627bf215546Sopenharmony_ci   /* Restore states. */
628bf215546Sopenharmony_ci   glthread->CurrentArrayBufferName = top->CurrentArrayBufferName;
629bf215546Sopenharmony_ci   glthread->ClientActiveTexture = top->ClientActiveTexture;
630bf215546Sopenharmony_ci   glthread->RestartIndex = top->RestartIndex;
631bf215546Sopenharmony_ci   glthread->PrimitiveRestart = top->PrimitiveRestart;
632bf215546Sopenharmony_ci   glthread->PrimitiveRestartFixedIndex = top->PrimitiveRestartFixedIndex;
633bf215546Sopenharmony_ci
634bf215546Sopenharmony_ci   if (!vao)
635bf215546Sopenharmony_ci      vao = &glthread->DefaultVAO;
636bf215546Sopenharmony_ci
637bf215546Sopenharmony_ci   assert(top->VAO.Name == vao->Name);
638bf215546Sopenharmony_ci   *vao = top->VAO; /* Copy all fields. */
639bf215546Sopenharmony_ci   glthread->CurrentVAO = vao;
640bf215546Sopenharmony_ci}
641bf215546Sopenharmony_ci
642bf215546Sopenharmony_civoid
643bf215546Sopenharmony_ci_mesa_glthread_ClientAttribDefault(struct gl_context *ctx, GLbitfield mask)
644bf215546Sopenharmony_ci{
645bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
646bf215546Sopenharmony_ci
647bf215546Sopenharmony_ci   if (!(mask & GL_CLIENT_VERTEX_ARRAY_BIT))
648bf215546Sopenharmony_ci      return;
649bf215546Sopenharmony_ci
650bf215546Sopenharmony_ci   glthread->CurrentArrayBufferName = 0;
651bf215546Sopenharmony_ci   glthread->ClientActiveTexture = 0;
652bf215546Sopenharmony_ci   glthread->RestartIndex = 0;
653bf215546Sopenharmony_ci   glthread->PrimitiveRestart = false;
654bf215546Sopenharmony_ci   glthread->PrimitiveRestartFixedIndex = false;
655bf215546Sopenharmony_ci   glthread->CurrentVAO = &glthread->DefaultVAO;
656bf215546Sopenharmony_ci   _mesa_glthread_reset_vao(glthread->CurrentVAO);
657bf215546Sopenharmony_ci}
658bf215546Sopenharmony_ci
659bf215546Sopenharmony_civoid
660bf215546Sopenharmony_ci_mesa_glthread_InterleavedArrays(struct gl_context *ctx, GLenum format,
661bf215546Sopenharmony_ci                                 GLsizei stride, const GLvoid *pointer)
662bf215546Sopenharmony_ci{
663bf215546Sopenharmony_ci   struct gl_interleaved_layout layout;
664bf215546Sopenharmony_ci   unsigned tex = VERT_ATTRIB_TEX(ctx->GLThread.ClientActiveTexture);
665bf215546Sopenharmony_ci
666bf215546Sopenharmony_ci   if (stride < 0 || !_mesa_get_interleaved_layout(format, &layout))
667bf215546Sopenharmony_ci      return;
668bf215546Sopenharmony_ci
669bf215546Sopenharmony_ci   if (!stride)
670bf215546Sopenharmony_ci      stride = layout.defstride;
671bf215546Sopenharmony_ci
672bf215546Sopenharmony_ci   _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_EDGEFLAG, false);
673bf215546Sopenharmony_ci   _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_COLOR_INDEX, false);
674bf215546Sopenharmony_ci   /* XXX also disable secondary color and generic arrays? */
675bf215546Sopenharmony_ci
676bf215546Sopenharmony_ci   /* Texcoords */
677bf215546Sopenharmony_ci   if (layout.tflag) {
678bf215546Sopenharmony_ci      _mesa_glthread_ClientState(ctx, NULL, tex, true);
679bf215546Sopenharmony_ci      _mesa_glthread_AttribPointer(ctx, tex, layout.tcomps, GL_FLOAT, stride,
680bf215546Sopenharmony_ci                                   (GLubyte *) pointer + layout.toffset);
681bf215546Sopenharmony_ci   } else {
682bf215546Sopenharmony_ci      _mesa_glthread_ClientState(ctx, NULL, tex, false);
683bf215546Sopenharmony_ci   }
684bf215546Sopenharmony_ci
685bf215546Sopenharmony_ci   /* Color */
686bf215546Sopenharmony_ci   if (layout.cflag) {
687bf215546Sopenharmony_ci      _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_COLOR0, true);
688bf215546Sopenharmony_ci      _mesa_glthread_AttribPointer(ctx, VERT_ATTRIB_COLOR0, layout.ccomps,
689bf215546Sopenharmony_ci                                   layout.ctype, stride,
690bf215546Sopenharmony_ci                                   (GLubyte *) pointer + layout.coffset);
691bf215546Sopenharmony_ci   } else {
692bf215546Sopenharmony_ci      _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_COLOR0, false);
693bf215546Sopenharmony_ci   }
694bf215546Sopenharmony_ci
695bf215546Sopenharmony_ci   /* Normals */
696bf215546Sopenharmony_ci   if (layout.nflag) {
697bf215546Sopenharmony_ci      _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_NORMAL, true);
698bf215546Sopenharmony_ci      _mesa_glthread_AttribPointer(ctx, VERT_ATTRIB_NORMAL, 3, GL_FLOAT,
699bf215546Sopenharmony_ci                                   stride, (GLubyte *) pointer + layout.noffset);
700bf215546Sopenharmony_ci   } else {
701bf215546Sopenharmony_ci      _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_NORMAL, false);
702bf215546Sopenharmony_ci   }
703bf215546Sopenharmony_ci
704bf215546Sopenharmony_ci   /* Vertices */
705bf215546Sopenharmony_ci   _mesa_glthread_ClientState(ctx, NULL, VERT_ATTRIB_POS, true);
706bf215546Sopenharmony_ci   _mesa_glthread_AttribPointer(ctx, VERT_ATTRIB_POS, layout.vcomps, GL_FLOAT,
707bf215546Sopenharmony_ci                                stride, (GLubyte *) pointer + layout.voffset);
708bf215546Sopenharmony_ci}
709