2 * Copyright © 2020 Advanced Micro Devices, Inc.
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:
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
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
24 /* This implements vertex array state tracking for glthread. It's separate
25 * from the rest of Mesa. Only minimum functionality is implemented here
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"
38 _mesa_glthread_reset_vao(struct glthread_vao
*vao
)
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,
49 vao
->CurrentElementBufferName
= 0;
52 vao
->BufferEnabled
= 0;
53 vao
->UserPointerMask
= 0;
54 vao
->NonZeroDivisorMask
= 0;
56 for (unsigned i
= 0; i
< ARRAY_SIZE(vao
->Attrib
); i
++) {
57 unsigned elem_size
= default_elem_size
[i
];
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
;
71 static struct glthread_vao
*
72 lookup_vao(struct gl_context
*ctx
, GLuint id
)
74 struct glthread_state
*glthread
= &ctx
->GLThread
;
75 struct glthread_vao
*vao
;
79 if (glthread
->LastLookedUpVAO
&&
80 glthread
->LastLookedUpVAO
->Name
== id
) {
81 vao
= glthread
->LastLookedUpVAO
;
83 vao
= _mesa_HashLookupLocked(glthread
->VAOs
, id
);
87 glthread
->LastLookedUpVAO
= vao
;
94 _mesa_glthread_BindVertexArray(struct gl_context
*ctx
, GLuint id
)
96 struct glthread_state
*glthread
= &ctx
->GLThread
;
99 glthread
->CurrentVAO
= &glthread
->DefaultVAO
;
101 struct glthread_vao
*vao
= lookup_vao(ctx
, id
);
104 glthread
->CurrentVAO
= vao
;
109 _mesa_glthread_DeleteVertexArrays(struct gl_context
*ctx
,
110 GLsizei n
, const GLuint
*ids
)
112 struct glthread_state
*glthread
= &ctx
->GLThread
;
117 for (int i
= 0; i
< n
; i
++) {
118 /* IDs equal to 0 should be silently ignored. */
122 struct glthread_vao
*vao
= lookup_vao(ctx
, ids
[i
]);
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
130 if (glthread
->CurrentVAO
== vao
)
131 glthread
->CurrentVAO
= &glthread
->DefaultVAO
;
133 if (glthread
->LastLookedUpVAO
== vao
)
134 glthread
->LastLookedUpVAO
= NULL
;
136 /* The ID is immediately freed for re-use */
137 _mesa_HashRemoveLocked(glthread
->VAOs
, vao
->Name
);
143 _mesa_glthread_GenVertexArrays(struct gl_context
*ctx
,
144 GLsizei n
, GLuint
*arrays
)
146 struct glthread_state
*glthread
= &ctx
->GLThread
;
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
;
156 vao
= calloc(1, sizeof(*vao
));
158 continue; /* Is that all we can do? */
161 _mesa_glthread_reset_vao(vao
);
162 _mesa_HashInsertLocked(glthread
->VAOs
, id
, vao
);
166 /* If vaobj is NULL, use the currently-bound VAO. */
167 static inline struct glthread_vao
*
168 get_vao(struct gl_context
*ctx
, const GLuint
*vaobj
)
171 return lookup_vao(ctx
, *vaobj
);
173 return ctx
->GLThread
.CurrentVAO
;
177 update_primitive_restart(struct gl_context
*ctx
)
179 struct glthread_state
*glthread
= &ctx
->GLThread
;
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);
195 _mesa_glthread_set_prim_restart(struct gl_context
*ctx
, GLenum cap
, bool value
)
198 case GL_PRIMITIVE_RESTART
:
199 ctx
->GLThread
.PrimitiveRestart
= value
;
201 case GL_PRIMITIVE_RESTART_FIXED_INDEX
:
202 ctx
->GLThread
.PrimitiveRestartFixedIndex
= value
;
206 update_primitive_restart(ctx
);
210 _mesa_glthread_PrimitiveRestartIndex(struct gl_context
*ctx
, GLuint index
)
212 ctx
->GLThread
.RestartIndex
= index
;
213 update_primitive_restart(ctx
);
217 enable_buffer(struct glthread_vao
*vao
, unsigned binding_index
)
219 int attrib_count
= ++vao
->Attrib
[binding_index
].EnabledAttribCount
;
221 if (attrib_count
== 1)
222 vao
->BufferEnabled
|= 1 << binding_index
;
223 else if (attrib_count
== 2)
224 vao
->BufferInterleaved
|= 1 << binding_index
;
228 disable_buffer(struct glthread_vao
*vao
, unsigned binding_index
)
230 int attrib_count
= --vao
->Attrib
[binding_index
].EnabledAttribCount
;
232 if (attrib_count
== 0)
233 vao
->BufferEnabled
&= ~(1 << binding_index
);
234 else if (attrib_count
== 1)
235 vao
->BufferInterleaved
&= ~(1 << binding_index
);
237 assert(attrib_count
>= 0);
241 _mesa_glthread_ClientState(struct gl_context
*ctx
, GLuint
*vaobj
,
242 gl_vert_attrib attrib
, bool enable
)
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
);
251 if (attrib
>= VERT_ATTRIB_MAX
)
254 struct glthread_vao
*vao
= get_vao(ctx
, vaobj
);
258 const unsigned attrib_bit
= 1u << attrib
;
260 if (enable
&& !(vao
->UserEnabled
& attrib_bit
)) {
261 vao
->UserEnabled
|= attrib_bit
;
263 /* The generic0 attribute supersedes the position attribute. We need to
264 * update BufferBindingEnabled accordingly.
266 if (attrib
== VERT_ATTRIB_POS
) {
267 if (!(vao
->UserEnabled
& VERT_BIT_GENERIC0
))
268 enable_buffer(vao
, vao
->Attrib
[VERT_ATTRIB_POS
].BufferIndex
);
270 enable_buffer(vao
, vao
->Attrib
[attrib
].BufferIndex
);
272 if (attrib
== VERT_ATTRIB_GENERIC0
&& vao
->UserEnabled
& VERT_BIT_POS
)
273 disable_buffer(vao
, vao
->Attrib
[VERT_ATTRIB_POS
].BufferIndex
);
275 } else if (!enable
&& (vao
->UserEnabled
& attrib_bit
)) {
276 vao
->UserEnabled
&= ~attrib_bit
;
278 /* The generic0 attribute supersedes the position attribute. We need to
279 * update BufferBindingEnabled accordingly.
281 if (attrib
== VERT_ATTRIB_POS
) {
282 if (!(vao
->UserEnabled
& VERT_BIT_GENERIC0
))
283 disable_buffer(vao
, vao
->Attrib
[VERT_ATTRIB_POS
].BufferIndex
);
285 disable_buffer(vao
, vao
->Attrib
[attrib
].BufferIndex
);
287 if (attrib
== VERT_ATTRIB_GENERIC0
&& vao
->UserEnabled
& VERT_BIT_POS
)
288 enable_buffer(vao
, vao
->Attrib
[VERT_ATTRIB_POS
].BufferIndex
);
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
;
299 set_attrib_binding(struct glthread_state
*glthread
, struct glthread_vao
*vao
,
300 gl_vert_attrib attrib
, unsigned new_binding_index
)
302 unsigned old_binding_index
= vao
->Attrib
[attrib
].BufferIndex
;
304 if (old_binding_index
!= new_binding_index
) {
305 vao
->Attrib
[attrib
].BufferIndex
= new_binding_index
;
307 if (vao
->Enabled
& (1u << attrib
)) {
308 /* Update BufferBindingEnabled. */
309 enable_buffer(vao
, new_binding_index
);
310 disable_buffer(vao
, old_binding_index
);
315 void _mesa_glthread_AttribDivisor(struct gl_context
*ctx
, const GLuint
*vaobj
,
316 gl_vert_attrib attrib
, GLuint divisor
)
318 if (attrib
>= VERT_ATTRIB_MAX
)
321 struct glthread_vao
*vao
= get_vao(ctx
, vaobj
);
325 vao
->Attrib
[attrib
].Divisor
= divisor
;
327 set_attrib_binding(&ctx
->GLThread
, vao
, attrib
, attrib
);
330 vao
->NonZeroDivisorMask
|= 1u << attrib
;
332 vao
->NonZeroDivisorMask
&= ~(1u << attrib
);
336 attrib_pointer(struct glthread_state
*glthread
, struct glthread_vao
*vao
,
337 GLuint buffer
, gl_vert_attrib attrib
,
338 GLint size
, GLenum type
, GLsizei stride
,
341 if (attrib
>= VERT_ATTRIB_MAX
)
344 unsigned elem_size
= _mesa_bytes_per_vertex_attrib(size
, type
);
346 vao
->Attrib
[attrib
].ElementSize
= elem_size
;
347 vao
->Attrib
[attrib
].Stride
= stride
? stride
: elem_size
;
348 vao
->Attrib
[attrib
].Pointer
= pointer
;
349 vao
->Attrib
[attrib
].RelativeOffset
= 0;
351 set_attrib_binding(glthread
, vao
, attrib
, attrib
);
354 vao
->UserPointerMask
&= ~(1u << attrib
);
356 vao
->UserPointerMask
|= 1u << attrib
;
360 _mesa_glthread_AttribPointer(struct gl_context
*ctx
, gl_vert_attrib attrib
,
361 GLint size
, GLenum type
, GLsizei stride
,
364 struct glthread_state
*glthread
= &ctx
->GLThread
;
366 attrib_pointer(glthread
, glthread
->CurrentVAO
,
367 glthread
->CurrentArrayBufferName
,
368 attrib
, size
, type
, stride
, pointer
);
372 _mesa_glthread_DSAAttribPointer(struct gl_context
*ctx
, GLuint vaobj
,
373 GLuint buffer
, gl_vert_attrib attrib
,
374 GLint size
, GLenum type
, GLsizei stride
,
377 struct glthread_state
*glthread
= &ctx
->GLThread
;
378 struct glthread_vao
*vao
;
380 vao
= lookup_vao(ctx
, vaobj
);
384 attrib_pointer(glthread
, vao
, buffer
, attrib
, size
, type
, stride
,
385 (const void*)offset
);
389 attrib_format(struct glthread_state
*glthread
, struct glthread_vao
*vao
,
390 GLuint attribindex
, GLint size
, GLenum type
,
391 GLuint relativeoffset
)
393 if (attribindex
>= VERT_ATTRIB_GENERIC_MAX
)
396 unsigned elem_size
= _mesa_bytes_per_vertex_attrib(size
, type
);
398 unsigned i
= VERT_ATTRIB_GENERIC(attribindex
);
399 vao
->Attrib
[i
].ElementSize
= elem_size
;
400 vao
->Attrib
[i
].RelativeOffset
= relativeoffset
;
404 _mesa_glthread_AttribFormat(struct gl_context
*ctx
, GLuint attribindex
,
405 GLint size
, GLenum type
, GLuint relativeoffset
)
407 struct glthread_state
*glthread
= &ctx
->GLThread
;
409 attrib_format(glthread
, glthread
->CurrentVAO
, attribindex
, size
, type
,
414 _mesa_glthread_DSAAttribFormat(struct gl_context
*ctx
, GLuint vaobj
,
415 GLuint attribindex
, GLint size
, GLenum type
,
416 GLuint relativeoffset
)
418 struct glthread_state
*glthread
= &ctx
->GLThread
;
419 struct glthread_vao
*vao
= lookup_vao(ctx
, vaobj
);
422 attrib_format(glthread
, vao
, attribindex
, size
, type
, relativeoffset
);
426 bind_vertex_buffer(struct glthread_state
*glthread
, struct glthread_vao
*vao
,
427 GLuint bindingindex
, GLuint buffer
, GLintptr offset
,
430 if (bindingindex
>= VERT_ATTRIB_GENERIC_MAX
)
433 unsigned i
= VERT_ATTRIB_GENERIC(bindingindex
);
434 vao
->Attrib
[i
].Pointer
= (const void*)offset
;
435 vao
->Attrib
[i
].Stride
= stride
;
438 vao
->UserPointerMask
&= ~(1u << i
);
440 vao
->UserPointerMask
|= 1u << i
;
444 _mesa_glthread_VertexBuffer(struct gl_context
*ctx
, GLuint bindingindex
,
445 GLuint buffer
, GLintptr offset
, GLsizei stride
)
447 struct glthread_state
*glthread
= &ctx
->GLThread
;
449 bind_vertex_buffer(glthread
, glthread
->CurrentVAO
, bindingindex
, buffer
,
454 _mesa_glthread_DSAVertexBuffer(struct gl_context
*ctx
, GLuint vaobj
,
455 GLuint bindingindex
, GLuint buffer
,
456 GLintptr offset
, GLsizei stride
)
458 struct glthread_state
*glthread
= &ctx
->GLThread
;
459 struct glthread_vao
*vao
= lookup_vao(ctx
, vaobj
);
462 bind_vertex_buffer(glthread
, vao
, bindingindex
, buffer
, offset
, stride
);
466 _mesa_glthread_DSAVertexBuffers(struct gl_context
*ctx
, GLuint vaobj
,
467 GLuint first
, GLsizei count
,
468 const GLuint
*buffers
,
469 const GLintptr
*offsets
,
470 const GLsizei
*strides
)
472 struct glthread_state
*glthread
= &ctx
->GLThread
;
473 struct glthread_vao
*vao
;
475 vao
= lookup_vao(ctx
, vaobj
);
479 for (unsigned i
= 0; i
< count
; i
++) {
480 bind_vertex_buffer(glthread
, vao
, first
+ i
, buffers
[i
], offsets
[i
],
486 binding_divisor(struct glthread_state
*glthread
, struct glthread_vao
*vao
,
487 GLuint bindingindex
, GLuint divisor
)
489 if (bindingindex
>= VERT_ATTRIB_GENERIC_MAX
)
492 unsigned i
= VERT_ATTRIB_GENERIC(bindingindex
);
493 vao
->Attrib
[i
].Divisor
= divisor
;
496 vao
->NonZeroDivisorMask
|= 1u << i
;
498 vao
->NonZeroDivisorMask
&= ~(1u << i
);
502 _mesa_glthread_BindingDivisor(struct gl_context
*ctx
, GLuint bindingindex
,
505 struct glthread_state
*glthread
= &ctx
->GLThread
;
507 binding_divisor(glthread
, glthread
->CurrentVAO
, bindingindex
, divisor
);
511 _mesa_glthread_DSABindingDivisor(struct gl_context
*ctx
, GLuint vaobj
,
512 GLuint bindingindex
, GLuint divisor
)
514 struct glthread_state
*glthread
= &ctx
->GLThread
;
515 struct glthread_vao
*vao
= lookup_vao(ctx
, vaobj
);
518 binding_divisor(glthread
, vao
, bindingindex
, divisor
);
522 _mesa_glthread_AttribBinding(struct gl_context
*ctx
, GLuint attribindex
,
525 struct glthread_state
*glthread
= &ctx
->GLThread
;
527 if (attribindex
>= VERT_ATTRIB_GENERIC_MAX
||
528 bindingindex
>= VERT_ATTRIB_GENERIC_MAX
)
531 set_attrib_binding(glthread
, glthread
->CurrentVAO
,
532 VERT_ATTRIB_GENERIC(attribindex
),
533 VERT_ATTRIB_GENERIC(bindingindex
));
537 _mesa_glthread_DSAAttribBinding(struct gl_context
*ctx
, GLuint vaobj
,
538 GLuint attribindex
, GLuint bindingindex
)
540 struct glthread_state
*glthread
= &ctx
->GLThread
;
542 if (attribindex
>= VERT_ATTRIB_GENERIC_MAX
||
543 bindingindex
>= VERT_ATTRIB_GENERIC_MAX
)
546 struct glthread_vao
*vao
= lookup_vao(ctx
, vaobj
);
548 set_attrib_binding(glthread
, vao
,
549 VERT_ATTRIB_GENERIC(attribindex
),
550 VERT_ATTRIB_GENERIC(bindingindex
));
555 _mesa_glthread_DSAElementBuffer(struct gl_context
*ctx
, GLuint vaobj
,
558 struct glthread_vao
*vao
= lookup_vao(ctx
, vaobj
);
561 vao
->CurrentElementBufferName
= buffer
;
565 _mesa_glthread_PushClientAttrib(struct gl_context
*ctx
, GLbitfield mask
,
568 struct glthread_state
*glthread
= &ctx
->GLThread
;
570 if (glthread
->ClientAttribStackTop
>= MAX_CLIENT_ATTRIB_STACK_DEPTH
)
573 struct glthread_client_attrib
*top
=
574 &glthread
->ClientAttribStack
[glthread
->ClientAttribStackTop
];
576 if (mask
& GL_CLIENT_VERTEX_ARRAY_BIT
) {
577 top
->VAO
= *glthread
->CurrentVAO
;
578 top
->CurrentArrayBufferName
= glthread
->CurrentArrayBufferName
;
579 top
->ClientActiveTexture
= glthread
->ClientActiveTexture
;
580 top
->RestartIndex
= glthread
->RestartIndex
;
581 top
->PrimitiveRestart
= glthread
->PrimitiveRestart
;
582 top
->PrimitiveRestartFixedIndex
= glthread
->PrimitiveRestartFixedIndex
;
588 glthread
->ClientAttribStackTop
++;
591 _mesa_glthread_ClientAttribDefault(ctx
, mask
);
595 _mesa_glthread_PopClientAttrib(struct gl_context
*ctx
)
597 struct glthread_state
*glthread
= &ctx
->GLThread
;
599 if (glthread
->ClientAttribStackTop
== 0)
602 glthread
->ClientAttribStackTop
--;
604 struct glthread_client_attrib
*top
=
605 &glthread
->ClientAttribStack
[glthread
->ClientAttribStackTop
];
610 /* Popping a delete VAO is an error. */
611 struct glthread_vao
*vao
= NULL
;
613 vao
= lookup_vao(ctx
, top
->VAO
.Name
);
618 /* Restore states. */
619 glthread
->CurrentArrayBufferName
= top
->CurrentArrayBufferName
;
620 glthread
->ClientActiveTexture
= top
->ClientActiveTexture
;
621 glthread
->RestartIndex
= top
->RestartIndex
;
622 glthread
->PrimitiveRestart
= top
->PrimitiveRestart
;
623 glthread
->PrimitiveRestartFixedIndex
= top
->PrimitiveRestartFixedIndex
;
626 vao
= &glthread
->DefaultVAO
;
628 assert(top
->VAO
.Name
== vao
->Name
);
629 *vao
= top
->VAO
; /* Copy all fields. */
630 glthread
->CurrentVAO
= vao
;
634 _mesa_glthread_ClientAttribDefault(struct gl_context
*ctx
, GLbitfield mask
)
636 struct glthread_state
*glthread
= &ctx
->GLThread
;
638 if (!(mask
& GL_CLIENT_VERTEX_ARRAY_BIT
))
641 glthread
->CurrentArrayBufferName
= 0;
642 glthread
->ClientActiveTexture
= 0;
643 glthread
->RestartIndex
= 0;
644 glthread
->PrimitiveRestart
= false;
645 glthread
->PrimitiveRestartFixedIndex
= false;
646 glthread
->CurrentVAO
= &glthread
->DefaultVAO
;
647 _mesa_glthread_reset_vao(glthread
->CurrentVAO
);