glthread: handle buffer unbinding via glDeleteBuffers
[mesa.git] / src / mesa / main / glthread_bufferobj.c
1 /*
2 * Copyright © 2012 Intel Corporation
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 #include "glthread_marshal.h"
25 #include "dispatch.h"
26
27 /** Tracks the current bindings for the vertex array and index array buffers.
28 *
29 * This is part of what we need to enable glthread on compat-GL contexts that
30 * happen to use VBOs, without also supporting the full tracking of VBO vs
31 * user vertex array bindings per attribute on each vertex array for
32 * determining what to upload at draw call time.
33 *
34 * Note that GL core makes it so that a buffer binding with an invalid handle
35 * in the "buffer" parameter will throw an error, and then a
36 * glVertexAttribPointer() that followsmight not end up pointing at a VBO.
37 * However, in GL core the draw call would throw an error as well, so we don't
38 * really care if our tracking is wrong for this case -- we never need to
39 * marshal user data for draw calls, and the unmarshal will just generate an
40 * error or not as appropriate.
41 *
42 * For compatibility GL, we do need to accurately know whether the draw call
43 * on the unmarshal side will dereference a user pointer or load data from a
44 * VBO per vertex. That would make it seem like we need to track whether a
45 * "buffer" is valid, so that we can know when an error will be generated
46 * instead of updating the binding. However, compat GL has the ridiculous
47 * feature that if you pass a bad name, it just gens a buffer object for you,
48 * so we escape without having to know if things are valid or not.
49 */
50 void
51 _mesa_glthread_BindBuffer(struct gl_context *ctx, GLenum target, GLuint buffer)
52 {
53 struct glthread_state *glthread = &ctx->GLThread;
54
55 switch (target) {
56 case GL_ARRAY_BUFFER:
57 glthread->CurrentArrayBufferName = buffer;
58 break;
59 case GL_ELEMENT_ARRAY_BUFFER:
60 /* The current element array buffer binding is actually tracked in the
61 * vertex array object instead of the context, so this would need to
62 * change on vertex array object updates.
63 */
64 glthread->CurrentVAO->CurrentElementBufferName = buffer;
65 break;
66 case GL_DRAW_INDIRECT_BUFFER:
67 glthread->CurrentDrawIndirectBufferName = buffer;
68 break;
69 }
70 }
71
72 void
73 _mesa_glthread_DeleteBuffers(struct gl_context *ctx, GLsizei n,
74 const GLuint *buffers)
75 {
76 struct glthread_state *glthread = &ctx->GLThread;
77
78 if (!buffers)
79 return;
80
81 for (unsigned i = 0; i < n; i++) {
82 GLuint id = buffers[i];
83
84 if (id == glthread->CurrentArrayBufferName)
85 _mesa_glthread_BindBuffer(ctx, GL_ARRAY_BUFFER, 0);
86 if (id == glthread->CurrentVAO->CurrentElementBufferName)
87 _mesa_glthread_BindBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, 0);
88 if (id == glthread->CurrentDrawIndirectBufferName)
89 _mesa_glthread_BindBuffer(ctx, GL_DRAW_INDIRECT_BUFFER, 0);
90 }
91 }
92
93 /* BufferData: marshalled asynchronously */
94 struct marshal_cmd_BufferData
95 {
96 struct marshal_cmd_base cmd_base;
97 GLuint target_or_name;
98 GLsizeiptr size;
99 GLenum usage;
100 const GLvoid *data_external_mem;
101 bool data_null; /* If set, no data follows for "data" */
102 bool named;
103 bool ext_dsa;
104 /* Next size bytes are GLubyte data[size] */
105 };
106
107 void
108 _mesa_unmarshal_BufferData(struct gl_context *ctx,
109 const struct marshal_cmd_BufferData *cmd)
110 {
111 const GLuint target_or_name = cmd->target_or_name;
112 const GLsizei size = cmd->size;
113 const GLenum usage = cmd->usage;
114 const void *data;
115
116 if (cmd->data_null)
117 data = NULL;
118 else if (!cmd->named && target_or_name == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD)
119 data = cmd->data_external_mem;
120 else
121 data = (const void *) (cmd + 1);
122
123 if (cmd->ext_dsa) {
124 CALL_NamedBufferDataEXT(ctx->CurrentServerDispatch,
125 (target_or_name, size, data, usage));
126 } else if (cmd->named) {
127 CALL_NamedBufferData(ctx->CurrentServerDispatch,
128 (target_or_name, size, data, usage));
129 } else {
130 CALL_BufferData(ctx->CurrentServerDispatch,
131 (target_or_name, size, data, usage));
132 }
133 }
134
135 void
136 _mesa_unmarshal_NamedBufferData(struct gl_context *ctx,
137 const struct marshal_cmd_NamedBufferData *cmd)
138 {
139 unreachable("never used - all BufferData variants use DISPATCH_CMD_BufferData");
140 }
141
142 void
143 _mesa_unmarshal_NamedBufferDataEXT(struct gl_context *ctx,
144 const struct marshal_cmd_NamedBufferDataEXT *cmd)
145 {
146 unreachable("never used - all BufferData variants use DISPATCH_CMD_BufferData");
147 }
148
149 static void
150 _mesa_marshal_BufferData_merged(GLuint target_or_name, GLsizeiptr size,
151 const GLvoid *data, GLenum usage, bool named,
152 bool ext_dsa, const char *func)
153 {
154 GET_CURRENT_CONTEXT(ctx);
155 bool external_mem = !named &&
156 target_or_name == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD;
157 bool copy_data = data && !external_mem;
158 int cmd_size = sizeof(struct marshal_cmd_BufferData) + (copy_data ? size : 0);
159
160 if (unlikely(size < 0 || size > INT_MAX || cmd_size < 0 ||
161 cmd_size > MARSHAL_MAX_CMD_SIZE ||
162 (named && target_or_name == 0))) {
163 _mesa_glthread_finish_before(ctx, func);
164 if (named) {
165 CALL_NamedBufferData(ctx->CurrentServerDispatch,
166 (target_or_name, size, data, usage));
167 } else {
168 CALL_BufferData(ctx->CurrentServerDispatch,
169 (target_or_name, size, data, usage));
170 }
171 return;
172 }
173
174 struct marshal_cmd_BufferData *cmd =
175 _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_BufferData,
176 cmd_size);
177
178 cmd->target_or_name = target_or_name;
179 cmd->size = size;
180 cmd->usage = usage;
181 cmd->data_null = !data;
182 cmd->named = named;
183 cmd->ext_dsa = ext_dsa;
184 cmd->data_external_mem = data;
185
186 if (copy_data) {
187 char *variable_data = (char *) (cmd + 1);
188 memcpy(variable_data, data, size);
189 }
190 }
191
192 void GLAPIENTRY
193 _mesa_marshal_BufferData(GLenum target, GLsizeiptr size, const GLvoid * data,
194 GLenum usage)
195 {
196 _mesa_marshal_BufferData_merged(target, size, data, usage, false, false,
197 "BufferData");
198 }
199
200 void GLAPIENTRY
201 _mesa_marshal_NamedBufferData(GLuint buffer, GLsizeiptr size,
202 const GLvoid * data, GLenum usage)
203 {
204 _mesa_marshal_BufferData_merged(buffer, size, data, usage, true, false,
205 "NamedBufferData");
206 }
207
208 void GLAPIENTRY
209 _mesa_marshal_NamedBufferDataEXT(GLuint buffer, GLsizeiptr size,
210 const GLvoid *data, GLenum usage)
211 {
212 _mesa_marshal_BufferData_merged(buffer, size, data, usage, true, true,
213 "NamedBufferDataEXT");
214 }
215
216
217 /* BufferSubData: marshalled asynchronously */
218 struct marshal_cmd_BufferSubData
219 {
220 struct marshal_cmd_base cmd_base;
221 GLenum target_or_name;
222 GLintptr offset;
223 GLsizeiptr size;
224 bool named;
225 bool ext_dsa;
226 /* Next size bytes are GLubyte data[size] */
227 };
228
229 void
230 _mesa_unmarshal_BufferSubData(struct gl_context *ctx,
231 const struct marshal_cmd_BufferSubData *cmd)
232 {
233 const GLenum target_or_name = cmd->target_or_name;
234 const GLintptr offset = cmd->offset;
235 const GLsizeiptr size = cmd->size;
236 const void *data = (const void *) (cmd + 1);
237
238 if (cmd->ext_dsa) {
239 CALL_NamedBufferSubDataEXT(ctx->CurrentServerDispatch,
240 (target_or_name, offset, size, data));
241 } else if (cmd->named) {
242 CALL_NamedBufferSubData(ctx->CurrentServerDispatch,
243 (target_or_name, offset, size, data));
244 } else {
245 CALL_BufferSubData(ctx->CurrentServerDispatch,
246 (target_or_name, offset, size, data));
247 }
248 }
249
250 void
251 _mesa_unmarshal_NamedBufferSubData(struct gl_context *ctx,
252 const struct marshal_cmd_NamedBufferSubData *cmd)
253 {
254 unreachable("never used - all BufferSubData variants use DISPATCH_CMD_BufferSubData");
255 }
256
257 void
258 _mesa_unmarshal_NamedBufferSubDataEXT(struct gl_context *ctx,
259 const struct marshal_cmd_NamedBufferSubDataEXT *cmd)
260 {
261 unreachable("never used - all BufferSubData variants use DISPATCH_CMD_BufferSubData");
262 }
263
264 static void
265 _mesa_marshal_BufferSubData_merged(GLuint target_or_name, GLintptr offset,
266 GLsizeiptr size, const GLvoid *data,
267 bool named, bool ext_dsa, const char *func)
268 {
269 GET_CURRENT_CONTEXT(ctx);
270 size_t cmd_size = sizeof(struct marshal_cmd_BufferSubData) + size;
271
272 if (unlikely(size < 0 || size > INT_MAX || cmd_size < 0 ||
273 cmd_size > MARSHAL_MAX_CMD_SIZE || !data ||
274 (named && target_or_name == 0))) {
275 _mesa_glthread_finish_before(ctx, func);
276 if (named) {
277 CALL_NamedBufferSubData(ctx->CurrentServerDispatch,
278 (target_or_name, offset, size, data));
279 } else {
280 CALL_BufferSubData(ctx->CurrentServerDispatch,
281 (target_or_name, offset, size, data));
282 }
283 return;
284 }
285
286 struct marshal_cmd_BufferSubData *cmd =
287 _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_BufferSubData,
288 cmd_size);
289 cmd->target_or_name = target_or_name;
290 cmd->offset = offset;
291 cmd->size = size;
292 cmd->named = named;
293 cmd->ext_dsa = ext_dsa;
294
295 char *variable_data = (char *) (cmd + 1);
296 memcpy(variable_data, data, size);
297 }
298
299 void GLAPIENTRY
300 _mesa_marshal_BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size,
301 const GLvoid * data)
302 {
303 _mesa_marshal_BufferSubData_merged(target, offset, size, data, false,
304 false, "BufferSubData");
305 }
306
307 void GLAPIENTRY
308 _mesa_marshal_NamedBufferSubData(GLuint buffer, GLintptr offset,
309 GLsizeiptr size, const GLvoid * data)
310 {
311 _mesa_marshal_BufferSubData_merged(buffer, offset, size, data, true,
312 false, "NamedBufferSubData");
313 }
314
315 void GLAPIENTRY
316 _mesa_marshal_NamedBufferSubDataEXT(GLuint buffer, GLintptr offset,
317 GLsizeiptr size, const GLvoid * data)
318 {
319 _mesa_marshal_BufferSubData_merged(buffer, offset, size, data, true,
320 true, "NamedBufferSubDataEXT");
321 }