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