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"
37 * - Handle ARB_vertex_attrib_binding (incl. EXT_dsa and ARB_dsa)
41 _mesa_glthread_reset_vao(struct glthread_vao
*vao
)
43 static unsigned default_elem_size
[VERT_ATTRIB_MAX
] = {
44 [VERT_ATTRIB_NORMAL
] = 12,
45 [VERT_ATTRIB_COLOR1
] = 12,
46 [VERT_ATTRIB_FOG
] = 4,
47 [VERT_ATTRIB_COLOR_INDEX
] = 4,
48 [VERT_ATTRIB_EDGEFLAG
] = 1,
49 [VERT_ATTRIB_POINT_SIZE
] = 4,
52 vao
->CurrentElementBufferName
= 0;
55 vao
->UserPointerMask
= 0;
56 vao
->NonZeroDivisorMask
= 0;
58 for (unsigned i
= 0; i
< ARRAY_SIZE(vao
->Attrib
); i
++) {
59 unsigned elem_size
= default_elem_size
[i
];
63 vao
->Attrib
[i
].ElementSize
= elem_size
;
64 vao
->Attrib
[i
].Stride
= elem_size
;
65 vao
->Attrib
[i
].Divisor
= 0;
66 vao
->Attrib
[i
].Pointer
= NULL
;
70 static struct glthread_vao
*
71 lookup_vao(struct gl_context
*ctx
, GLuint id
)
73 struct glthread_state
*glthread
= &ctx
->GLThread
;
74 struct glthread_vao
*vao
;
78 if (glthread
->LastLookedUpVAO
&&
79 glthread
->LastLookedUpVAO
->Name
== id
) {
80 vao
= glthread
->LastLookedUpVAO
;
82 vao
= _mesa_HashLookupLocked(glthread
->VAOs
, id
);
86 glthread
->LastLookedUpVAO
= vao
;
93 _mesa_glthread_BindVertexArray(struct gl_context
*ctx
, GLuint id
)
95 struct glthread_state
*glthread
= &ctx
->GLThread
;
98 glthread
->CurrentVAO
= &glthread
->DefaultVAO
;
100 struct glthread_vao
*vao
= lookup_vao(ctx
, id
);
103 glthread
->CurrentVAO
= vao
;
108 _mesa_glthread_DeleteVertexArrays(struct gl_context
*ctx
,
109 GLsizei n
, const GLuint
*ids
)
111 struct glthread_state
*glthread
= &ctx
->GLThread
;
116 for (int i
= 0; i
< n
; i
++) {
117 /* IDs equal to 0 should be silently ignored. */
121 struct glthread_vao
*vao
= lookup_vao(ctx
, ids
[i
]);
125 /* If the array object is currently bound, the spec says "the binding
126 * for that object reverts to zero and the default vertex array
129 if (glthread
->CurrentVAO
== vao
)
130 glthread
->CurrentVAO
= &glthread
->DefaultVAO
;
132 if (glthread
->LastLookedUpVAO
== vao
)
133 glthread
->LastLookedUpVAO
= NULL
;
135 /* The ID is immediately freed for re-use */
136 _mesa_HashRemoveLocked(glthread
->VAOs
, vao
->Name
);
142 _mesa_glthread_GenVertexArrays(struct gl_context
*ctx
,
143 GLsizei n
, GLuint
*arrays
)
145 struct glthread_state
*glthread
= &ctx
->GLThread
;
150 /* The IDs have been generated at this point. Create VAOs for glthread. */
151 for (int i
= 0; i
< n
; i
++) {
152 GLuint id
= arrays
[i
];
153 struct glthread_vao
*vao
;
155 vao
= calloc(1, sizeof(*vao
));
157 continue; /* Is that all we can do? */
160 _mesa_glthread_reset_vao(vao
);
161 _mesa_HashInsertLocked(glthread
->VAOs
, id
, vao
);
165 /* If vaobj is NULL, use the currently-bound VAO. */
166 static inline struct glthread_vao
*
167 get_vao(struct gl_context
*ctx
, const GLuint
*vaobj
)
170 return lookup_vao(ctx
, *vaobj
);
172 return ctx
->GLThread
.CurrentVAO
;
176 update_primitive_restart(struct gl_context
*ctx
)
178 struct glthread_state
*glthread
= &ctx
->GLThread
;
180 glthread
->_PrimitiveRestart
= glthread
->PrimitiveRestart
||
181 glthread
->PrimitiveRestartFixedIndex
;
182 glthread
->_RestartIndex
[0] =
183 _mesa_get_prim_restart_index(glthread
->PrimitiveRestartFixedIndex
,
184 glthread
->RestartIndex
, 1);
185 glthread
->_RestartIndex
[1] =
186 _mesa_get_prim_restart_index(glthread
->PrimitiveRestartFixedIndex
,
187 glthread
->RestartIndex
, 2);
188 glthread
->_RestartIndex
[3] =
189 _mesa_get_prim_restart_index(glthread
->PrimitiveRestartFixedIndex
,
190 glthread
->RestartIndex
, 4);
194 _mesa_glthread_set_prim_restart(struct gl_context
*ctx
, GLenum cap
, bool value
)
197 case GL_PRIMITIVE_RESTART
:
198 ctx
->GLThread
.PrimitiveRestart
= value
;
200 case GL_PRIMITIVE_RESTART_FIXED_INDEX
:
201 ctx
->GLThread
.PrimitiveRestartFixedIndex
= value
;
205 update_primitive_restart(ctx
);
209 _mesa_glthread_PrimitiveRestartIndex(struct gl_context
*ctx
, GLuint index
)
211 ctx
->GLThread
.RestartIndex
= index
;
212 update_primitive_restart(ctx
);
216 _mesa_glthread_ClientState(struct gl_context
*ctx
, GLuint
*vaobj
,
217 gl_vert_attrib attrib
, bool enable
)
219 /* The primitive restart client state uses a special value. */
220 if (attrib
== VERT_ATTRIB_PRIMITIVE_RESTART_NV
) {
221 ctx
->GLThread
.PrimitiveRestart
= enable
;
222 update_primitive_restart(ctx
);
226 if (attrib
>= VERT_ATTRIB_MAX
)
229 struct glthread_vao
*vao
= get_vao(ctx
, vaobj
);
234 vao
->UserEnabled
|= 1u << attrib
;
236 vao
->UserEnabled
&= ~(1u << attrib
);
238 /* The generic0 attribute superseeds the position attribute */
239 vao
->Enabled
= vao
->UserEnabled
;
240 if (vao
->Enabled
& VERT_BIT_GENERIC0
)
241 vao
->Enabled
&= ~VERT_BIT_POS
;
244 void _mesa_glthread_AttribDivisor(struct gl_context
*ctx
, const GLuint
*vaobj
,
245 gl_vert_attrib attrib
, GLuint divisor
)
247 if (attrib
>= VERT_ATTRIB_MAX
)
250 struct glthread_vao
*vao
= get_vao(ctx
, vaobj
);
254 vao
->Attrib
[attrib
].Divisor
= divisor
;
257 vao
->NonZeroDivisorMask
|= 1u << attrib
;
259 vao
->NonZeroDivisorMask
&= ~(1u << attrib
);
263 attrib_pointer(struct glthread_state
*glthread
, struct glthread_vao
*vao
,
264 GLuint buffer
, gl_vert_attrib attrib
,
265 GLint size
, GLenum type
, GLsizei stride
,
268 if (attrib
>= VERT_ATTRIB_MAX
)
271 unsigned elem_size
= _mesa_bytes_per_vertex_attrib(size
, type
);
273 vao
->Attrib
[attrib
].ElementSize
= elem_size
;
274 vao
->Attrib
[attrib
].Stride
= stride
? stride
: elem_size
;
275 vao
->Attrib
[attrib
].Pointer
= pointer
;
278 vao
->UserPointerMask
&= ~(1u << attrib
);
280 vao
->UserPointerMask
|= 1u << attrib
;
284 _mesa_glthread_AttribPointer(struct gl_context
*ctx
, gl_vert_attrib attrib
,
285 GLint size
, GLenum type
, GLsizei stride
,
288 struct glthread_state
*glthread
= &ctx
->GLThread
;
290 attrib_pointer(glthread
, glthread
->CurrentVAO
,
291 glthread
->CurrentArrayBufferName
,
292 attrib
, size
, type
, stride
, pointer
);
296 _mesa_glthread_DSAAttribPointer(struct gl_context
*ctx
, GLuint vaobj
,
297 GLuint buffer
, gl_vert_attrib attrib
,
298 GLint size
, GLenum type
, GLsizei stride
,
301 struct glthread_state
*glthread
= &ctx
->GLThread
;
302 struct glthread_vao
*vao
;
304 vao
= lookup_vao(ctx
, vaobj
);
308 attrib_pointer(glthread
, vao
, buffer
, attrib
, size
, type
, stride
,
309 (const void*)offset
);
313 _mesa_glthread_PushClientAttrib(struct gl_context
*ctx
, GLbitfield mask
,
316 struct glthread_state
*glthread
= &ctx
->GLThread
;
318 if (glthread
->ClientAttribStackTop
>= MAX_CLIENT_ATTRIB_STACK_DEPTH
)
321 struct glthread_client_attrib
*top
=
322 &glthread
->ClientAttribStack
[glthread
->ClientAttribStackTop
];
324 if (mask
& GL_CLIENT_VERTEX_ARRAY_BIT
) {
325 top
->VAO
= *glthread
->CurrentVAO
;
326 top
->CurrentArrayBufferName
= glthread
->CurrentArrayBufferName
;
327 top
->ClientActiveTexture
= glthread
->ClientActiveTexture
;
328 top
->RestartIndex
= glthread
->RestartIndex
;
329 top
->PrimitiveRestart
= glthread
->PrimitiveRestart
;
330 top
->PrimitiveRestartFixedIndex
= glthread
->PrimitiveRestartFixedIndex
;
336 glthread
->ClientAttribStackTop
++;
339 _mesa_glthread_ClientAttribDefault(ctx
, mask
);
343 _mesa_glthread_PopClientAttrib(struct gl_context
*ctx
)
345 struct glthread_state
*glthread
= &ctx
->GLThread
;
347 if (glthread
->ClientAttribStackTop
== 0)
350 glthread
->ClientAttribStackTop
--;
352 struct glthread_client_attrib
*top
=
353 &glthread
->ClientAttribStack
[glthread
->ClientAttribStackTop
];
358 /* Popping a delete VAO is an error. */
359 struct glthread_vao
*vao
= NULL
;
361 vao
= lookup_vao(ctx
, top
->VAO
.Name
);
366 /* Restore states. */
367 glthread
->CurrentArrayBufferName
= top
->CurrentArrayBufferName
;
368 glthread
->ClientActiveTexture
= top
->ClientActiveTexture
;
369 glthread
->RestartIndex
= top
->RestartIndex
;
370 glthread
->PrimitiveRestart
= top
->PrimitiveRestart
;
371 glthread
->PrimitiveRestartFixedIndex
= top
->PrimitiveRestartFixedIndex
;
374 vao
= &glthread
->DefaultVAO
;
376 assert(top
->VAO
.Name
== vao
->Name
);
377 *vao
= top
->VAO
; /* Copy all fields. */
378 glthread
->CurrentVAO
= vao
;
382 _mesa_glthread_ClientAttribDefault(struct gl_context
*ctx
, GLbitfield mask
)
384 struct glthread_state
*glthread
= &ctx
->GLThread
;
386 if (!(mask
& GL_CLIENT_VERTEX_ARRAY_BIT
))
389 glthread
->CurrentArrayBufferName
= 0;
390 glthread
->ClientActiveTexture
= 0;
391 glthread
->RestartIndex
= 0;
392 glthread
->PrimitiveRestart
= false;
393 glthread
->PrimitiveRestartFixedIndex
= false;
394 glthread
->CurrentVAO
= &glthread
->DefaultVAO
;
395 _mesa_glthread_reset_vao(glthread
->CurrentVAO
);