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