glthread: Fix use of alloca() without #include "c99_alloca.h"
[mesa.git] / src / mesa / main / glthread_varray.c
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 /* TODO:
37 * - Handle ARB_vertex_attrib_binding (incl. EXT_dsa and ARB_dsa)
38 */
39
40 void
41 _mesa_glthread_reset_vao(struct glthread_vao *vao)
42 {
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,
50 };
51
52 vao->CurrentElementBufferName = 0;
53 vao->UserEnabled = 0;
54 vao->Enabled = 0;
55 vao->UserPointerMask = 0;
56 vao->NonZeroDivisorMask = 0;
57
58 for (unsigned i = 0; i < ARRAY_SIZE(vao->Attrib); i++) {
59 unsigned elem_size = default_elem_size[i];
60 if (!elem_size)
61 elem_size = 16;
62
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;
67 }
68 }
69
70 static struct glthread_vao *
71 lookup_vao(struct gl_context *ctx, GLuint id)
72 {
73 struct glthread_state *glthread = &ctx->GLThread;
74 struct glthread_vao *vao;
75
76 assert(id != 0);
77
78 if (glthread->LastLookedUpVAO &&
79 glthread->LastLookedUpVAO->Name == id) {
80 vao = glthread->LastLookedUpVAO;
81 } else {
82 vao = _mesa_HashLookupLocked(glthread->VAOs, id);
83 if (!vao)
84 return NULL;
85
86 glthread->LastLookedUpVAO = vao;
87 }
88
89 return vao;
90 }
91
92 void
93 _mesa_glthread_BindVertexArray(struct gl_context *ctx, GLuint id)
94 {
95 struct glthread_state *glthread = &ctx->GLThread;
96
97 if (id == 0) {
98 glthread->CurrentVAO = &glthread->DefaultVAO;
99 } else {
100 struct glthread_vao *vao = lookup_vao(ctx, id);
101
102 if (vao)
103 glthread->CurrentVAO = vao;
104 }
105 }
106
107 void
108 _mesa_glthread_DeleteVertexArrays(struct gl_context *ctx,
109 GLsizei n, const GLuint *ids)
110 {
111 struct glthread_state *glthread = &ctx->GLThread;
112
113 if (!ids)
114 return;
115
116 for (int i = 0; i < n; i++) {
117 /* IDs equal to 0 should be silently ignored. */
118 if (!ids[i])
119 continue;
120
121 struct glthread_vao *vao = lookup_vao(ctx, ids[i]);
122 if (!vao)
123 continue;
124
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
127 * becomes current."
128 */
129 if (glthread->CurrentVAO == vao)
130 glthread->CurrentVAO = &glthread->DefaultVAO;
131
132 if (glthread->LastLookedUpVAO == vao)
133 glthread->LastLookedUpVAO = NULL;
134
135 /* The ID is immediately freed for re-use */
136 _mesa_HashRemoveLocked(glthread->VAOs, vao->Name);
137 free(vao);
138 }
139 }
140
141 void
142 _mesa_glthread_GenVertexArrays(struct gl_context *ctx,
143 GLsizei n, GLuint *arrays)
144 {
145 struct glthread_state *glthread = &ctx->GLThread;
146
147 if (!arrays)
148 return;
149
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;
154
155 vao = calloc(1, sizeof(*vao));
156 if (!vao)
157 continue; /* Is that all we can do? */
158
159 vao->Name = id;
160 _mesa_glthread_reset_vao(vao);
161 _mesa_HashInsertLocked(glthread->VAOs, id, vao);
162 }
163 }
164
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)
168 {
169 if (vaobj)
170 return lookup_vao(ctx, *vaobj);
171
172 return ctx->GLThread.CurrentVAO;
173 }
174
175 static void
176 update_primitive_restart(struct gl_context *ctx)
177 {
178 struct glthread_state *glthread = &ctx->GLThread;
179
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);
191 }
192
193 void
194 _mesa_glthread_set_prim_restart(struct gl_context *ctx, GLenum cap, bool value)
195 {
196 switch (cap) {
197 case GL_PRIMITIVE_RESTART:
198 ctx->GLThread.PrimitiveRestart = value;
199 break;
200 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
201 ctx->GLThread.PrimitiveRestartFixedIndex = value;
202 break;
203 }
204
205 update_primitive_restart(ctx);
206 }
207
208 void
209 _mesa_glthread_PrimitiveRestartIndex(struct gl_context *ctx, GLuint index)
210 {
211 ctx->GLThread.RestartIndex = index;
212 update_primitive_restart(ctx);
213 }
214
215 void
216 _mesa_glthread_ClientState(struct gl_context *ctx, GLuint *vaobj,
217 gl_vert_attrib attrib, bool enable)
218 {
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);
223 return;
224 }
225
226 if (attrib >= VERT_ATTRIB_MAX)
227 return;
228
229 struct glthread_vao *vao = get_vao(ctx, vaobj);
230 if (!vao)
231 return;
232
233 if (enable)
234 vao->UserEnabled |= 1u << attrib;
235 else
236 vao->UserEnabled &= ~(1u << attrib);
237
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;
242 }
243
244 void _mesa_glthread_AttribDivisor(struct gl_context *ctx, const GLuint *vaobj,
245 gl_vert_attrib attrib, GLuint divisor)
246 {
247 if (attrib >= VERT_ATTRIB_MAX)
248 return;
249
250 struct glthread_vao *vao = get_vao(ctx, vaobj);
251 if (!vao)
252 return;
253
254 vao->Attrib[attrib].Divisor = divisor;
255
256 if (divisor)
257 vao->NonZeroDivisorMask |= 1u << attrib;
258 else
259 vao->NonZeroDivisorMask &= ~(1u << attrib);
260 }
261
262 static void
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,
266 const void *pointer)
267 {
268 if (attrib >= VERT_ATTRIB_MAX)
269 return;
270
271 unsigned elem_size = _mesa_bytes_per_vertex_attrib(size, type);
272
273 vao->Attrib[attrib].ElementSize = elem_size;
274 vao->Attrib[attrib].Stride = stride ? stride : elem_size;
275 vao->Attrib[attrib].Pointer = pointer;
276
277 if (buffer != 0)
278 vao->UserPointerMask &= ~(1u << attrib);
279 else
280 vao->UserPointerMask |= 1u << attrib;
281 }
282
283 void
284 _mesa_glthread_AttribPointer(struct gl_context *ctx, gl_vert_attrib attrib,
285 GLint size, GLenum type, GLsizei stride,
286 const void *pointer)
287 {
288 struct glthread_state *glthread = &ctx->GLThread;
289
290 attrib_pointer(glthread, glthread->CurrentVAO,
291 glthread->CurrentArrayBufferName,
292 attrib, size, type, stride, pointer);
293 }
294
295 void
296 _mesa_glthread_DSAAttribPointer(struct gl_context *ctx, GLuint vaobj,
297 GLuint buffer, gl_vert_attrib attrib,
298 GLint size, GLenum type, GLsizei stride,
299 GLintptr offset)
300 {
301 struct glthread_state *glthread = &ctx->GLThread;
302 struct glthread_vao *vao;
303
304 vao = lookup_vao(ctx, vaobj);
305 if (!vao)
306 return;
307
308 attrib_pointer(glthread, vao, buffer, attrib, size, type, stride,
309 (const void*)offset);
310 }
311
312 void
313 _mesa_glthread_PushClientAttrib(struct gl_context *ctx, GLbitfield mask,
314 bool set_default)
315 {
316 struct glthread_state *glthread = &ctx->GLThread;
317
318 if (glthread->ClientAttribStackTop >= MAX_CLIENT_ATTRIB_STACK_DEPTH)
319 return;
320
321 struct glthread_client_attrib *top =
322 &glthread->ClientAttribStack[glthread->ClientAttribStackTop];
323
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;
331 top->Valid = true;
332 } else {
333 top->Valid = false;
334 }
335
336 glthread->ClientAttribStackTop++;
337
338 if (set_default)
339 _mesa_glthread_ClientAttribDefault(ctx, mask);
340 }
341
342 void
343 _mesa_glthread_PopClientAttrib(struct gl_context *ctx)
344 {
345 struct glthread_state *glthread = &ctx->GLThread;
346
347 if (glthread->ClientAttribStackTop == 0)
348 return;
349
350 glthread->ClientAttribStackTop--;
351
352 struct glthread_client_attrib *top =
353 &glthread->ClientAttribStack[glthread->ClientAttribStackTop];
354
355 if (!top->Valid)
356 return;
357
358 /* Popping a delete VAO is an error. */
359 struct glthread_vao *vao = NULL;
360 if (top->VAO.Name) {
361 vao = lookup_vao(ctx, top->VAO.Name);
362 if (!vao)
363 return;
364 }
365
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;
372
373 if (!vao)
374 vao = &glthread->DefaultVAO;
375
376 assert(top->VAO.Name == vao->Name);
377 *vao = top->VAO; /* Copy all fields. */
378 glthread->CurrentVAO = vao;
379 }
380
381 void
382 _mesa_glthread_ClientAttribDefault(struct gl_context *ctx, GLbitfield mask)
383 {
384 struct glthread_state *glthread = &ctx->GLThread;
385
386 if (!(mask & GL_CLIENT_VERTEX_ARRAY_BIT))
387 return;
388
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);
396 }