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"
34 #include "marshal_generated.h"
38 struct marshal_cmd_Flush
40 struct marshal_cmd_base cmd_base
;
45 _mesa_unmarshal_Flush(struct gl_context
*ctx
,
46 const struct marshal_cmd_Flush
*cmd
)
48 CALL_Flush(ctx
->CurrentServerDispatch
, ());
53 _mesa_marshal_Flush(void)
55 GET_CURRENT_CONTEXT(ctx
);
56 struct marshal_cmd_Flush
*cmd
=
57 _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_Flush
,
58 sizeof(struct marshal_cmd_Flush
));
60 _mesa_post_marshal_hook(ctx
);
62 /* Flush() needs to be handled specially. In addition to telling the
63 * background thread to flush, we need to ensure that our own buffer is
64 * submitted to the background thread so that it will complete in a finite
67 _mesa_glthread_flush_batch(ctx
);
70 /* Enable: marshalled asynchronously */
71 struct marshal_cmd_Enable
73 struct marshal_cmd_base cmd_base
;
78 _mesa_unmarshal_Enable(struct gl_context
*ctx
,
79 const struct marshal_cmd_Enable
*cmd
)
81 const GLenum cap
= cmd
->cap
;
82 CALL_Enable(ctx
->CurrentServerDispatch
, (cap
));
86 _mesa_marshal_Enable(GLenum cap
)
88 GET_CURRENT_CONTEXT(ctx
);
89 struct marshal_cmd_Enable
*cmd
;
90 debug_print_marshal("Enable");
92 if (cap
== GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB
) {
93 _mesa_glthread_finish(ctx
);
94 _mesa_glthread_restore_dispatch(ctx
);
96 cmd
= _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_Enable
,
99 _mesa_post_marshal_hook(ctx
);
103 _mesa_glthread_finish(ctx
);
104 debug_print_sync_fallback("Enable");
105 CALL_Enable(ctx
->CurrentServerDispatch
, (cap
));
108 struct marshal_cmd_ShaderSource
110 struct marshal_cmd_base cmd_base
;
113 /* Followed by GLint length[count], then the contents of all strings,
120 _mesa_unmarshal_ShaderSource(struct gl_context
*ctx
,
121 const struct marshal_cmd_ShaderSource
*cmd
)
123 const GLint
*cmd_length
= (const GLint
*) (cmd
+ 1);
124 const GLchar
*cmd_strings
= (const GLchar
*) (cmd_length
+ cmd
->count
);
125 /* TODO: how to deal with malloc failure? */
126 const GLchar
* *string
= malloc(cmd
->count
* sizeof(const GLchar
*));
129 for (i
= 0; i
< cmd
->count
; ++i
) {
130 string
[i
] = cmd_strings
;
131 cmd_strings
+= cmd_length
[i
];
133 CALL_ShaderSource(ctx
->CurrentServerDispatch
,
134 (cmd
->shader
, cmd
->count
, string
, cmd_length
));
140 measure_ShaderSource_strings(GLsizei count
, const GLchar
* const *string
,
141 const GLint
*length_in
, GLint
*length_out
)
144 size_t total_string_length
= 0;
146 for (i
= 0; i
< count
; ++i
) {
147 if (length_in
== NULL
|| length_in
[i
] < 0) {
149 length_out
[i
] = strlen(string
[i
]);
151 length_out
[i
] = length_in
[i
];
153 total_string_length
+= length_out
[i
];
155 return total_string_length
;
160 _mesa_marshal_ShaderSource(GLuint shader
, GLsizei count
,
161 const GLchar
* const *string
, const GLint
*length
)
163 /* TODO: how to report an error if count < 0? */
165 GET_CURRENT_CONTEXT(ctx
);
166 /* TODO: how to deal with malloc failure? */
167 const size_t fixed_cmd_size
= sizeof(struct marshal_cmd_ShaderSource
);
168 STATIC_ASSERT(sizeof(struct marshal_cmd_ShaderSource
) % sizeof(GLint
) == 0);
169 size_t length_size
= count
* sizeof(GLint
);
170 GLint
*length_tmp
= malloc(length_size
);
171 size_t total_string_length
=
172 measure_ShaderSource_strings(count
, string
, length
, length_tmp
);
173 size_t total_cmd_size
= fixed_cmd_size
+ length_size
+ total_string_length
;
175 if (total_cmd_size
<= MARSHAL_MAX_CMD_SIZE
) {
176 struct marshal_cmd_ShaderSource
*cmd
=
177 _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_ShaderSource
,
179 GLint
*cmd_length
= (GLint
*) (cmd
+ 1);
180 GLchar
*cmd_strings
= (GLchar
*) (cmd_length
+ count
);
183 cmd
->shader
= shader
;
185 memcpy(cmd_length
, length_tmp
, length_size
);
186 for (i
= 0; i
< count
; ++i
) {
187 memcpy(cmd_strings
, string
[i
], cmd_length
[i
]);
188 cmd_strings
+= cmd_length
[i
];
190 _mesa_post_marshal_hook(ctx
);
192 _mesa_glthread_finish(ctx
);
193 CALL_ShaderSource(ctx
->CurrentServerDispatch
,
194 (shader
, count
, string
, length_tmp
));
200 /* BindBufferBase: marshalled asynchronously */
201 struct marshal_cmd_BindBufferBase
203 struct marshal_cmd_base cmd_base
;
209 /** Tracks the current bindings for the vertex array and index array buffers.
211 * This is part of what we need to enable glthread on compat-GL contexts that
212 * happen to use VBOs, without also supporting the full tracking of VBO vs
213 * user vertex array bindings per attribute on each vertex array for
214 * determining what to upload at draw call time.
216 * Note that GL core makes it so that a buffer binding with an invalid handle
217 * in the "buffer" parameter will throw an error, and then a
218 * glVertexAttribPointer() that followsmight not end up pointing at a VBO.
219 * However, in GL core the draw call would throw an error as well, so we don't
220 * really care if our tracking is wrong for this case -- we never need to
221 * marshal user data for draw calls, and the unmarshal will just generate an
222 * error or not as appropriate.
224 * For compatibility GL, we do need to accurately know whether the draw call
225 * on the unmarshal side will dereference a user pointer or load data from a
226 * VBO per vertex. That would make it seem like we need to track whether a
227 * "buffer" is valid, so that we can know when an error will be generated
228 * instead of updating the binding. However, compat GL has the ridiculous
229 * feature that if you pass a bad name, it just gens a buffer object for you,
230 * so we escape without having to know if things are valid or not.
233 track_vbo_binding(struct gl_context
*ctx
, GLenum target
, GLuint buffer
)
235 struct glthread_state
*glthread
= ctx
->GLThread
;
238 case GL_ARRAY_BUFFER
:
239 glthread
->vertex_array_is_vbo
= (buffer
!= 0);
241 case GL_ELEMENT_ARRAY_BUFFER
:
242 /* The current element array buffer binding is actually tracked in the
243 * vertex array object instead of the context, so this would need to
244 * change on vertex array object updates.
246 glthread
->element_array_is_vbo
= (buffer
!= 0);
252 struct marshal_cmd_BindBuffer
254 struct marshal_cmd_base cmd_base
;
260 * This is just like the code-generated glBindBuffer() support, except that we
261 * call track_vbo_binding().
264 _mesa_unmarshal_BindBuffer(struct gl_context
*ctx
,
265 const struct marshal_cmd_BindBuffer
*cmd
)
267 const GLenum target
= cmd
->target
;
268 const GLuint buffer
= cmd
->buffer
;
269 CALL_BindBuffer(ctx
->CurrentServerDispatch
, (target
, buffer
));
272 _mesa_marshal_BindBuffer(GLenum target
, GLuint buffer
)
274 GET_CURRENT_CONTEXT(ctx
);
275 size_t cmd_size
= sizeof(struct marshal_cmd_BindBuffer
);
276 struct marshal_cmd_BindBuffer
*cmd
;
277 debug_print_marshal("BindBuffer");
279 track_vbo_binding(ctx
, target
, buffer
);
281 if (cmd_size
<= MARSHAL_MAX_CMD_SIZE
) {
282 cmd
= _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_BindBuffer
,
284 cmd
->target
= target
;
285 cmd
->buffer
= buffer
;
286 _mesa_post_marshal_hook(ctx
);
288 _mesa_glthread_finish(ctx
);
289 CALL_BindBuffer(ctx
->CurrentServerDispatch
, (target
, buffer
));
293 /* BufferData: marshalled asynchronously */
294 struct marshal_cmd_BufferData
296 struct marshal_cmd_base cmd_base
;
300 bool data_null
; /* If set, no data follows for "data" */
301 /* Next size bytes are GLubyte data[size] */
305 _mesa_unmarshal_BufferData(struct gl_context
*ctx
,
306 const struct marshal_cmd_BufferData
*cmd
)
308 const GLenum target
= cmd
->target
;
309 const GLsizeiptr size
= cmd
->size
;
310 const GLenum usage
= cmd
->usage
;
316 data
= (const void *) (cmd
+ 1);
318 CALL_BufferData(ctx
->CurrentServerDispatch
, (target
, size
, data
, usage
));
322 _mesa_marshal_BufferData(GLenum target
, GLsizeiptr size
, const GLvoid
* data
,
325 GET_CURRENT_CONTEXT(ctx
);
327 sizeof(struct marshal_cmd_BufferData
) + (data
? size
: 0);
328 debug_print_marshal("BufferData");
330 if (unlikely(size
< 0)) {
331 _mesa_glthread_finish(ctx
);
332 _mesa_error(ctx
, GL_INVALID_VALUE
, "BufferData(size < 0)");
336 if (target
!= GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD
&&
337 cmd_size
<= MARSHAL_MAX_CMD_SIZE
) {
338 struct marshal_cmd_BufferData
*cmd
=
339 _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_BufferData
,
342 cmd
->target
= target
;
345 cmd
->data_null
= !data
;
347 char *variable_data
= (char *) (cmd
+ 1);
348 memcpy(variable_data
, data
, size
);
350 _mesa_post_marshal_hook(ctx
);
352 _mesa_glthread_finish(ctx
);
353 CALL_BufferData(ctx
->CurrentServerDispatch
,
354 (target
, size
, data
, usage
));
358 /* BufferSubData: marshalled asynchronously */
359 struct marshal_cmd_BufferSubData
361 struct marshal_cmd_base cmd_base
;
365 /* Next size bytes are GLubyte data[size] */
369 _mesa_unmarshal_BufferSubData(struct gl_context
*ctx
,
370 const struct marshal_cmd_BufferSubData
*cmd
)
372 const GLenum target
= cmd
->target
;
373 const GLintptr offset
= cmd
->offset
;
374 const GLsizeiptr size
= cmd
->size
;
375 const void *data
= (const void *) (cmd
+ 1);
377 CALL_BufferSubData(ctx
->CurrentServerDispatch
,
378 (target
, offset
, size
, data
));
382 _mesa_marshal_BufferSubData(GLenum target
, GLintptr offset
, GLsizeiptr size
,
385 GET_CURRENT_CONTEXT(ctx
);
386 size_t cmd_size
= sizeof(struct marshal_cmd_BufferSubData
) + size
;
388 debug_print_marshal("BufferSubData");
389 if (unlikely(size
< 0)) {
390 _mesa_glthread_finish(ctx
);
391 _mesa_error(ctx
, GL_INVALID_VALUE
, "BufferSubData(size < 0)");
395 if (target
!= GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD
&&
396 cmd_size
<= MARSHAL_MAX_CMD_SIZE
) {
397 struct marshal_cmd_BufferSubData
*cmd
=
398 _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_BufferSubData
,
400 cmd
->target
= target
;
401 cmd
->offset
= offset
;
403 char *variable_data
= (char *) (cmd
+ 1);
404 memcpy(variable_data
, data
, size
);
405 _mesa_post_marshal_hook(ctx
);
407 _mesa_glthread_finish(ctx
);
408 CALL_BufferSubData(ctx
->CurrentServerDispatch
,
409 (target
, offset
, size
, data
));
413 /* ClearBufferfv: marshalled asynchronously */
414 struct marshal_cmd_ClearBufferfv
416 struct marshal_cmd_base cmd_base
;
422 _mesa_unmarshal_ClearBufferfv(struct gl_context
*ctx
,
423 const struct marshal_cmd_ClearBufferfv
*cmd
)
425 const GLenum buffer
= cmd
->buffer
;
426 const GLint drawbuffer
= cmd
->drawbuffer
;
427 const char *variable_data
= (const char *) (cmd
+ 1);
428 const GLfloat
*value
= (const GLfloat
*) variable_data
;
430 CALL_ClearBufferfv(ctx
->CurrentServerDispatch
,
431 (buffer
, drawbuffer
, value
));
435 _mesa_marshal_ClearBufferfv(GLenum buffer
, GLint drawbuffer
,
436 const GLfloat
*value
)
438 GET_CURRENT_CONTEXT(ctx
);
439 debug_print_marshal("ClearBufferfv");
444 size
= sizeof(GLfloat
);
447 size
= sizeof(GLfloat
) * 4;
450 _mesa_glthread_finish(ctx
);
452 /* Page 498 of the PDF, section '17.4.3.1 Clearing Individual Buffers'
453 * of the OpenGL 4.5 spec states:
455 * "An INVALID_ENUM error is generated by ClearBufferfv and
456 * ClearNamedFramebufferfv if buffer is not COLOR or DEPTH."
458 _mesa_error(ctx
, GL_INVALID_ENUM
, "glClearBufferfv(buffer=%s)",
459 _mesa_enum_to_string(buffer
));
463 size_t cmd_size
= sizeof(struct marshal_cmd_ClearBufferfv
) + size
;
464 if (cmd_size
<= MARSHAL_MAX_CMD_SIZE
) {
465 struct marshal_cmd_ClearBufferfv
*cmd
=
466 _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_ClearBufferfv
,
468 cmd
->buffer
= buffer
;
469 cmd
->drawbuffer
= drawbuffer
;
470 GLfloat
*variable_data
= (GLfloat
*) (cmd
+ 1);
471 if (buffer
== GL_COLOR
)
472 COPY_4V(variable_data
, value
);
474 *variable_data
= *value
;
476 _mesa_post_marshal_hook(ctx
);
478 debug_print_sync("ClearBufferfv");
479 _mesa_glthread_finish(ctx
);
480 CALL_ClearBufferfv(ctx
->CurrentServerDispatch
,
481 (buffer
, drawbuffer
, value
));