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