glthread: track primitive restart state
[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 static struct glthread_vao *
41 lookup_vao(struct gl_context *ctx, GLuint id)
42 {
43 struct glthread_state *glthread = &ctx->GLThread;
44 struct glthread_vao *vao;
45
46 assert(id != 0);
47
48 if (glthread->LastLookedUpVAO &&
49 glthread->LastLookedUpVAO->Name == id) {
50 vao = glthread->LastLookedUpVAO;
51 } else {
52 vao = _mesa_HashLookupLocked(glthread->VAOs, id);
53 if (!vao)
54 return NULL;
55
56 glthread->LastLookedUpVAO = vao;
57 }
58
59 return vao;
60 }
61
62 void
63 _mesa_glthread_BindVertexArray(struct gl_context *ctx, GLuint id)
64 {
65 struct glthread_state *glthread = &ctx->GLThread;
66
67 if (id == 0) {
68 glthread->CurrentVAO = &glthread->DefaultVAO;
69 } else {
70 struct glthread_vao *vao = lookup_vao(ctx, id);
71
72 if (vao)
73 glthread->CurrentVAO = vao;
74 }
75 }
76
77 void
78 _mesa_glthread_DeleteVertexArrays(struct gl_context *ctx,
79 GLsizei n, const GLuint *ids)
80 {
81 struct glthread_state *glthread = &ctx->GLThread;
82
83 if (!ids)
84 return;
85
86 for (int i = 0; i < n; i++) {
87 /* IDs equal to 0 should be silently ignored. */
88 if (!ids[i])
89 continue;
90
91 struct glthread_vao *vao = lookup_vao(ctx, ids[i]);
92 if (!vao)
93 continue;
94
95 /* If the array object is currently bound, the spec says "the binding
96 * for that object reverts to zero and the default vertex array
97 * becomes current."
98 */
99 if (glthread->CurrentVAO == vao)
100 glthread->CurrentVAO = &glthread->DefaultVAO;
101
102 if (glthread->LastLookedUpVAO == vao)
103 glthread->LastLookedUpVAO = NULL;
104
105 /* The ID is immediately freed for re-use */
106 _mesa_HashRemoveLocked(glthread->VAOs, vao->Name);
107 free(vao);
108 }
109 }
110
111 void
112 _mesa_glthread_GenVertexArrays(struct gl_context *ctx,
113 GLsizei n, GLuint *arrays)
114 {
115 struct glthread_state *glthread = &ctx->GLThread;
116
117 if (!arrays)
118 return;
119
120 /* The IDs have been generated at this point. Create VAOs for glthread. */
121 for (int i = 0; i < n; i++) {
122 GLuint id = arrays[i];
123 struct glthread_vao *vao;
124
125 vao = calloc(1, sizeof(*vao));
126 if (!vao)
127 continue; /* Is that all we can do? */
128
129 vao->Name = id;
130 _mesa_HashInsertLocked(glthread->VAOs, id, vao);
131 }
132 }
133
134 /* If vaobj is NULL, use the currently-bound VAO. */
135 static inline struct glthread_vao *
136 get_vao(struct gl_context *ctx, const GLuint *vaobj)
137 {
138 if (vaobj)
139 return lookup_vao(ctx, *vaobj);
140
141 return ctx->GLThread.CurrentVAO;
142 }
143
144 static void
145 update_primitive_restart(struct gl_context *ctx)
146 {
147 struct glthread_state *glthread = &ctx->GLThread;
148
149 glthread->_PrimitiveRestart = glthread->PrimitiveRestart ||
150 glthread->PrimitiveRestartFixedIndex;
151 glthread->_RestartIndex[0] =
152 _mesa_get_prim_restart_index(glthread->PrimitiveRestartFixedIndex,
153 glthread->RestartIndex, 1);
154 glthread->_RestartIndex[1] =
155 _mesa_get_prim_restart_index(glthread->PrimitiveRestartFixedIndex,
156 glthread->RestartIndex, 2);
157 glthread->_RestartIndex[3] =
158 _mesa_get_prim_restart_index(glthread->PrimitiveRestartFixedIndex,
159 glthread->RestartIndex, 4);
160 }
161
162 void
163 _mesa_glthread_set_prim_restart(struct gl_context *ctx, GLenum cap, bool value)
164 {
165 switch (cap) {
166 case GL_PRIMITIVE_RESTART:
167 ctx->GLThread.PrimitiveRestart = value;
168 break;
169 case GL_PRIMITIVE_RESTART_FIXED_INDEX:
170 ctx->GLThread.PrimitiveRestartFixedIndex = value;
171 break;
172 }
173
174 update_primitive_restart(ctx);
175 }
176
177 void
178 _mesa_glthread_PrimitiveRestartIndex(struct gl_context *ctx, GLuint index)
179 {
180 ctx->GLThread.RestartIndex = index;
181 update_primitive_restart(ctx);
182 }
183
184 void
185 _mesa_glthread_ClientState(struct gl_context *ctx, GLuint *vaobj,
186 gl_vert_attrib attrib, bool enable)
187 {
188 /* The primitive restart client state uses a special value. */
189 if (attrib == VERT_ATTRIB_PRIMITIVE_RESTART_NV) {
190 ctx->GLThread.PrimitiveRestart = enable;
191 update_primitive_restart(ctx);
192 return;
193 }
194
195 if (attrib >= VERT_ATTRIB_MAX)
196 return;
197
198 struct glthread_vao *vao = get_vao(ctx, vaobj);
199 if (!vao)
200 return;
201
202 if (enable)
203 vao->Enabled |= 1u << attrib;
204 else
205 vao->Enabled &= ~(1u << attrib);
206 }
207
208 void _mesa_glthread_AttribDivisor(struct gl_context *ctx, const GLuint *vaobj,
209 gl_vert_attrib attrib, GLuint divisor)
210 {
211 if (attrib >= VERT_ATTRIB_MAX)
212 return;
213
214 struct glthread_vao *vao = get_vao(ctx, vaobj);
215 if (!vao)
216 return;
217
218 vao->Attrib[attrib].Divisor = divisor;
219
220 if (divisor)
221 vao->NonZeroDivisorMask |= 1u << attrib;
222 else
223 vao->NonZeroDivisorMask &= ~(1u << attrib);
224 }
225
226 static void
227 attrib_pointer(struct glthread_state *glthread, struct glthread_vao *vao,
228 GLuint buffer, gl_vert_attrib attrib,
229 GLint size, GLenum type, GLsizei stride,
230 const void *pointer)
231 {
232 if (attrib >= VERT_ATTRIB_MAX)
233 return;
234
235 unsigned elem_size = _mesa_bytes_per_vertex_attrib(size, type);
236
237 vao->Attrib[attrib].ElementSize = elem_size;
238 vao->Attrib[attrib].Stride = stride ? stride : elem_size;
239 vao->Attrib[attrib].Pointer = pointer;
240
241 if (buffer != 0)
242 vao->UserPointerMask &= ~(1u << attrib);
243 else
244 vao->UserPointerMask |= 1u << attrib;
245 }
246
247 void
248 _mesa_glthread_AttribPointer(struct gl_context *ctx, gl_vert_attrib attrib,
249 GLint size, GLenum type, GLsizei stride,
250 const void *pointer)
251 {
252 struct glthread_state *glthread = &ctx->GLThread;
253
254 attrib_pointer(glthread, glthread->CurrentVAO,
255 glthread->CurrentArrayBufferName,
256 attrib, size, type, stride, pointer);
257 }
258
259 void
260 _mesa_glthread_DSAAttribPointer(struct gl_context *ctx, GLuint vaobj,
261 GLuint buffer, gl_vert_attrib attrib,
262 GLint size, GLenum type, GLsizei stride,
263 GLintptr offset)
264 {
265 struct glthread_state *glthread = &ctx->GLThread;
266 struct glthread_vao *vao;
267
268 vao = lookup_vao(ctx, vaobj);
269 if (!vao)
270 return;
271
272 attrib_pointer(glthread, vao, buffer, attrib, size, type, stride,
273 (const void*)offset);
274 }