glthread: track instance divisor changes
[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
35 /* TODO:
36 * - Handle ARB_vertex_attrib_binding (incl. EXT_dsa and ARB_dsa)
37 */
38
39 static struct glthread_vao *
40 lookup_vao(struct gl_context *ctx, GLuint id)
41 {
42 struct glthread_state *glthread = &ctx->GLThread;
43 struct glthread_vao *vao;
44
45 assert(id != 0);
46
47 if (glthread->LastLookedUpVAO &&
48 glthread->LastLookedUpVAO->Name == id) {
49 vao = glthread->LastLookedUpVAO;
50 } else {
51 vao = _mesa_HashLookupLocked(glthread->VAOs, id);
52 if (!vao)
53 return NULL;
54
55 glthread->LastLookedUpVAO = vao;
56 }
57
58 return vao;
59 }
60
61 void
62 _mesa_glthread_BindVertexArray(struct gl_context *ctx, GLuint id)
63 {
64 struct glthread_state *glthread = &ctx->GLThread;
65
66 if (id == 0) {
67 glthread->CurrentVAO = &glthread->DefaultVAO;
68 } else {
69 struct glthread_vao *vao = lookup_vao(ctx, id);
70
71 if (vao)
72 glthread->CurrentVAO = vao;
73 }
74 }
75
76 void
77 _mesa_glthread_DeleteVertexArrays(struct gl_context *ctx,
78 GLsizei n, const GLuint *ids)
79 {
80 struct glthread_state *glthread = &ctx->GLThread;
81
82 if (!ids)
83 return;
84
85 for (int i = 0; i < n; i++) {
86 /* IDs equal to 0 should be silently ignored. */
87 if (!ids[i])
88 continue;
89
90 struct glthread_vao *vao = lookup_vao(ctx, ids[i]);
91 if (!vao)
92 continue;
93
94 /* If the array object is currently bound, the spec says "the binding
95 * for that object reverts to zero and the default vertex array
96 * becomes current."
97 */
98 if (glthread->CurrentVAO == vao)
99 glthread->CurrentVAO = &glthread->DefaultVAO;
100
101 if (glthread->LastLookedUpVAO == vao)
102 glthread->LastLookedUpVAO = NULL;
103
104 /* The ID is immediately freed for re-use */
105 _mesa_HashRemoveLocked(glthread->VAOs, vao->Name);
106 free(vao);
107 }
108 }
109
110 void
111 _mesa_glthread_GenVertexArrays(struct gl_context *ctx,
112 GLsizei n, GLuint *arrays)
113 {
114 struct glthread_state *glthread = &ctx->GLThread;
115
116 if (!arrays)
117 return;
118
119 /* The IDs have been generated at this point. Create VAOs for glthread. */
120 for (int i = 0; i < n; i++) {
121 GLuint id = arrays[i];
122 struct glthread_vao *vao;
123
124 vao = calloc(1, sizeof(*vao));
125 if (!vao)
126 continue; /* Is that all we can do? */
127
128 vao->Name = id;
129 _mesa_HashInsertLocked(glthread->VAOs, id, vao);
130 }
131 }
132
133 /* If vaobj is NULL, use the currently-bound VAO. */
134 static inline struct glthread_vao *
135 get_vao(struct gl_context *ctx, const GLuint *vaobj)
136 {
137 if (vaobj)
138 return lookup_vao(ctx, *vaobj);
139
140 return ctx->GLThread.CurrentVAO;
141 }
142
143 void
144 _mesa_glthread_ClientState(struct gl_context *ctx, GLuint *vaobj,
145 gl_vert_attrib attrib, bool enable)
146 {
147 if (attrib >= VERT_ATTRIB_MAX)
148 return;
149
150 struct glthread_vao *vao = get_vao(ctx, vaobj);
151 if (!vao)
152 return;
153
154 if (enable)
155 vao->Enabled |= 1u << attrib;
156 else
157 vao->Enabled &= ~(1u << attrib);
158 }
159
160 void _mesa_glthread_AttribDivisor(struct gl_context *ctx, const GLuint *vaobj,
161 gl_vert_attrib attrib, GLuint divisor)
162 {
163 if (attrib >= VERT_ATTRIB_MAX)
164 return;
165
166 struct glthread_vao *vao = get_vao(ctx, vaobj);
167 if (!vao)
168 return;
169
170 vao->Attrib[attrib].Divisor = divisor;
171
172 if (divisor)
173 vao->NonZeroDivisorMask |= 1u << attrib;
174 else
175 vao->NonZeroDivisorMask &= ~(1u << attrib);
176 }
177
178 static void
179 attrib_pointer(struct glthread_state *glthread, struct glthread_vao *vao,
180 GLuint buffer, gl_vert_attrib attrib,
181 GLint size, GLenum type, GLsizei stride,
182 const void *pointer)
183 {
184 if (attrib >= VERT_ATTRIB_MAX)
185 return;
186
187 unsigned elem_size = _mesa_bytes_per_vertex_attrib(size, type);
188
189 vao->Attrib[attrib].ElementSize = elem_size;
190 vao->Attrib[attrib].Stride = stride ? stride : elem_size;
191 vao->Attrib[attrib].Pointer = pointer;
192
193 if (buffer != 0)
194 vao->UserPointerMask &= ~(1u << attrib);
195 else
196 vao->UserPointerMask |= 1u << attrib;
197 }
198
199 void
200 _mesa_glthread_AttribPointer(struct gl_context *ctx, gl_vert_attrib attrib,
201 GLint size, GLenum type, GLsizei stride,
202 const void *pointer)
203 {
204 struct glthread_state *glthread = &ctx->GLThread;
205
206 attrib_pointer(glthread, glthread->CurrentVAO,
207 glthread->CurrentArrayBufferName,
208 attrib, size, type, stride, pointer);
209 }
210
211 void
212 _mesa_glthread_DSAAttribPointer(struct gl_context *ctx, GLuint vaobj,
213 GLuint buffer, gl_vert_attrib attrib,
214 GLint size, GLenum type, GLsizei stride,
215 GLintptr offset)
216 {
217 struct glthread_state *glthread = &ctx->GLThread;
218 struct glthread_vao *vao;
219
220 vao = lookup_vao(ctx, vaobj);
221 if (!vao)
222 return;
223
224 attrib_pointer(glthread, vao, buffer, attrib, size, type, stride,
225 (const void*)offset);
226 }