872bcbc69b88480716f33fecda9d8299db2222ed
[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->vertex_array_is_vbo = (buffer != 0);
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->IndexBufferIsUserPointer = buffer != 0;
65 break;
66 case GL_DRAW_INDIRECT_BUFFER:
67 glthread->draw_indirect_buffer_is_vbo = buffer != 0;
68 break;
69 }
70 }
71
72
73 /* BufferData: marshalled asynchronously */
74 struct marshal_cmd_BufferData
75 {
76 struct marshal_cmd_base cmd_base;
77 GLuint target_or_name;
78 GLsizeiptr size;
79 GLenum usage;
80 const GLvoid *data_external_mem;
81 bool data_null; /* If set, no data follows for "data" */
82 bool named;
83 bool ext_dsa;
84 /* Next size bytes are GLubyte data[size] */
85 };
86
87 void
88 _mesa_unmarshal_BufferData(struct gl_context *ctx,
89 const struct marshal_cmd_BufferData *cmd)
90 {
91 const GLuint target_or_name = cmd->target_or_name;
92 const GLsizei size = cmd->size;
93 const GLenum usage = cmd->usage;
94 const void *data;
95
96 if (cmd->data_null)
97 data = NULL;
98 else if (!cmd->named && target_or_name == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD)
99 data = cmd->data_external_mem;
100 else
101 data = (const void *) (cmd + 1);
102
103 if (cmd->ext_dsa) {
104 CALL_NamedBufferDataEXT(ctx->CurrentServerDispatch,
105 (target_or_name, size, data, usage));
106 } else if (cmd->named) {
107 CALL_NamedBufferData(ctx->CurrentServerDispatch,
108 (target_or_name, size, data, usage));
109 } else {
110 CALL_BufferData(ctx->CurrentServerDispatch,
111 (target_or_name, size, data, usage));
112 }
113 }
114
115 void
116 _mesa_unmarshal_NamedBufferData(struct gl_context *ctx,
117 const struct marshal_cmd_NamedBufferData *cmd)
118 {
119 unreachable("never used - all BufferData variants use DISPATCH_CMD_BufferData");
120 }
121
122 void
123 _mesa_unmarshal_NamedBufferDataEXT(struct gl_context *ctx,
124 const struct marshal_cmd_NamedBufferDataEXT *cmd)
125 {
126 unreachable("never used - all BufferData variants use DISPATCH_CMD_BufferData");
127 }
128
129 static void
130 _mesa_marshal_BufferData_merged(GLuint target_or_name, GLsizeiptr size,
131 const GLvoid *data, GLenum usage, bool named,
132 bool ext_dsa, const char *func)
133 {
134 GET_CURRENT_CONTEXT(ctx);
135 bool external_mem = !named &&
136 target_or_name == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD;
137 bool copy_data = data && !external_mem;
138 int cmd_size = sizeof(struct marshal_cmd_BufferData) + (copy_data ? size : 0);
139
140 if (unlikely(size < 0 || size > INT_MAX || cmd_size < 0 ||
141 cmd_size > MARSHAL_MAX_CMD_SIZE ||
142 (named && target_or_name == 0))) {
143 _mesa_glthread_finish_before(ctx, func);
144 if (named) {
145 CALL_NamedBufferData(ctx->CurrentServerDispatch,
146 (target_or_name, size, data, usage));
147 } else {
148 CALL_BufferData(ctx->CurrentServerDispatch,
149 (target_or_name, size, data, usage));
150 }
151 return;
152 }
153
154 struct marshal_cmd_BufferData *cmd =
155 _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_BufferData,
156 cmd_size);
157
158 cmd->target_or_name = target_or_name;
159 cmd->size = size;
160 cmd->usage = usage;
161 cmd->data_null = !data;
162 cmd->named = named;
163 cmd->ext_dsa = ext_dsa;
164 cmd->data_external_mem = data;
165
166 if (copy_data) {
167 char *variable_data = (char *) (cmd + 1);
168 memcpy(variable_data, data, size);
169 }
170 }
171
172 void GLAPIENTRY
173 _mesa_marshal_BufferData(GLenum target, GLsizeiptr size, const GLvoid * data,
174 GLenum usage)
175 {
176 _mesa_marshal_BufferData_merged(target, size, data, usage, false, false,
177 "BufferData");
178 }
179
180 void GLAPIENTRY
181 _mesa_marshal_NamedBufferData(GLuint buffer, GLsizeiptr size,
182 const GLvoid * data, GLenum usage)
183 {
184 _mesa_marshal_BufferData_merged(buffer, size, data, usage, true, false,
185 "NamedBufferData");
186 }
187
188 void GLAPIENTRY
189 _mesa_marshal_NamedBufferDataEXT(GLuint buffer, GLsizeiptr size,
190 const GLvoid *data, GLenum usage)
191 {
192 _mesa_marshal_BufferData_merged(buffer, size, data, usage, true, true,
193 "NamedBufferDataEXT");
194 }
195
196
197 /* BufferSubData: marshalled asynchronously */
198 struct marshal_cmd_BufferSubData
199 {
200 struct marshal_cmd_base cmd_base;
201 GLenum target_or_name;
202 GLintptr offset;
203 GLsizeiptr size;
204 bool named;
205 bool ext_dsa;
206 /* Next size bytes are GLubyte data[size] */
207 };
208
209 void
210 _mesa_unmarshal_BufferSubData(struct gl_context *ctx,
211 const struct marshal_cmd_BufferSubData *cmd)
212 {
213 const GLenum target_or_name = cmd->target_or_name;
214 const GLintptr offset = cmd->offset;
215 const GLsizeiptr size = cmd->size;
216 const void *data = (const void *) (cmd + 1);
217
218 if (cmd->ext_dsa) {
219 CALL_NamedBufferSubDataEXT(ctx->CurrentServerDispatch,
220 (target_or_name, offset, size, data));
221 } else if (cmd->named) {
222 CALL_NamedBufferSubData(ctx->CurrentServerDispatch,
223 (target_or_name, offset, size, data));
224 } else {
225 CALL_BufferSubData(ctx->CurrentServerDispatch,
226 (target_or_name, offset, size, data));
227 }
228 }
229
230 void
231 _mesa_unmarshal_NamedBufferSubData(struct gl_context *ctx,
232 const struct marshal_cmd_NamedBufferSubData *cmd)
233 {
234 unreachable("never used - all BufferSubData variants use DISPATCH_CMD_BufferSubData");
235 }
236
237 void
238 _mesa_unmarshal_NamedBufferSubDataEXT(struct gl_context *ctx,
239 const struct marshal_cmd_NamedBufferSubDataEXT *cmd)
240 {
241 unreachable("never used - all BufferSubData variants use DISPATCH_CMD_BufferSubData");
242 }
243
244 static void
245 _mesa_marshal_BufferSubData_merged(GLuint target_or_name, GLintptr offset,
246 GLsizeiptr size, const GLvoid *data,
247 bool named, bool ext_dsa, const char *func)
248 {
249 GET_CURRENT_CONTEXT(ctx);
250 size_t cmd_size = sizeof(struct marshal_cmd_BufferSubData) + size;
251
252 if (unlikely(size < 0 || size > INT_MAX || cmd_size < 0 ||
253 cmd_size > MARSHAL_MAX_CMD_SIZE || !data ||
254 (named && target_or_name == 0))) {
255 _mesa_glthread_finish_before(ctx, func);
256 if (named) {
257 CALL_NamedBufferSubData(ctx->CurrentServerDispatch,
258 (target_or_name, offset, size, data));
259 } else {
260 CALL_BufferSubData(ctx->CurrentServerDispatch,
261 (target_or_name, offset, size, data));
262 }
263 return;
264 }
265
266 struct marshal_cmd_BufferSubData *cmd =
267 _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_BufferSubData,
268 cmd_size);
269 cmd->target_or_name = target_or_name;
270 cmd->offset = offset;
271 cmd->size = size;
272 cmd->named = named;
273 cmd->ext_dsa = ext_dsa;
274
275 char *variable_data = (char *) (cmd + 1);
276 memcpy(variable_data, data, size);
277 }
278
279 void GLAPIENTRY
280 _mesa_marshal_BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size,
281 const GLvoid * data)
282 {
283 _mesa_marshal_BufferSubData_merged(target, offset, size, data, false,
284 false, "BufferSubData");
285 }
286
287 void GLAPIENTRY
288 _mesa_marshal_NamedBufferSubData(GLuint buffer, GLintptr offset,
289 GLsizeiptr size, const GLvoid * data)
290 {
291 _mesa_marshal_BufferSubData_merged(buffer, offset, size, data, true,
292 false, "NamedBufferSubData");
293 }
294
295 void GLAPIENTRY
296 _mesa_marshal_NamedBufferSubDataEXT(GLuint buffer, GLintptr offset,
297 GLsizeiptr size, const GLvoid * data)
298 {
299 _mesa_marshal_BufferSubData_merged(buffer, offset, size, data, true,
300 true, "NamedBufferSubDataEXT");
301 }