• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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