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
36struct marshal_cmd_Flush
37{
38   struct marshal_cmd_base cmd_base;
39};
40
41
42void
43_mesa_unmarshal_Flush(struct gl_context *ctx,
44                      const struct marshal_cmd_Flush *cmd)
45{
46   CALL_Flush(ctx->CurrentServerDispatch, ());
47}
48
49
50void GLAPIENTRY
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 */
69struct marshal_cmd_Enable
70{
71   struct marshal_cmd_base cmd_base;
72   GLenum cap;
73};
74
75void
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
83void GLAPIENTRY
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, "Enable(DEBUG_OUTPUT_SYNCHRONOUS)");
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
106struct 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
117void
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
137static size_t
138measure_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
157void GLAPIENTRY
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 */
199struct 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 */
230static void
231track_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
250struct 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 */
261void
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}
269void GLAPIENTRY
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 */
292struct 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
302void
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
319void GLAPIENTRY
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 */
357struct 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
366void
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
379void GLAPIENTRY
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 */
412struct 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
422void
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
440void GLAPIENTRY
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 */
475struct 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
484void
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
497void GLAPIENTRY
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 */
529struct marshal_cmd_ClearBuffer
530{
531   struct marshal_cmd_base cmd_base;
532   GLenum buffer;
533   GLint drawbuffer;
534};
535
536void
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
549void
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
562void
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
575void
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
589static 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
604static 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
630void GLAPIENTRY
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
660void GLAPIENTRY
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
690void GLAPIENTRY
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
719void GLAPIENTRY
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