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
26 * Custom functions for marshalling GL calls from the main thread to a worker
27 * thread when automatic code generation isn't appropriate.
30 #include "main/enums.h"
31 #include "main/macros.h"
36 _mesa_post_marshal_hook(struct gl_context
*ctx
)
38 /* This can be enabled for debugging whether a failure is a synchronization
39 * problem between the main thread and the worker thread, or a failure in
40 * how we actually marshal.
43 _mesa_glthread_finish(ctx
);
47 struct marshal_cmd_ShaderSource
49 struct marshal_cmd_base cmd_base
;
52 /* Followed by GLint length[count], then the contents of all strings,
59 _mesa_unmarshal_ShaderSource(struct gl_context
*ctx
,
60 const struct marshal_cmd_ShaderSource
*cmd
)
62 const GLint
*cmd_length
= (const GLint
*) (cmd
+ 1);
63 const GLchar
*cmd_strings
= (const GLchar
*) (cmd_length
+ cmd
->count
);
64 /* TODO: how to deal with malloc failure? */
65 const GLchar
* *string
= malloc(cmd
->count
* sizeof(const GLchar
*));
68 for (i
= 0; i
< cmd
->count
; ++i
) {
69 string
[i
] = cmd_strings
;
70 cmd_strings
+= cmd_length
[i
];
72 CALL_ShaderSource(ctx
->CurrentServerDispatch
,
73 (cmd
->shader
, cmd
->count
, string
, cmd_length
));
79 measure_ShaderSource_strings(GLsizei count
, const GLchar
* const *string
,
80 const GLint
*length_in
, GLint
*length_out
)
83 size_t total_string_length
= 0;
85 for (i
= 0; i
< count
; ++i
) {
86 if (length_in
== NULL
|| length_in
[i
] < 0) {
88 length_out
[i
] = strlen(string
[i
]);
90 length_out
[i
] = length_in
[i
];
92 total_string_length
+= length_out
[i
];
94 return total_string_length
;
99 _mesa_marshal_ShaderSource(GLuint shader
, GLsizei count
,
100 const GLchar
* const *string
, const GLint
*length
)
102 /* TODO: how to report an error if count < 0? */
104 GET_CURRENT_CONTEXT(ctx
);
105 /* TODO: how to deal with malloc failure? */
106 const size_t fixed_cmd_size
= sizeof(struct marshal_cmd_ShaderSource
);
107 STATIC_ASSERT(sizeof(struct marshal_cmd_ShaderSource
) % sizeof(GLint
) == 0);
108 size_t length_size
= count
* sizeof(GLint
);
109 GLint
*length_tmp
= malloc(length_size
);
110 size_t total_string_length
=
111 measure_ShaderSource_strings(count
, string
, length
, length_tmp
);
112 size_t total_cmd_size
= fixed_cmd_size
+ length_size
+ total_string_length
;
114 if (total_cmd_size
<= MARSHAL_MAX_CMD_SIZE
) {
115 struct marshal_cmd_ShaderSource
*cmd
=
116 _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_ShaderSource
,
118 GLint
*cmd_length
= (GLint
*) (cmd
+ 1);
119 GLchar
*cmd_strings
= (GLchar
*) (cmd_length
+ count
);
122 cmd
->shader
= shader
;
124 memcpy(cmd_length
, length_tmp
, length_size
);
125 for (i
= 0; i
< count
; ++i
) {
126 memcpy(cmd_strings
, string
[i
], cmd_length
[i
]);
127 cmd_strings
+= cmd_length
[i
];
129 _mesa_post_marshal_hook(ctx
);
131 _mesa_glthread_finish(ctx
);
132 CALL_ShaderSource(ctx
->CurrentServerDispatch
,
133 (shader
, count
, string
, length_tmp
));
139 /* BindBufferBase: marshalled asynchronously */
140 struct marshal_cmd_BindBufferBase
142 struct marshal_cmd_base cmd_base
;
148 /** Tracks the current bindings for the vertex array and index array buffers.
150 * This is part of what we need to enable glthread on compat-GL contexts that
151 * happen to use VBOs, without also supporting the full tracking of VBO vs
152 * user vertex array bindings per attribute on each vertex array for
153 * determining what to upload at draw call time.
155 * Note that GL core makes it so that a buffer binding with an invalid handle
156 * in the "buffer" parameter will throw an error, and then a
157 * glVertexAttribPointer() that followsmight not end up pointing at a VBO.
158 * However, in GL core the draw call would throw an error as well, so we don't
159 * really care if our tracking is wrong for this case -- we never need to
160 * marshal user data for draw calls, and the unmarshal will just generate an
161 * error or not as appropriate.
163 * For compatibility GL, we do need to accurately know whether the draw call
164 * on the unmarshal side will dereference a user pointer or load data from a
165 * VBO per vertex. That would make it seem like we need to track whether a
166 * "buffer" is valid, so that we can know when an error will be generated
167 * instead of updating the binding. However, compat GL has the ridiculous
168 * feature that if you pass a bad name, it just gens a buffer object for you,
169 * so we escape without having to know if things are valid or not.
172 track_vbo_binding(struct gl_context
*ctx
, GLenum target
, GLuint buffer
)
174 struct glthread_state
*glthread
= ctx
->GLThread
;
177 case GL_ARRAY_BUFFER
:
178 glthread
->vertex_array_is_vbo
= (buffer
!= 0);
180 case GL_ELEMENT_ARRAY_BUFFER
:
181 /* The current element array buffer binding is actually tracked in the
182 * vertex array object instead of the context, so this would need to
183 * change on vertex array object updates.
185 glthread
->element_array_is_vbo
= (buffer
!= 0);
187 case GL_DRAW_INDIRECT_BUFFER
:
188 glthread
->draw_indirect_buffer_is_vbo
= buffer
!= 0;
194 struct marshal_cmd_BindBuffer
196 struct marshal_cmd_base cmd_base
;
202 * This is just like the code-generated glBindBuffer() support, except that we
203 * call track_vbo_binding().
206 _mesa_unmarshal_BindBuffer(struct gl_context
*ctx
,
207 const struct marshal_cmd_BindBuffer
*cmd
)
209 const GLenum target
= cmd
->target
;
210 const GLuint buffer
= cmd
->buffer
;
211 CALL_BindBuffer(ctx
->CurrentServerDispatch
, (target
, buffer
));
214 _mesa_marshal_BindBuffer(GLenum target
, GLuint buffer
)
216 GET_CURRENT_CONTEXT(ctx
);
217 size_t cmd_size
= sizeof(struct marshal_cmd_BindBuffer
);
218 struct marshal_cmd_BindBuffer
*cmd
;
219 debug_print_marshal("BindBuffer");
221 track_vbo_binding(ctx
, target
, buffer
);
223 if (cmd_size
<= MARSHAL_MAX_CMD_SIZE
) {
224 cmd
= _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_BindBuffer
,
226 cmd
->target
= target
;
227 cmd
->buffer
= buffer
;
228 _mesa_post_marshal_hook(ctx
);
230 _mesa_glthread_finish(ctx
);
231 CALL_BindBuffer(ctx
->CurrentServerDispatch
, (target
, buffer
));
235 /* BufferData: marshalled asynchronously */
236 struct marshal_cmd_BufferData
238 struct marshal_cmd_base cmd_base
;
242 bool data_null
; /* If set, no data follows for "data" */
243 /* Next size bytes are GLubyte data[size] */
247 _mesa_unmarshal_BufferData(struct gl_context
*ctx
,
248 const struct marshal_cmd_BufferData
*cmd
)
250 const GLenum target
= cmd
->target
;
251 const GLsizeiptr size
= cmd
->size
;
252 const GLenum usage
= cmd
->usage
;
258 data
= (const void *) (cmd
+ 1);
260 CALL_BufferData(ctx
->CurrentServerDispatch
, (target
, size
, data
, usage
));
264 _mesa_marshal_BufferData(GLenum target
, GLsizeiptr size
, const GLvoid
* data
,
267 GET_CURRENT_CONTEXT(ctx
);
269 sizeof(struct marshal_cmd_BufferData
) + (data
? size
: 0);
270 debug_print_marshal("BufferData");
272 if (unlikely(size
< 0)) {
273 _mesa_glthread_finish(ctx
);
274 _mesa_error(ctx
, GL_INVALID_VALUE
, "BufferData(size < 0)");
278 if (target
!= GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD
&&
279 cmd_size
<= MARSHAL_MAX_CMD_SIZE
) {
280 struct marshal_cmd_BufferData
*cmd
=
281 _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_BufferData
,
284 cmd
->target
= target
;
287 cmd
->data_null
= !data
;
289 char *variable_data
= (char *) (cmd
+ 1);
290 memcpy(variable_data
, data
, size
);
292 _mesa_post_marshal_hook(ctx
);
294 _mesa_glthread_finish(ctx
);
295 CALL_BufferData(ctx
->CurrentServerDispatch
,
296 (target
, size
, data
, usage
));
300 /* BufferSubData: marshalled asynchronously */
301 struct marshal_cmd_BufferSubData
303 struct marshal_cmd_base cmd_base
;
307 /* Next size bytes are GLubyte data[size] */
311 _mesa_unmarshal_BufferSubData(struct gl_context
*ctx
,
312 const struct marshal_cmd_BufferSubData
*cmd
)
314 const GLenum target
= cmd
->target
;
315 const GLintptr offset
= cmd
->offset
;
316 const GLsizeiptr size
= cmd
->size
;
317 const void *data
= (const void *) (cmd
+ 1);
319 CALL_BufferSubData(ctx
->CurrentServerDispatch
,
320 (target
, offset
, size
, data
));
324 _mesa_marshal_BufferSubData(GLenum target
, GLintptr offset
, GLsizeiptr size
,
327 GET_CURRENT_CONTEXT(ctx
);
328 size_t cmd_size
= sizeof(struct marshal_cmd_BufferSubData
) + size
;
330 debug_print_marshal("BufferSubData");
331 if (unlikely(size
< 0)) {
332 _mesa_glthread_finish(ctx
);
333 _mesa_error(ctx
, GL_INVALID_VALUE
, "BufferSubData(size < 0)");
337 if (target
!= GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD
&&
338 cmd_size
<= MARSHAL_MAX_CMD_SIZE
) {
339 struct marshal_cmd_BufferSubData
*cmd
=
340 _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_BufferSubData
,
342 cmd
->target
= target
;
343 cmd
->offset
= offset
;
345 char *variable_data
= (char *) (cmd
+ 1);
346 memcpy(variable_data
, data
, size
);
347 _mesa_post_marshal_hook(ctx
);
349 _mesa_glthread_finish(ctx
);
350 CALL_BufferSubData(ctx
->CurrentServerDispatch
,
351 (target
, offset
, size
, data
));
355 /* NamedBufferData: marshalled asynchronously */
356 struct marshal_cmd_NamedBufferData
358 struct marshal_cmd_base cmd_base
;
362 bool data_null
; /* If set, no data follows for "data" */
363 /* Next size bytes are GLubyte data[size] */
367 _mesa_unmarshal_NamedBufferData(struct gl_context
*ctx
,
368 const struct marshal_cmd_NamedBufferData
*cmd
)
370 const GLuint name
= cmd
->name
;
371 const GLsizei size
= cmd
->size
;
372 const GLenum usage
= cmd
->usage
;
378 data
= (const void *) (cmd
+ 1);
380 CALL_NamedBufferData(ctx
->CurrentServerDispatch
,
381 (name
, size
, data
, usage
));
385 _mesa_marshal_NamedBufferData(GLuint buffer
, GLsizeiptr size
,
386 const GLvoid
* data
, GLenum usage
)
388 GET_CURRENT_CONTEXT(ctx
);
389 size_t cmd_size
= sizeof(struct marshal_cmd_NamedBufferData
) + (data
? size
: 0);
391 debug_print_marshal("NamedBufferData");
392 if (unlikely(size
< 0)) {
393 _mesa_glthread_finish(ctx
);
394 _mesa_error(ctx
, GL_INVALID_VALUE
, "NamedBufferData(size < 0)");
398 if (buffer
> 0 && cmd_size
<= MARSHAL_MAX_CMD_SIZE
) {
399 struct marshal_cmd_NamedBufferData
*cmd
=
400 _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_NamedBufferData
,
405 cmd
->data_null
= !data
;
407 char *variable_data
= (char *) (cmd
+ 1);
408 memcpy(variable_data
, data
, size
);
410 _mesa_post_marshal_hook(ctx
);
412 _mesa_glthread_finish(ctx
);
413 CALL_NamedBufferData(ctx
->CurrentServerDispatch
,
414 (buffer
, size
, data
, usage
));
418 /* NamedBufferSubData: marshalled asynchronously */
419 struct marshal_cmd_NamedBufferSubData
421 struct marshal_cmd_base cmd_base
;
425 /* Next size bytes are GLubyte data[size] */
429 _mesa_unmarshal_NamedBufferSubData(struct gl_context
*ctx
,
430 const struct marshal_cmd_NamedBufferSubData
*cmd
)
432 const GLuint name
= cmd
->name
;
433 const GLintptr offset
= cmd
->offset
;
434 const GLsizei size
= cmd
->size
;
435 const void *data
= (const void *) (cmd
+ 1);
437 CALL_NamedBufferSubData(ctx
->CurrentServerDispatch
,
438 (name
, offset
, size
, data
));
442 _mesa_marshal_NamedBufferSubData(GLuint buffer
, GLintptr offset
,
443 GLsizeiptr size
, const GLvoid
* data
)
445 GET_CURRENT_CONTEXT(ctx
);
446 size_t cmd_size
= sizeof(struct marshal_cmd_NamedBufferSubData
) + size
;
448 debug_print_marshal("NamedBufferSubData");
449 if (unlikely(size
< 0)) {
450 _mesa_glthread_finish(ctx
);
451 _mesa_error(ctx
, GL_INVALID_VALUE
, "NamedBufferSubData(size < 0)");
455 if (buffer
> 0 && cmd_size
<= MARSHAL_MAX_CMD_SIZE
) {
456 struct marshal_cmd_NamedBufferSubData
*cmd
=
457 _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_NamedBufferSubData
,
460 cmd
->offset
= offset
;
462 char *variable_data
= (char *) (cmd
+ 1);
463 memcpy(variable_data
, data
, size
);
464 _mesa_post_marshal_hook(ctx
);
466 _mesa_glthread_finish(ctx
);
467 CALL_NamedBufferSubData(ctx
->CurrentServerDispatch
,
468 (buffer
, offset
, size
, data
));