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 struct marshal_cmd_Flush
37 {
38 struct marshal_cmd_base cmd_base;
39 };
40
41
42 void
_mesa_unmarshal_Flush(struct gl_context * ctx,const struct marshal_cmd_Flush * cmd)43 _mesa_unmarshal_Flush(struct gl_context *ctx,
44 const struct marshal_cmd_Flush *cmd)
45 {
46 CALL_Flush(ctx->CurrentServerDispatch, ());
47 }
48
49
50 void GLAPIENTRY
_mesa_marshal_Flush(void)51 _mesa_marshal_Flush(void)
52 {
53 GET_CURRENT_CONTEXT(ctx);
54 struct marshal_cmd_Flush *cmd =
55 _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_Flush,
56 sizeof(struct marshal_cmd_Flush));
57 (void) cmd;
58 _mesa_post_marshal_hook(ctx);
59
60 /* Flush() needs to be handled specially. In addition to telling the
61 * background thread to flush, we need to ensure that our own buffer is
62 * submitted to the background thread so that it will complete in a finite
63 * amount of time.
64 */
65 _mesa_glthread_flush_batch(ctx);
66 }
67
68 /* Enable: marshalled asynchronously */
69 struct marshal_cmd_Enable
70 {
71 struct marshal_cmd_base cmd_base;
72 GLenum cap;
73 };
74
75 void
_mesa_unmarshal_Enable(struct gl_context * ctx,const struct marshal_cmd_Enable * cmd)76 _mesa_unmarshal_Enable(struct gl_context *ctx,
77 const struct marshal_cmd_Enable *cmd)
78 {
79 const GLenum cap = cmd->cap;
80 CALL_Enable(ctx->CurrentServerDispatch, (cap));
81 }
82
83 void GLAPIENTRY
_mesa_marshal_Enable(GLenum cap)84 _mesa_marshal_Enable(GLenum cap)
85 {
86 GET_CURRENT_CONTEXT(ctx);
87 struct marshal_cmd_Enable *cmd;
88 debug_print_marshal("Enable");
89
90 if (cap == GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB) {
91 _mesa_glthread_finish(ctx);
92 _mesa_glthread_restore_dispatch(ctx);
93 } else {
94 cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_Enable,
95 sizeof(*cmd));
96 cmd->cap = cap;
97 _mesa_post_marshal_hook(ctx);
98 return;
99 }
100
101 _mesa_glthread_finish(ctx);
102 debug_print_sync_fallback("Enable");
103 CALL_Enable(ctx->CurrentServerDispatch, (cap));
104 }
105
106 struct marshal_cmd_ShaderSource
107 {
108 struct marshal_cmd_base cmd_base;
109 GLuint shader;
110 GLsizei count;
111 /* Followed by GLint length[count], then the contents of all strings,
112 * concatenated.
113 */
114 };
115
116
117 void
_mesa_unmarshal_ShaderSource(struct gl_context * ctx,const struct marshal_cmd_ShaderSource * cmd)118 _mesa_unmarshal_ShaderSource(struct gl_context *ctx,
119 const struct marshal_cmd_ShaderSource *cmd)
120 {
121 const GLint *cmd_length = (const GLint *) (cmd + 1);
122 const GLchar *cmd_strings = (const GLchar *) (cmd_length + cmd->count);
123 /* TODO: how to deal with malloc failure? */
124 const GLchar * *string = malloc(cmd->count * sizeof(const GLchar *));
125 int i;
126
127 for (i = 0; i < cmd->count; ++i) {
128 string[i] = cmd_strings;
129 cmd_strings += cmd_length[i];
130 }
131 CALL_ShaderSource(ctx->CurrentServerDispatch,
132 (cmd->shader, cmd->count, string, cmd_length));
133 free(string);
134 }
135
136
137 static size_t
measure_ShaderSource_strings(GLsizei count,const GLchar * const * string,const GLint * length_in,GLint * length_out)138 measure_ShaderSource_strings(GLsizei count, const GLchar * const *string,
139 const GLint *length_in, GLint *length_out)
140 {
141 int i;
142 size_t total_string_length = 0;
143
144 for (i = 0; i < count; ++i) {
145 if (length_in == NULL || length_in[i] < 0) {
146 if (string[i])
147 length_out[i] = strlen(string[i]);
148 } else {
149 length_out[i] = length_in[i];
150 }
151 total_string_length += length_out[i];
152 }
153 return total_string_length;
154 }
155
156
157 void GLAPIENTRY
_mesa_marshal_ShaderSource(GLuint shader,GLsizei count,const GLchar * const * string,const GLint * length)158 _mesa_marshal_ShaderSource(GLuint shader, GLsizei count,
159 const GLchar * const *string, const GLint *length)
160 {
161 /* TODO: how to report an error if count < 0? */
162
163 GET_CURRENT_CONTEXT(ctx);
164 /* TODO: how to deal with malloc failure? */
165 const size_t fixed_cmd_size = sizeof(struct marshal_cmd_ShaderSource);
166 STATIC_ASSERT(sizeof(struct marshal_cmd_ShaderSource) % sizeof(GLint) == 0);
167 size_t length_size = count * sizeof(GLint);
168 GLint *length_tmp = malloc(length_size);
169 size_t total_string_length =
170 measure_ShaderSource_strings(count, string, length, length_tmp);
171 size_t total_cmd_size = fixed_cmd_size + length_size + total_string_length;
172
173 if (total_cmd_size <= MARSHAL_MAX_CMD_SIZE) {
174 struct marshal_cmd_ShaderSource *cmd =
175 _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_ShaderSource,
176 total_cmd_size);
177 GLint *cmd_length = (GLint *) (cmd + 1);
178 GLchar *cmd_strings = (GLchar *) (cmd_length + count);
179 int i;
180
181 cmd->shader = shader;
182 cmd->count = count;
183 memcpy(cmd_length, length_tmp, length_size);
184 for (i = 0; i < count; ++i) {
185 memcpy(cmd_strings, string[i], cmd_length[i]);
186 cmd_strings += cmd_length[i];
187 }
188 _mesa_post_marshal_hook(ctx);
189 } else {
190 _mesa_glthread_finish(ctx);
191 CALL_ShaderSource(ctx->CurrentServerDispatch,
192 (shader, count, string, length_tmp));
193 }
194 free(length_tmp);
195 }
196
197
198 /* BindBufferBase: marshalled asynchronously */
199 struct marshal_cmd_BindBufferBase
200 {
201 struct marshal_cmd_base cmd_base;
202 GLenum target;
203 GLuint index;
204 GLuint buffer;
205 };
206
207 /** Tracks the current bindings for the vertex array and index array buffers.
208 *
209 * This is part of what we need to enable glthread on compat-GL contexts that
210 * happen to use VBOs, without also supporting the full tracking of VBO vs
211 * user vertex array bindings per attribute on each vertex array for
212 * determining what to upload at draw call time.
213 *
214 * Note that GL core makes it so that a buffer binding with an invalid handle
215 * in the "buffer" parameter will throw an error, and then a
216 * glVertexAttribPointer() that followsmight not end up pointing at a VBO.
217 * However, in GL core the draw call would throw an error as well, so we don't
218 * really care if our tracking is wrong for this case -- we never need to
219 * marshal user data for draw calls, and the unmarshal will just generate an
220 * error or not as appropriate.
221 *
222 * For compatibility GL, we do need to accurately know whether the draw call
223 * on the unmarshal side will dereference a user pointer or load data from a
224 * VBO per vertex. That would make it seem like we need to track whether a
225 * "buffer" is valid, so that we can know when an error will be generated
226 * instead of updating the binding. However, compat GL has the ridiculous
227 * feature that if you pass a bad name, it just gens a buffer object for you,
228 * so we escape without having to know if things are valid or not.
229 */
230 static void
track_vbo_binding(struct gl_context * ctx,GLenum target,GLuint buffer)231 track_vbo_binding(struct gl_context *ctx, GLenum target, GLuint buffer)
232 {
233 struct glthread_state *glthread = ctx->GLThread;
234
235 switch (target) {
236 case GL_ARRAY_BUFFER:
237 glthread->vertex_array_is_vbo = (buffer != 0);
238 break;
239 case GL_ELEMENT_ARRAY_BUFFER:
240 /* The current element array buffer binding is actually tracked in the
241 * vertex array object instead of the context, so this would need to
242 * change on vertex array object updates.
243 */
244 glthread->element_array_is_vbo = (buffer != 0);
245 break;
246 }
247 }
248
249
250 struct marshal_cmd_BindBuffer
251 {
252 struct marshal_cmd_base cmd_base;
253 GLenum target;
254 GLuint buffer;
255 };
256
257 /**
258 * This is just like the code-generated glBindBuffer() support, except that we
259 * call track_vbo_binding().
260 */
261 void
_mesa_unmarshal_BindBuffer(struct gl_context * ctx,const struct marshal_cmd_BindBuffer * cmd)262 _mesa_unmarshal_BindBuffer(struct gl_context *ctx,
263 const struct marshal_cmd_BindBuffer *cmd)
264 {
265 const GLenum target = cmd->target;
266 const GLuint buffer = cmd->buffer;
267 CALL_BindBuffer(ctx->CurrentServerDispatch, (target, buffer));
268 }
269 void GLAPIENTRY
_mesa_marshal_BindBuffer(GLenum target,GLuint buffer)270 _mesa_marshal_BindBuffer(GLenum target, GLuint buffer)
271 {
272 GET_CURRENT_CONTEXT(ctx);
273 size_t cmd_size = sizeof(struct marshal_cmd_BindBuffer);
274 struct marshal_cmd_BindBuffer *cmd;
275 debug_print_marshal("BindBuffer");
276
277 track_vbo_binding(ctx, target, buffer);
278
279 if (cmd_size <= MARSHAL_MAX_CMD_SIZE) {
280 cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_BindBuffer,
281 cmd_size);
282 cmd->target = target;
283 cmd->buffer = buffer;
284 _mesa_post_marshal_hook(ctx);
285 } else {
286 _mesa_glthread_finish(ctx);
287 CALL_BindBuffer(ctx->CurrentServerDispatch, (target, buffer));
288 }
289 }
290
291 /* BufferData: marshalled asynchronously */
292 struct marshal_cmd_BufferData
293 {
294 struct marshal_cmd_base cmd_base;
295 GLenum target;
296 GLsizeiptr size;
297 GLenum usage;
298 bool data_null; /* If set, no data follows for "data" */
299 /* Next size bytes are GLubyte data[size] */
300 };
301
302 void
_mesa_unmarshal_BufferData(struct gl_context * ctx,const struct marshal_cmd_BufferData * cmd)303 _mesa_unmarshal_BufferData(struct gl_context *ctx,
304 const struct marshal_cmd_BufferData *cmd)
305 {
306 const GLenum target = cmd->target;
307 const GLsizeiptr size = cmd->size;
308 const GLenum usage = cmd->usage;
309 const void *data;
310
311 if (cmd->data_null)
312 data = NULL;
313 else
314 data = (const void *) (cmd + 1);
315
316 CALL_BufferData(ctx->CurrentServerDispatch, (target, size, data, usage));
317 }
318
319 void GLAPIENTRY
_mesa_marshal_BufferData(GLenum target,GLsizeiptr size,const GLvoid * data,GLenum usage)320 _mesa_marshal_BufferData(GLenum target, GLsizeiptr size, const GLvoid * data,
321 GLenum usage)
322 {
323 GET_CURRENT_CONTEXT(ctx);
324 size_t cmd_size =
325 sizeof(struct marshal_cmd_BufferData) + (data ? size : 0);
326 debug_print_marshal("BufferData");
327
328 if (unlikely(size < 0)) {
329 _mesa_glthread_finish(ctx);
330 _mesa_error(ctx, GL_INVALID_VALUE, "BufferData(size < 0)");
331 return;
332 }
333
334 if (target != GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD &&
335 cmd_size <= MARSHAL_MAX_CMD_SIZE) {
336 struct marshal_cmd_BufferData *cmd =
337 _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_BufferData,
338 cmd_size);
339
340 cmd->target = target;
341 cmd->size = size;
342 cmd->usage = usage;
343 cmd->data_null = !data;
344 if (data) {
345 char *variable_data = (char *) (cmd + 1);
346 memcpy(variable_data, data, size);
347 }
348 _mesa_post_marshal_hook(ctx);
349 } else {
350 _mesa_glthread_finish(ctx);
351 CALL_BufferData(ctx->CurrentServerDispatch,
352 (target, size, data, usage));
353 }
354 }
355
356 /* BufferSubData: marshalled asynchronously */
357 struct marshal_cmd_BufferSubData
358 {
359 struct marshal_cmd_base cmd_base;
360 GLenum target;
361 GLintptr offset;
362 GLsizeiptr size;
363 /* Next size bytes are GLubyte data[size] */
364 };
365
366 void
_mesa_unmarshal_BufferSubData(struct gl_context * ctx,const struct marshal_cmd_BufferSubData * cmd)367 _mesa_unmarshal_BufferSubData(struct gl_context *ctx,
368 const struct marshal_cmd_BufferSubData *cmd)
369 {
370 const GLenum target = cmd->target;
371 const GLintptr offset = cmd->offset;
372 const GLsizeiptr size = cmd->size;
373 const void *data = (const void *) (cmd + 1);
374
375 CALL_BufferSubData(ctx->CurrentServerDispatch,
376 (target, offset, size, data));
377 }
378
379 void GLAPIENTRY
_mesa_marshal_BufferSubData(GLenum target,GLintptr offset,GLsizeiptr size,const GLvoid * data)380 _mesa_marshal_BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size,
381 const GLvoid * data)
382 {
383 GET_CURRENT_CONTEXT(ctx);
384 size_t cmd_size = sizeof(struct marshal_cmd_BufferSubData) + size;
385
386 debug_print_marshal("BufferSubData");
387 if (unlikely(size < 0)) {
388 _mesa_glthread_finish(ctx);
389 _mesa_error(ctx, GL_INVALID_VALUE, "BufferSubData(size < 0)");
390 return;
391 }
392
393 if (target != GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD &&
394 cmd_size <= MARSHAL_MAX_CMD_SIZE) {
395 struct marshal_cmd_BufferSubData *cmd =
396 _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_BufferSubData,
397 cmd_size);
398 cmd->target = target;
399 cmd->offset = offset;
400 cmd->size = size;
401 char *variable_data = (char *) (cmd + 1);
402 memcpy(variable_data, data, size);
403 _mesa_post_marshal_hook(ctx);
404 } else {
405 _mesa_glthread_finish(ctx);
406 CALL_BufferSubData(ctx->CurrentServerDispatch,
407 (target, offset, size, data));
408 }
409 }
410
411 /* NamedBufferData: marshalled asynchronously */
412 struct marshal_cmd_NamedBufferData
413 {
414 struct marshal_cmd_base cmd_base;
415 GLuint name;
416 GLsizei size;
417 GLenum usage;
418 bool data_null; /* If set, no data follows for "data" */
419 /* Next size bytes are GLubyte data[size] */
420 };
421
422 void
_mesa_unmarshal_NamedBufferData(struct gl_context * ctx,const struct marshal_cmd_NamedBufferData * cmd)423 _mesa_unmarshal_NamedBufferData(struct gl_context *ctx,
424 const struct marshal_cmd_NamedBufferData *cmd)
425 {
426 const GLuint name = cmd->name;
427 const GLsizei size = cmd->size;
428 const GLenum usage = cmd->usage;
429 const void *data;
430
431 if (cmd->data_null)
432 data = NULL;
433 else
434 data = (const void *) (cmd + 1);
435
436 CALL_NamedBufferData(ctx->CurrentServerDispatch,
437 (name, size, data, usage));
438 }
439
440 void GLAPIENTRY
_mesa_marshal_NamedBufferData(GLuint buffer,GLsizeiptr size,const GLvoid * data,GLenum usage)441 _mesa_marshal_NamedBufferData(GLuint buffer, GLsizeiptr size,
442 const GLvoid * data, GLenum usage)
443 {
444 GET_CURRENT_CONTEXT(ctx);
445 size_t cmd_size = sizeof(struct marshal_cmd_NamedBufferData) + (data ? size : 0);
446
447 debug_print_marshal("NamedBufferData");
448 if (unlikely(size < 0)) {
449 _mesa_glthread_finish(ctx);
450 _mesa_error(ctx, GL_INVALID_VALUE, "NamedBufferData(size < 0)");
451 return;
452 }
453
454 if (buffer > 0 && cmd_size <= MARSHAL_MAX_CMD_SIZE) {
455 struct marshal_cmd_NamedBufferData *cmd =
456 _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_NamedBufferData,
457 cmd_size);
458 cmd->name = buffer;
459 cmd->size = size;
460 cmd->usage = usage;
461 cmd->data_null = !data;
462 if (data) {
463 char *variable_data = (char *) (cmd + 1);
464 memcpy(variable_data, data, size);
465 }
466 _mesa_post_marshal_hook(ctx);
467 } else {
468 _mesa_glthread_finish(ctx);
469 CALL_NamedBufferData(ctx->CurrentServerDispatch,
470 (buffer, size, data, usage));
471 }
472 }
473
474 /* NamedBufferSubData: marshalled asynchronously */
475 struct marshal_cmd_NamedBufferSubData
476 {
477 struct marshal_cmd_base cmd_base;
478 GLuint name;
479 GLintptr offset;
480 GLsizei size;
481 /* Next size bytes are GLubyte data[size] */
482 };
483
484 void
_mesa_unmarshal_NamedBufferSubData(struct gl_context * ctx,const struct marshal_cmd_NamedBufferSubData * cmd)485 _mesa_unmarshal_NamedBufferSubData(struct gl_context *ctx,
486 const struct marshal_cmd_NamedBufferSubData *cmd)
487 {
488 const GLuint name = cmd->name;
489 const GLintptr offset = cmd->offset;
490 const GLsizei size = cmd->size;
491 const void *data = (const void *) (cmd + 1);
492
493 CALL_NamedBufferSubData(ctx->CurrentServerDispatch,
494 (name, offset, size, data));
495 }
496
497 void GLAPIENTRY
_mesa_marshal_NamedBufferSubData(GLuint buffer,GLintptr offset,GLsizeiptr size,const GLvoid * data)498 _mesa_marshal_NamedBufferSubData(GLuint buffer, GLintptr offset,
499 GLsizeiptr size, const GLvoid * data)
500 {
501 GET_CURRENT_CONTEXT(ctx);
502 size_t cmd_size = sizeof(struct marshal_cmd_NamedBufferSubData) + size;
503
504 debug_print_marshal("NamedBufferSubData");
505 if (unlikely(size < 0)) {
506 _mesa_glthread_finish(ctx);
507 _mesa_error(ctx, GL_INVALID_VALUE, "NamedBufferSubData(size < 0)");
508 return;
509 }
510
511 if (buffer > 0 && cmd_size <= MARSHAL_MAX_CMD_SIZE) {
512 struct marshal_cmd_NamedBufferSubData *cmd =
513 _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_NamedBufferSubData,
514 cmd_size);
515 cmd->name = buffer;
516 cmd->offset = offset;
517 cmd->size = size;
518 char *variable_data = (char *) (cmd + 1);
519 memcpy(variable_data, data, size);
520 _mesa_post_marshal_hook(ctx);
521 } else {
522 _mesa_glthread_finish(ctx);
523 CALL_NamedBufferSubData(ctx->CurrentServerDispatch,
524 (buffer, offset, size, data));
525 }
526 }
527
528 /* ClearBuffer* (all variants): marshalled asynchronously */
529 struct marshal_cmd_ClearBuffer
530 {
531 struct marshal_cmd_base cmd_base;
532 GLenum buffer;
533 GLint drawbuffer;
534 };
535
536 void
_mesa_unmarshal_ClearBufferfv(struct gl_context * ctx,const struct marshal_cmd_ClearBuffer * cmd)537 _mesa_unmarshal_ClearBufferfv(struct gl_context *ctx,
538 const struct marshal_cmd_ClearBuffer *cmd)
539 {
540 const GLenum buffer = cmd->buffer;
541 const GLint drawbuffer = cmd->drawbuffer;
542 const char *variable_data = (const char *) (cmd + 1);
543 const GLfloat *value = (const GLfloat *) variable_data;
544
545 CALL_ClearBufferfv(ctx->CurrentServerDispatch,
546 (buffer, drawbuffer, value));
547 }
548
549 void
_mesa_unmarshal_ClearBufferiv(struct gl_context * ctx,const struct marshal_cmd_ClearBuffer * cmd)550 _mesa_unmarshal_ClearBufferiv(struct gl_context *ctx,
551 const struct marshal_cmd_ClearBuffer *cmd)
552 {
553 const GLenum buffer = cmd->buffer;
554 const GLint drawbuffer = cmd->drawbuffer;
555 const char *variable_data = (const char *) (cmd + 1);
556 const GLint *value = (const GLint *) variable_data;
557
558 CALL_ClearBufferiv(ctx->CurrentServerDispatch,
559 (buffer, drawbuffer, value));
560 }
561
562 void
_mesa_unmarshal_ClearBufferuiv(struct gl_context * ctx,const struct marshal_cmd_ClearBuffer * cmd)563 _mesa_unmarshal_ClearBufferuiv(struct gl_context *ctx,
564 const struct marshal_cmd_ClearBuffer *cmd)
565 {
566 const GLenum buffer = cmd->buffer;
567 const GLint drawbuffer = cmd->drawbuffer;
568 const char *variable_data = (const char *) (cmd + 1);
569 const GLuint *value = (const GLuint *) variable_data;
570
571 CALL_ClearBufferuiv(ctx->CurrentServerDispatch,
572 (buffer, drawbuffer, value));
573 }
574
575 void
_mesa_unmarshal_ClearBufferfi(struct gl_context * ctx,const struct marshal_cmd_ClearBuffer * cmd)576 _mesa_unmarshal_ClearBufferfi(struct gl_context *ctx,
577 const struct marshal_cmd_ClearBuffer *cmd)
578 {
579 const GLenum buffer = cmd->buffer;
580 const GLint drawbuffer = cmd->drawbuffer;
581 const char *variable_data = (const char *) (cmd + 1);
582 const GLfloat *depth = (const GLfloat *) variable_data;
583 const GLint *stencil = (const GLint *) (variable_data + 4);
584
585 CALL_ClearBufferfi(ctx->CurrentServerDispatch,
586 (buffer, drawbuffer, *depth, *stencil));
587 }
588
buffer_to_size(GLenum buffer)589 static inline size_t buffer_to_size(GLenum buffer)
590 {
591 switch (buffer) {
592 case GL_COLOR:
593 return 4;
594 case GL_DEPTH_STENCIL:
595 return 2;
596 case GL_STENCIL:
597 case GL_DEPTH:
598 return 1;
599 default:
600 return 0;
601 }
602 }
603
clear_buffer_add_command(struct gl_context * ctx,uint16_t id,GLenum buffer,GLint drawbuffer,const GLuint * value,size_t size)604 static inline bool clear_buffer_add_command(struct gl_context *ctx, uint16_t id,
605 GLenum buffer, GLint drawbuffer,
606 const GLuint *value, size_t size)
607 {
608 size_t cmd_size = sizeof(struct marshal_cmd_ClearBuffer) + 4 * size;
609 if (cmd_size <= MARSHAL_MAX_CMD_SIZE) {
610 struct marshal_cmd_ClearBuffer *cmd =
611 _mesa_glthread_allocate_command(ctx, id,
612 cmd_size);
613 cmd->buffer = buffer;
614 cmd->drawbuffer = drawbuffer;
615 GLuint *variable_data = (GLuint *) (cmd + 1);
616 if (size == 4)
617 COPY_4V(variable_data, value);
618 else if (size == 2)
619 COPY_2V(variable_data, value);
620 else
621 *variable_data = *value;
622
623 _mesa_post_marshal_hook(ctx);
624 return true;
625 }
626
627 return false;
628 }
629
630 void GLAPIENTRY
_mesa_marshal_ClearBufferfv(GLenum buffer,GLint drawbuffer,const GLfloat * value)631 _mesa_marshal_ClearBufferfv(GLenum buffer, GLint drawbuffer,
632 const GLfloat *value)
633 {
634 GET_CURRENT_CONTEXT(ctx);
635 debug_print_marshal("ClearBufferfv");
636
637 if (!(buffer == GL_DEPTH || buffer == GL_COLOR)) {
638 _mesa_glthread_finish(ctx);
639
640 /* Page 498 of the PDF, section '17.4.3.1 Clearing Individual Buffers'
641 * of the OpenGL 4.5 spec states:
642 *
643 * "An INVALID_ENUM error is generated by ClearBufferfv and
644 * ClearNamedFramebufferfv if buffer is not COLOR or DEPTH."
645 */
646 _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferfv(buffer=%s)",
647 _mesa_enum_to_string(buffer));
648 }
649
650 size_t size = buffer_to_size(buffer);
651 if (!clear_buffer_add_command(ctx, DISPATCH_CMD_ClearBufferfv, buffer,
652 drawbuffer, (GLuint *)value, size)) {
653 debug_print_sync("ClearBufferfv");
654 _mesa_glthread_finish(ctx);
655 CALL_ClearBufferfv(ctx->CurrentServerDispatch,
656 (buffer, drawbuffer, value));
657 }
658 }
659
660 void GLAPIENTRY
_mesa_marshal_ClearBufferiv(GLenum buffer,GLint drawbuffer,const GLint * value)661 _mesa_marshal_ClearBufferiv(GLenum buffer, GLint drawbuffer,
662 const GLint *value)
663 {
664 GET_CURRENT_CONTEXT(ctx);
665 debug_print_marshal("ClearBufferiv");
666
667 if (!(buffer == GL_STENCIL || buffer == GL_COLOR)) {
668 _mesa_glthread_finish(ctx);
669
670 /* Page 498 of the PDF, section '17.4.3.1 Clearing Individual Buffers'
671 * of the OpenGL 4.5 spec states:
672 *
673 * "An INVALID_ENUM error is generated by ClearBufferiv and
674 * ClearNamedFramebufferiv if buffer is not COLOR or STENCIL."
675 */
676 _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferiv(buffer=%s)",
677 _mesa_enum_to_string(buffer));
678 }
679
680 size_t size = buffer_to_size(buffer);
681 if (!clear_buffer_add_command(ctx, DISPATCH_CMD_ClearBufferiv, buffer,
682 drawbuffer, (GLuint *)value, size)) {
683 debug_print_sync("ClearBufferiv");
684 _mesa_glthread_finish(ctx);
685 CALL_ClearBufferiv(ctx->CurrentServerDispatch,
686 (buffer, drawbuffer, value));
687 }
688 }
689
690 void GLAPIENTRY
_mesa_marshal_ClearBufferuiv(GLenum buffer,GLint drawbuffer,const GLuint * value)691 _mesa_marshal_ClearBufferuiv(GLenum buffer, GLint drawbuffer,
692 const GLuint *value)
693 {
694 GET_CURRENT_CONTEXT(ctx);
695 debug_print_marshal("ClearBufferuiv");
696
697 if (buffer != GL_COLOR) {
698 _mesa_glthread_finish(ctx);
699
700 /* Page 498 of the PDF, section '17.4.3.1 Clearing Individual Buffers'
701 * of the OpenGL 4.5 spec states:
702 *
703 * "An INVALID_ENUM error is generated by ClearBufferuiv and
704 * ClearNamedFramebufferuiv if buffer is not COLOR."
705 */
706 _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferuiv(buffer=%s)",
707 _mesa_enum_to_string(buffer));
708 }
709
710 if (!clear_buffer_add_command(ctx, DISPATCH_CMD_ClearBufferuiv, buffer,
711 drawbuffer, (GLuint *)value, 4)) {
712 debug_print_sync("ClearBufferuiv");
713 _mesa_glthread_finish(ctx);
714 CALL_ClearBufferuiv(ctx->CurrentServerDispatch,
715 (buffer, drawbuffer, value));
716 }
717 }
718
719 void GLAPIENTRY
_mesa_marshal_ClearBufferfi(GLenum buffer,GLint drawbuffer,const GLfloat depth,const GLint stencil)720 _mesa_marshal_ClearBufferfi(GLenum buffer, GLint drawbuffer,
721 const GLfloat depth, const GLint stencil)
722 {
723 GET_CURRENT_CONTEXT(ctx);
724 debug_print_marshal("ClearBufferfi");
725
726 if (buffer != GL_DEPTH_STENCIL) {
727 _mesa_glthread_finish(ctx);
728
729 /* Page 498 of the PDF, section '17.4.3.1 Clearing Individual Buffers'
730 * of the OpenGL 4.5 spec states:
731 *
732 * "An INVALID_ENUM error is generated by ClearBufferfi and
733 * ClearNamedFramebufferfi if buffer is not DEPTH_STENCIL."
734 */
735 _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferfi(buffer=%s)",
736 _mesa_enum_to_string(buffer));
737 }
738
739 fi_type value[2];
740 value[0].f = depth;
741 value[1].i = stencil;
742 if (!clear_buffer_add_command(ctx, DISPATCH_CMD_ClearBufferfi, buffer,
743 drawbuffer, (GLuint *)value, 2)) {
744 debug_print_sync("ClearBufferfi");
745 _mesa_glthread_finish(ctx);
746 CALL_ClearBufferfi(ctx->CurrentServerDispatch,
747 (buffer, drawbuffer, depth, stencil));
748 }
749 }
750