2 * Copyright © 2012 Intel Corporation
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:
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
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
24 #include "glthread_marshal.h"
27 /** Tracks the current bindings for the vertex array and index array buffers.
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.
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.
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.
51 _mesa_glthread_BindBuffer(struct gl_context
*ctx
, GLenum target
, GLuint buffer
)
53 struct glthread_state
*glthread
= &ctx
->GLThread
;
57 glthread
->CurrentArrayBufferName
= buffer
;
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.
64 glthread
->CurrentVAO
->CurrentElementBufferName
= buffer
;
66 case GL_DRAW_INDIRECT_BUFFER
:
67 glthread
->CurrentDrawIndirectBufferName
= buffer
;
73 _mesa_glthread_DeleteBuffers(struct gl_context
*ctx
, GLsizei n
,
74 const GLuint
*buffers
)
76 struct glthread_state
*glthread
= &ctx
->GLThread
;
81 for (unsigned i
= 0; i
< n
; i
++) {
82 GLuint id
= buffers
[i
];
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);
93 /* BufferData: marshalled asynchronously */
94 struct marshal_cmd_BufferData
96 struct marshal_cmd_base cmd_base
;
97 GLuint target_or_name
;
100 const GLvoid
*data_external_mem
;
101 bool data_null
; /* If set, no data follows for "data" */
104 /* Next size bytes are GLubyte data[size] */
108 _mesa_unmarshal_BufferData(struct gl_context
*ctx
,
109 const struct marshal_cmd_BufferData
*cmd
)
111 const GLuint target_or_name
= cmd
->target_or_name
;
112 const GLsizei size
= cmd
->size
;
113 const GLenum usage
= cmd
->usage
;
118 else if (!cmd
->named
&& target_or_name
== GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD
)
119 data
= cmd
->data_external_mem
;
121 data
= (const void *) (cmd
+ 1);
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
));
130 CALL_BufferData(ctx
->CurrentServerDispatch
,
131 (target_or_name
, size
, data
, usage
));
136 _mesa_unmarshal_NamedBufferData(struct gl_context
*ctx
,
137 const struct marshal_cmd_NamedBufferData
*cmd
)
139 unreachable("never used - all BufferData variants use DISPATCH_CMD_BufferData");
143 _mesa_unmarshal_NamedBufferDataEXT(struct gl_context
*ctx
,
144 const struct marshal_cmd_NamedBufferDataEXT
*cmd
)
146 unreachable("never used - all BufferData variants use DISPATCH_CMD_BufferData");
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
)
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);
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
);
165 CALL_NamedBufferData(ctx
->CurrentServerDispatch
,
166 (target_or_name
, size
, data
, usage
));
168 CALL_BufferData(ctx
->CurrentServerDispatch
,
169 (target_or_name
, size
, data
, usage
));
174 struct marshal_cmd_BufferData
*cmd
=
175 _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_BufferData
,
178 cmd
->target_or_name
= target_or_name
;
181 cmd
->data_null
= !data
;
183 cmd
->ext_dsa
= ext_dsa
;
184 cmd
->data_external_mem
= data
;
187 char *variable_data
= (char *) (cmd
+ 1);
188 memcpy(variable_data
, data
, size
);
193 _mesa_marshal_BufferData(GLenum target
, GLsizeiptr size
, const GLvoid
* data
,
196 _mesa_marshal_BufferData_merged(target
, size
, data
, usage
, false, false,
201 _mesa_marshal_NamedBufferData(GLuint buffer
, GLsizeiptr size
,
202 const GLvoid
* data
, GLenum usage
)
204 _mesa_marshal_BufferData_merged(buffer
, size
, data
, usage
, true, false,
209 _mesa_marshal_NamedBufferDataEXT(GLuint buffer
, GLsizeiptr size
,
210 const GLvoid
*data
, GLenum usage
)
212 _mesa_marshal_BufferData_merged(buffer
, size
, data
, usage
, true, true,
213 "NamedBufferDataEXT");
217 /* BufferSubData: marshalled asynchronously */
218 struct marshal_cmd_BufferSubData
220 struct marshal_cmd_base cmd_base
;
221 GLenum target_or_name
;
226 /* Next size bytes are GLubyte data[size] */
230 _mesa_unmarshal_BufferSubData(struct gl_context
*ctx
,
231 const struct marshal_cmd_BufferSubData
*cmd
)
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);
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
));
245 CALL_BufferSubData(ctx
->CurrentServerDispatch
,
246 (target_or_name
, offset
, size
, data
));
251 _mesa_unmarshal_NamedBufferSubData(struct gl_context
*ctx
,
252 const struct marshal_cmd_NamedBufferSubData
*cmd
)
254 unreachable("never used - all BufferSubData variants use DISPATCH_CMD_BufferSubData");
258 _mesa_unmarshal_NamedBufferSubDataEXT(struct gl_context
*ctx
,
259 const struct marshal_cmd_NamedBufferSubDataEXT
*cmd
)
261 unreachable("never used - all BufferSubData variants use DISPATCH_CMD_BufferSubData");
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
)
269 GET_CURRENT_CONTEXT(ctx
);
270 size_t cmd_size
= sizeof(struct marshal_cmd_BufferSubData
) + size
;
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
);
277 CALL_NamedBufferSubData(ctx
->CurrentServerDispatch
,
278 (target_or_name
, offset
, size
, data
));
280 CALL_BufferSubData(ctx
->CurrentServerDispatch
,
281 (target_or_name
, offset
, size
, data
));
286 struct marshal_cmd_BufferSubData
*cmd
=
287 _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_BufferSubData
,
289 cmd
->target_or_name
= target_or_name
;
290 cmd
->offset
= offset
;
293 cmd
->ext_dsa
= ext_dsa
;
295 char *variable_data
= (char *) (cmd
+ 1);
296 memcpy(variable_data
, data
, size
);
300 _mesa_marshal_BufferSubData(GLenum target
, GLintptr offset
, GLsizeiptr size
,
303 _mesa_marshal_BufferSubData_merged(target
, offset
, size
, data
, false,
304 false, "BufferSubData");
308 _mesa_marshal_NamedBufferSubData(GLuint buffer
, GLintptr offset
,
309 GLsizeiptr size
, const GLvoid
* data
)
311 _mesa_marshal_BufferSubData_merged(buffer
, offset
, size
, data
, true,
312 false, "NamedBufferSubData");
316 _mesa_marshal_NamedBufferSubDataEXT(GLuint buffer
, GLintptr offset
,
317 GLsizeiptr size
, const GLvoid
* data
)
319 _mesa_marshal_BufferSubData_merged(buffer
, offset
, size
, data
, true,
320 true, "NamedBufferSubDataEXT");