d4c46a2717547288ea6d6daaee2033d5e1dbce60
[mesa.git] / src / mesa / main / marshal.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 /** \file marshal.c
25 *
26 * Custom functions for marshalling GL calls from the main thread to a worker
27 * thread when automatic code generation isn't appropriate.
28 */
29
30 #include "main/enums.h"
31 #include "main/macros.h"
32 #include "marshal.h"
33 #include "dispatch.h"
34 #include "marshal_generated.h"
35
36 #ifdef HAVE_PTHREAD
37
38 struct marshal_cmd_Flush
39 {
40 struct marshal_cmd_base cmd_base;
41 };
42
43
44 void
45 _mesa_unmarshal_Flush(struct gl_context *ctx,
46 const struct marshal_cmd_Flush *cmd)
47 {
48 CALL_Flush(ctx->CurrentServerDispatch, ());
49 }
50
51
52 void GLAPIENTRY
53 _mesa_marshal_Flush(void)
54 {
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));
59 (void) cmd;
60 _mesa_post_marshal_hook(ctx);
61
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
65 * amount of time.
66 */
67 _mesa_glthread_flush_batch(ctx);
68 }
69
70 /* Enable: marshalled asynchronously */
71 struct marshal_cmd_Enable
72 {
73 struct marshal_cmd_base cmd_base;
74 GLenum cap;
75 };
76
77 void
78 _mesa_unmarshal_Enable(struct gl_context *ctx,
79 const struct marshal_cmd_Enable *cmd)
80 {
81 const GLenum cap = cmd->cap;
82 CALL_Enable(ctx->CurrentServerDispatch, (cap));
83 }
84
85 void GLAPIENTRY
86 _mesa_marshal_Enable(GLenum cap)
87 {
88 GET_CURRENT_CONTEXT(ctx);
89 struct marshal_cmd_Enable *cmd;
90 debug_print_marshal("Enable");
91
92 if (cap == GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB) {
93 _mesa_glthread_finish(ctx);
94 _mesa_glthread_restore_dispatch(ctx);
95 } else {
96 cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_Enable,
97 sizeof(*cmd));
98 cmd->cap = cap;
99 _mesa_post_marshal_hook(ctx);
100 return;
101 }
102
103 _mesa_glthread_finish(ctx);
104 debug_print_sync_fallback("Enable");
105 CALL_Enable(ctx->CurrentServerDispatch, (cap));
106 }
107
108 struct marshal_cmd_ShaderSource
109 {
110 struct marshal_cmd_base cmd_base;
111 GLuint shader;
112 GLsizei count;
113 /* Followed by GLint length[count], then the contents of all strings,
114 * concatenated.
115 */
116 };
117
118
119 void
120 _mesa_unmarshal_ShaderSource(struct gl_context *ctx,
121 const struct marshal_cmd_ShaderSource *cmd)
122 {
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 *));
127 int i;
128
129 for (i = 0; i < cmd->count; ++i) {
130 string[i] = cmd_strings;
131 cmd_strings += cmd_length[i];
132 }
133 CALL_ShaderSource(ctx->CurrentServerDispatch,
134 (cmd->shader, cmd->count, string, cmd_length));
135 free(string);
136 }
137
138
139 static size_t
140 measure_ShaderSource_strings(GLsizei count, const GLchar * const *string,
141 const GLint *length_in, GLint *length_out)
142 {
143 int i;
144 size_t total_string_length = 0;
145
146 for (i = 0; i < count; ++i) {
147 if (length_in == NULL || length_in[i] < 0) {
148 if (string[i])
149 length_out[i] = strlen(string[i]);
150 } else {
151 length_out[i] = length_in[i];
152 }
153 total_string_length += length_out[i];
154 }
155 return total_string_length;
156 }
157
158
159 void GLAPIENTRY
160 _mesa_marshal_ShaderSource(GLuint shader, GLsizei count,
161 const GLchar * const *string, const GLint *length)
162 {
163 /* TODO: how to report an error if count < 0? */
164
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;
174
175 if (total_cmd_size <= MARSHAL_MAX_CMD_SIZE) {
176 struct marshal_cmd_ShaderSource *cmd =
177 _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_ShaderSource,
178 total_cmd_size);
179 GLint *cmd_length = (GLint *) (cmd + 1);
180 GLchar *cmd_strings = (GLchar *) (cmd_length + count);
181 int i;
182
183 cmd->shader = shader;
184 cmd->count = count;
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];
189 }
190 _mesa_post_marshal_hook(ctx);
191 } else {
192 _mesa_glthread_finish(ctx);
193 CALL_ShaderSource(ctx->CurrentServerDispatch,
194 (shader, count, string, length_tmp));
195 }
196 free(length_tmp);
197 }
198
199
200 /* BindBufferBase: marshalled asynchronously */
201 struct marshal_cmd_BindBufferBase
202 {
203 struct marshal_cmd_base cmd_base;
204 GLenum target;
205 GLuint index;
206 GLuint buffer;
207 };
208
209 /** Tracks the current bindings for the vertex array and index array buffers.
210 *
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.
215 *
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.
223 *
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.
231 */
232 static void
233 track_vbo_binding(struct gl_context *ctx, GLenum target, GLuint buffer)
234 {
235 struct glthread_state *glthread = ctx->GLThread;
236
237 switch (target) {
238 case GL_ARRAY_BUFFER:
239 glthread->vertex_array_is_vbo = (buffer != 0);
240 break;
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.
245 */
246 glthread->element_array_is_vbo = (buffer != 0);
247 break;
248 }
249 }
250
251
252 struct marshal_cmd_BindBuffer
253 {
254 struct marshal_cmd_base cmd_base;
255 GLenum target;
256 GLuint buffer;
257 };
258
259 /**
260 * This is just like the code-generated glBindBuffer() support, except that we
261 * call track_vbo_binding().
262 */
263 void
264 _mesa_unmarshal_BindBuffer(struct gl_context *ctx,
265 const struct marshal_cmd_BindBuffer *cmd)
266 {
267 const GLenum target = cmd->target;
268 const GLuint buffer = cmd->buffer;
269 CALL_BindBuffer(ctx->CurrentServerDispatch, (target, buffer));
270 }
271 void GLAPIENTRY
272 _mesa_marshal_BindBuffer(GLenum target, GLuint buffer)
273 {
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");
278
279 track_vbo_binding(ctx, target, buffer);
280
281 if (cmd_size <= MARSHAL_MAX_CMD_SIZE) {
282 cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_BindBuffer,
283 cmd_size);
284 cmd->target = target;
285 cmd->buffer = buffer;
286 _mesa_post_marshal_hook(ctx);
287 } else {
288 _mesa_glthread_finish(ctx);
289 CALL_BindBuffer(ctx->CurrentServerDispatch, (target, buffer));
290 }
291 }
292
293 /* BufferData: marshalled asynchronously */
294 struct marshal_cmd_BufferData
295 {
296 struct marshal_cmd_base cmd_base;
297 GLenum target;
298 GLsizeiptr size;
299 GLenum usage;
300 bool data_null; /* If set, no data follows for "data" */
301 /* Next size bytes are GLubyte data[size] */
302 };
303
304 void
305 _mesa_unmarshal_BufferData(struct gl_context *ctx,
306 const struct marshal_cmd_BufferData *cmd)
307 {
308 const GLenum target = cmd->target;
309 const GLsizeiptr size = cmd->size;
310 const GLenum usage = cmd->usage;
311 const void *data;
312
313 if (cmd->data_null)
314 data = NULL;
315 else
316 data = (const void *) (cmd + 1);
317
318 CALL_BufferData(ctx->CurrentServerDispatch, (target, size, data, usage));
319 }
320
321 void GLAPIENTRY
322 _mesa_marshal_BufferData(GLenum target, GLsizeiptr size, const GLvoid * data,
323 GLenum usage)
324 {
325 GET_CURRENT_CONTEXT(ctx);
326 size_t cmd_size =
327 sizeof(struct marshal_cmd_BufferData) + (data ? size : 0);
328 debug_print_marshal("BufferData");
329
330 if (unlikely(size < 0)) {
331 _mesa_glthread_finish(ctx);
332 _mesa_error(ctx, GL_INVALID_VALUE, "BufferData(size < 0)");
333 return;
334 }
335
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,
340 cmd_size);
341
342 cmd->target = target;
343 cmd->size = size;
344 cmd->usage = usage;
345 cmd->data_null = !data;
346 if (data) {
347 char *variable_data = (char *) (cmd + 1);
348 memcpy(variable_data, data, size);
349 }
350 _mesa_post_marshal_hook(ctx);
351 } else {
352 _mesa_glthread_finish(ctx);
353 CALL_BufferData(ctx->CurrentServerDispatch,
354 (target, size, data, usage));
355 }
356 }
357
358 /* BufferSubData: marshalled asynchronously */
359 struct marshal_cmd_BufferSubData
360 {
361 struct marshal_cmd_base cmd_base;
362 GLenum target;
363 GLintptr offset;
364 GLsizeiptr size;
365 /* Next size bytes are GLubyte data[size] */
366 };
367
368 void
369 _mesa_unmarshal_BufferSubData(struct gl_context *ctx,
370 const struct marshal_cmd_BufferSubData *cmd)
371 {
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);
376
377 CALL_BufferSubData(ctx->CurrentServerDispatch,
378 (target, offset, size, data));
379 }
380
381 void GLAPIENTRY
382 _mesa_marshal_BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size,
383 const GLvoid * data)
384 {
385 GET_CURRENT_CONTEXT(ctx);
386 size_t cmd_size = sizeof(struct marshal_cmd_BufferSubData) + size;
387
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)");
392 return;
393 }
394
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,
399 cmd_size);
400 cmd->target = target;
401 cmd->offset = offset;
402 cmd->size = size;
403 char *variable_data = (char *) (cmd + 1);
404 memcpy(variable_data, data, size);
405 _mesa_post_marshal_hook(ctx);
406 } else {
407 _mesa_glthread_finish(ctx);
408 CALL_BufferSubData(ctx->CurrentServerDispatch,
409 (target, offset, size, data));
410 }
411 }
412
413 /* NamedBufferData: marshalled asynchronously */
414 struct marshal_cmd_NamedBufferData
415 {
416 struct marshal_cmd_base cmd_base;
417 GLuint name;
418 GLsizei size;
419 GLenum usage;
420 /* Next size bytes are GLubyte data[size] */
421 };
422
423 void
424 _mesa_unmarshal_NamedBufferData(struct gl_context *ctx,
425 const struct marshal_cmd_NamedBufferData *cmd)
426 {
427 const GLuint name = cmd->name;
428 const GLsizei size = cmd->size;
429 const GLenum usage = cmd->usage;
430 const void *data = (const void *) (cmd + 1);
431
432 CALL_NamedBufferData(ctx->CurrentServerDispatch,
433 (name, size, data, usage));
434 }
435
436 void GLAPIENTRY
437 _mesa_marshal_NamedBufferData(GLuint buffer, GLsizeiptr size,
438 const GLvoid * data, GLenum usage)
439 {
440 GET_CURRENT_CONTEXT(ctx);
441 size_t cmd_size = sizeof(struct marshal_cmd_NamedBufferData) + size;
442
443 debug_print_marshal("NamedBufferData");
444 if (unlikely(size < 0)) {
445 _mesa_glthread_finish(ctx);
446 _mesa_error(ctx, GL_INVALID_VALUE, "NamedBufferData(size < 0)");
447 return;
448 }
449
450 if (buffer > 0 && cmd_size <= MARSHAL_MAX_CMD_SIZE) {
451 struct marshal_cmd_NamedBufferData *cmd =
452 _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_NamedBufferData,
453 cmd_size);
454 cmd->name = buffer;
455 cmd->size = size;
456 cmd->usage = usage;
457 char *variable_data = (char *) (cmd + 1);
458 memcpy(variable_data, data, size);
459 _mesa_post_marshal_hook(ctx);
460 } else {
461 _mesa_glthread_finish(ctx);
462 CALL_NamedBufferData(ctx->CurrentServerDispatch,
463 (buffer, size, data, usage));
464 }
465 }
466
467 /* NamedBufferSubData: marshalled asynchronously */
468 struct marshal_cmd_NamedBufferSubData
469 {
470 struct marshal_cmd_base cmd_base;
471 GLuint name;
472 GLintptr offset;
473 GLsizei size;
474 /* Next size bytes are GLubyte data[size] */
475 };
476
477 void
478 _mesa_unmarshal_NamedBufferSubData(struct gl_context *ctx,
479 const struct marshal_cmd_NamedBufferSubData *cmd)
480 {
481 const GLuint name = cmd->name;
482 const GLintptr offset = cmd->offset;
483 const GLsizei size = cmd->size;
484 const void *data = (const void *) (cmd + 1);
485
486 CALL_NamedBufferSubData(ctx->CurrentServerDispatch,
487 (name, offset, size, data));
488 }
489
490 void GLAPIENTRY
491 _mesa_marshal_NamedBufferSubData(GLuint buffer, GLintptr offset,
492 GLsizeiptr size, const GLvoid * data)
493 {
494 GET_CURRENT_CONTEXT(ctx);
495 size_t cmd_size = sizeof(struct marshal_cmd_NamedBufferSubData) + size;
496
497 debug_print_marshal("NamedBufferSubData");
498 if (unlikely(size < 0)) {
499 _mesa_glthread_finish(ctx);
500 _mesa_error(ctx, GL_INVALID_VALUE, "NamedBufferSubData(size < 0)");
501 return;
502 }
503
504 if (buffer > 0 && cmd_size <= MARSHAL_MAX_CMD_SIZE) {
505 struct marshal_cmd_NamedBufferSubData *cmd =
506 _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_NamedBufferSubData,
507 cmd_size);
508 cmd->name = buffer;
509 cmd->offset = offset;
510 cmd->size = size;
511 char *variable_data = (char *) (cmd + 1);
512 memcpy(variable_data, data, size);
513 _mesa_post_marshal_hook(ctx);
514 } else {
515 _mesa_glthread_finish(ctx);
516 CALL_NamedBufferSubData(ctx->CurrentServerDispatch,
517 (buffer, offset, size, data));
518 }
519 }
520
521 /* ClearBufferfv: marshalled asynchronously */
522 struct marshal_cmd_ClearBufferfv
523 {
524 struct marshal_cmd_base cmd_base;
525 GLenum buffer;
526 GLint drawbuffer;
527 };
528
529 void
530 _mesa_unmarshal_ClearBufferfv(struct gl_context *ctx,
531 const struct marshal_cmd_ClearBufferfv *cmd)
532 {
533 const GLenum buffer = cmd->buffer;
534 const GLint drawbuffer = cmd->drawbuffer;
535 const char *variable_data = (const char *) (cmd + 1);
536 const GLfloat *value = (const GLfloat *) variable_data;
537
538 CALL_ClearBufferfv(ctx->CurrentServerDispatch,
539 (buffer, drawbuffer, value));
540 }
541
542 void GLAPIENTRY
543 _mesa_marshal_ClearBufferfv(GLenum buffer, GLint drawbuffer,
544 const GLfloat *value)
545 {
546 GET_CURRENT_CONTEXT(ctx);
547 debug_print_marshal("ClearBufferfv");
548
549 size_t size;
550 switch (buffer) {
551 case GL_DEPTH:
552 size = sizeof(GLfloat);
553 break;
554 case GL_COLOR:
555 size = sizeof(GLfloat) * 4;
556 break;
557 default:
558 _mesa_glthread_finish(ctx);
559
560 /* Page 498 of the PDF, section '17.4.3.1 Clearing Individual Buffers'
561 * of the OpenGL 4.5 spec states:
562 *
563 * "An INVALID_ENUM error is generated by ClearBufferfv and
564 * ClearNamedFramebufferfv if buffer is not COLOR or DEPTH."
565 */
566 _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferfv(buffer=%s)",
567 _mesa_enum_to_string(buffer));
568 return;
569 }
570
571 size_t cmd_size = sizeof(struct marshal_cmd_ClearBufferfv) + size;
572 if (cmd_size <= MARSHAL_MAX_CMD_SIZE) {
573 struct marshal_cmd_ClearBufferfv *cmd =
574 _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_ClearBufferfv,
575 cmd_size);
576 cmd->buffer = buffer;
577 cmd->drawbuffer = drawbuffer;
578 GLfloat *variable_data = (GLfloat *) (cmd + 1);
579 if (buffer == GL_COLOR)
580 COPY_4V(variable_data, value);
581 else
582 *variable_data = *value;
583
584 _mesa_post_marshal_hook(ctx);
585 } else {
586 debug_print_sync("ClearBufferfv");
587 _mesa_glthread_finish(ctx);
588 CALL_ClearBufferfv(ctx->CurrentServerDispatch,
589 (buffer, drawbuffer, value));
590 }
591 }
592
593 #endif