xref: /aosp_15_r20/external/mesa3d/src/mesa/main/glthread_draw.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2020 Advanced Micro Devices, Inc.
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 /* Draw function marshalling for glthread.
25  *
26  * The purpose of these glDraw wrappers is to upload non-VBO vertex and
27  * index data, so that glthread doesn't have to execute synchronously.
28  */
29 
30 #include "c99_alloca.h"
31 
32 #include "api_exec_decl.h"
33 #include "main/glthread_marshal.h"
34 #include "main/dispatch.h"
35 #include "main/varray.h"
36 
37 static inline unsigned
get_index_size(GLenum type)38 get_index_size(GLenum type)
39 {
40    return 1 << _mesa_get_index_size_shift(type);
41 }
42 
43 static inline GLindextype
encode_index_type(GLenum type)44 encode_index_type(GLenum type)
45 {
46    /* Map invalid values less than GL_UNSIGNED_BYTE to GL_UNSIGNED_BYTE - 1,
47     * and invalid values greater than GL_UNSIGNED_INT to GL_UNSIGNED_INT + 1,
48     * Then subtract GL_UNSIGNED_BYTE - 1. Final encoding:
49     *    0 = invalid value
50     *    1 = GL_UNSIGNED_BYTE
51     *    2 = invalid value
52     *    3 = GL_UNSIGNED_SHORT
53     *    4 = invalid value
54     *    5 = GL_UNSIGNED_INT
55     *    6 = invalid value
56     */
57    const unsigned min = GL_UNSIGNED_BYTE - 1;
58    const unsigned max = GL_UNSIGNED_INT + 1;
59    return (GLindextype){CLAMP(type, min, max) - min};
60 }
61 
62 static ALWAYS_INLINE struct gl_buffer_object *
upload_indices(struct gl_context * ctx,unsigned count,unsigned index_size,const GLvoid ** indices)63 upload_indices(struct gl_context *ctx, unsigned count, unsigned index_size,
64                const GLvoid **indices)
65 {
66    struct gl_buffer_object *upload_buffer = NULL;
67    unsigned upload_offset = 0;
68 
69    assert(count);
70 
71    _mesa_glthread_upload(ctx, *indices, index_size * count,
72                          &upload_offset, &upload_buffer, NULL, 0);
73    *indices = (const GLvoid*)(intptr_t)upload_offset;
74 
75    if (!upload_buffer)
76       _mesa_marshal_InternalSetError(GL_OUT_OF_MEMORY);
77 
78    return upload_buffer;
79 }
80 
81 static ALWAYS_INLINE struct gl_buffer_object *
upload_multi_indices(struct gl_context * ctx,unsigned total_count,unsigned index_size,unsigned draw_count,const GLsizei * count,const GLvoid * const * indices,const GLvoid ** out_indices)82 upload_multi_indices(struct gl_context *ctx, unsigned total_count,
83                      unsigned index_size, unsigned draw_count,
84                      const GLsizei *count, const GLvoid *const *indices,
85                      const GLvoid **out_indices)
86 {
87    struct gl_buffer_object *upload_buffer = NULL;
88    unsigned upload_offset = 0;
89    uint8_t *upload_ptr = NULL;
90 
91    assert(total_count);
92 
93    _mesa_glthread_upload(ctx, NULL, index_size * total_count,
94                          &upload_offset, &upload_buffer, &upload_ptr, 0);
95    if (!upload_buffer) {
96       _mesa_marshal_InternalSetError(GL_OUT_OF_MEMORY);
97       return NULL;
98    }
99 
100    for (unsigned i = 0, offset = 0; i < draw_count; i++) {
101       if (!count[i]) {
102          /* Set some valid value so as not to leave it uninitialized. */
103          out_indices[i] = (const GLvoid*)(intptr_t)upload_offset;
104          continue;
105       }
106 
107       unsigned size = count[i] * index_size;
108 
109       memcpy(upload_ptr + offset, indices[i], size);
110       out_indices[i] = (const GLvoid*)(intptr_t)(upload_offset + offset);
111       offset += size;
112    }
113 
114    return upload_buffer;
115 }
116 
117 static ALWAYS_INLINE bool
upload_vertices(struct gl_context * ctx,unsigned user_buffer_mask,unsigned start_vertex,unsigned num_vertices,unsigned start_instance,unsigned num_instances,struct gl_buffer_object ** buffers,int * offsets)118 upload_vertices(struct gl_context *ctx, unsigned user_buffer_mask,
119                 unsigned start_vertex, unsigned num_vertices,
120                 unsigned start_instance, unsigned num_instances,
121                 struct gl_buffer_object **buffers, int *offsets)
122 {
123    struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
124    unsigned attrib_mask_iter = vao->Enabled;
125    unsigned num_buffers = 0;
126 
127    assert((num_vertices || !(user_buffer_mask & ~vao->NonZeroDivisorMask)) &&
128           (num_instances || !(user_buffer_mask & vao->NonZeroDivisorMask)));
129 
130    if (unlikely(vao->BufferInterleaved & user_buffer_mask)) {
131       /* Slower upload path where some buffers reference multiple attribs,
132        * so we have to use 2 while loops instead of 1.
133        */
134       unsigned start_offset[VERT_ATTRIB_MAX];
135       unsigned end_offset[VERT_ATTRIB_MAX];
136       uint32_t buffer_mask = 0;
137 
138       while (attrib_mask_iter) {
139          unsigned i = u_bit_scan(&attrib_mask_iter);
140          unsigned binding_index = vao->Attrib[i].BufferIndex;
141 
142          if (!(user_buffer_mask & (1 << binding_index)))
143             continue;
144 
145          unsigned stride = vao->Attrib[binding_index].Stride;
146          unsigned instance_div = vao->Attrib[binding_index].Divisor;
147          unsigned element_size = vao->Attrib[i].ElementSize;
148          unsigned offset = vao->Attrib[i].RelativeOffset;
149          unsigned size;
150 
151          if (instance_div) {
152             /* Per-instance attrib. */
153 
154             /* Figure out how many instances we'll render given instance_div.  We
155              * can't use the typical div_round_up() pattern because the CTS uses
156              * instance_div = ~0 for a test, which overflows div_round_up()'s
157              * addition.
158              */
159             unsigned count = num_instances / instance_div;
160             if (count * instance_div != num_instances)
161                count++;
162 
163             offset += stride * start_instance;
164             size = stride * (count - 1) + element_size;
165          } else {
166             /* Per-vertex attrib. */
167             offset += stride * start_vertex;
168             size = stride * (num_vertices - 1) + element_size;
169          }
170 
171          unsigned binding_index_bit = 1u << binding_index;
172 
173          /* Update upload offsets. */
174          if (!(buffer_mask & binding_index_bit)) {
175             start_offset[binding_index] = offset;
176             end_offset[binding_index] = offset + size;
177          } else {
178             if (offset < start_offset[binding_index])
179                start_offset[binding_index] = offset;
180             if (offset + size > end_offset[binding_index])
181                end_offset[binding_index] = offset + size;
182          }
183 
184          buffer_mask |= binding_index_bit;
185       }
186 
187       /* Upload buffers. */
188       while (buffer_mask) {
189          struct gl_buffer_object *upload_buffer = NULL;
190          unsigned upload_offset = 0;
191          unsigned start, end;
192 
193          unsigned binding_index = u_bit_scan(&buffer_mask);
194 
195          start = start_offset[binding_index];
196          end = end_offset[binding_index];
197          assert(start < end);
198 
199          /* If the draw start index is non-zero, glthread can upload to offset 0,
200          * which means the attrib offset has to be -(first * stride).
201          * So use signed vertex buffer offsets when possible to save memory.
202          */
203          const void *ptr = vao->Attrib[binding_index].Pointer;
204          _mesa_glthread_upload(ctx, (uint8_t*)ptr + start,
205                                end - start, &upload_offset,
206                                &upload_buffer, NULL, ctx->Const.VertexBufferOffsetIsInt32 ? 0 : start);
207          if (!upload_buffer) {
208             for (unsigned i = 0; i < num_buffers; i++)
209                _mesa_reference_buffer_object(ctx, &buffers[i], NULL);
210 
211             _mesa_marshal_InternalSetError(GL_OUT_OF_MEMORY);
212             return false;
213          }
214 
215          buffers[num_buffers] = upload_buffer;
216          offsets[num_buffers] = upload_offset - start;
217          num_buffers++;
218       }
219 
220       return true;
221    }
222 
223    /* Faster path where all attribs are separate. */
224    while (attrib_mask_iter) {
225       unsigned i = u_bit_scan(&attrib_mask_iter);
226       unsigned binding_index = vao->Attrib[i].BufferIndex;
227 
228       if (!(user_buffer_mask & (1 << binding_index)))
229          continue;
230 
231       struct gl_buffer_object *upload_buffer = NULL;
232       unsigned upload_offset = 0;
233       unsigned stride = vao->Attrib[binding_index].Stride;
234       unsigned instance_div = vao->Attrib[binding_index].Divisor;
235       unsigned element_size = vao->Attrib[i].ElementSize;
236       unsigned offset = vao->Attrib[i].RelativeOffset;
237       unsigned size;
238 
239       if (instance_div) {
240          /* Per-instance attrib. */
241 
242          /* Figure out how many instances we'll render given instance_div.  We
243           * can't use the typical div_round_up() pattern because the CTS uses
244           * instance_div = ~0 for a test, which overflows div_round_up()'s
245           * addition.
246           */
247          unsigned count = num_instances / instance_div;
248          if (count * instance_div != num_instances)
249             count++;
250 
251          offset += stride * start_instance;
252          size = stride * (count - 1) + element_size;
253       } else {
254          /* Per-vertex attrib. */
255          offset += stride * start_vertex;
256          size = stride * (num_vertices - 1) + element_size;
257       }
258 
259       /* If the draw start index is non-zero, glthread can upload to offset 0,
260        * which means the attrib offset has to be -(first * stride).
261        * So use signed vertex buffer offsets when possible to save memory.
262        */
263       const void *ptr = vao->Attrib[binding_index].Pointer;
264       _mesa_glthread_upload(ctx, (uint8_t*)ptr + offset,
265                             size, &upload_offset, &upload_buffer, NULL,
266                             ctx->Const.VertexBufferOffsetIsInt32 ? 0 : offset);
267       if (!upload_buffer) {
268          for (unsigned i = 0; i < num_buffers; i++)
269             _mesa_reference_buffer_object(ctx, &buffers[i], NULL);
270 
271          _mesa_marshal_InternalSetError(GL_OUT_OF_MEMORY);
272          return false;
273       }
274 
275       buffers[num_buffers] = upload_buffer;
276       offsets[num_buffers] = upload_offset - offset;
277       num_buffers++;
278    }
279 
280    return true;
281 }
282 
283 /* DrawArraysInstanced without user buffers. */
284 uint32_t
_mesa_unmarshal_DrawArraysInstanced(struct gl_context * ctx,const struct marshal_cmd_DrawArraysInstanced * restrict cmd)285 _mesa_unmarshal_DrawArraysInstanced(struct gl_context *ctx,
286                                     const struct marshal_cmd_DrawArraysInstanced *restrict cmd)
287 {
288    const GLenum mode = cmd->mode;
289    const GLint first = cmd->first;
290    const GLsizei count = cmd->count;
291    const GLsizei instance_count = cmd->primcount;
292 
293    CALL_DrawArraysInstanced(ctx->Dispatch.Current, (mode, first, count, instance_count));
294    return align(sizeof(*cmd), 8) / 8;
295 }
296 
297 struct marshal_cmd_DrawArraysInstancedBaseInstanceDrawID
298 {
299    struct marshal_cmd_base cmd_base;
300    GLenum8 mode;
301    GLint first;
302    GLsizei count;
303    GLsizei instance_count;
304    GLuint baseinstance;
305    GLuint drawid;
306 };
307 
308 uint32_t
_mesa_unmarshal_DrawArraysInstancedBaseInstanceDrawID(struct gl_context * ctx,const struct marshal_cmd_DrawArraysInstancedBaseInstanceDrawID * cmd)309 _mesa_unmarshal_DrawArraysInstancedBaseInstanceDrawID(struct gl_context *ctx,
310                                                 const struct marshal_cmd_DrawArraysInstancedBaseInstanceDrawID *cmd)
311 {
312    const GLenum mode = cmd->mode;
313    const GLint first = cmd->first;
314    const GLsizei count = cmd->count;
315    const GLsizei instance_count = cmd->instance_count;
316    const GLuint baseinstance = cmd->baseinstance;
317 
318    ctx->DrawID = cmd->drawid;
319    CALL_DrawArraysInstancedBaseInstance(ctx->Dispatch.Current,
320                                         (mode, first, count, instance_count,
321                                          baseinstance));
322    ctx->DrawID = 0;
323    return align(sizeof(*cmd), 8) / 8;
324 }
325 
326 /* DrawArraysInstancedBaseInstance with user buffers. */
327 struct marshal_cmd_DrawArraysUserBuf
328 {
329    struct marshal_cmd_base cmd_base;
330    GLenum8 mode;
331    uint16_t num_slots;
332    GLint first;
333    GLsizei count;
334    GLsizei instance_count;
335    GLuint baseinstance;
336    GLuint drawid;
337    GLuint user_buffer_mask;
338 };
339 
340 uint32_t
_mesa_unmarshal_DrawArraysUserBuf(struct gl_context * ctx,const struct marshal_cmd_DrawArraysUserBuf * restrict cmd)341 _mesa_unmarshal_DrawArraysUserBuf(struct gl_context *ctx,
342                                   const struct marshal_cmd_DrawArraysUserBuf *restrict cmd)
343 {
344    const GLuint user_buffer_mask = cmd->user_buffer_mask;
345 
346    /* Bind uploaded buffers if needed. */
347    if (user_buffer_mask) {
348       struct gl_buffer_object **buffers = (struct gl_buffer_object **)(cmd + 1);
349       const int *offsets = (const int *)(buffers + util_bitcount(user_buffer_mask));
350 
351       _mesa_InternalBindVertexBuffers(ctx, buffers, offsets, user_buffer_mask);
352    }
353 
354    const GLenum mode = cmd->mode;
355    const GLint first = cmd->first;
356    const GLsizei count = cmd->count;
357    const GLsizei instance_count = cmd->instance_count;
358    const GLuint baseinstance = cmd->baseinstance;
359 
360    ctx->DrawID = cmd->drawid;
361    CALL_DrawArraysInstancedBaseInstance(ctx->Dispatch.Current,
362                                         (mode, first, count, instance_count,
363                                          baseinstance));
364    ctx->DrawID = 0;
365    return cmd->num_slots;
366 }
367 
368 static inline unsigned
get_user_buffer_mask(struct gl_context * ctx)369 get_user_buffer_mask(struct gl_context *ctx)
370 {
371    struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
372 
373    /* BufferEnabled means which attribs are enabled in terms of buffer
374     * binding slots (not attrib slots).
375     *
376     * UserPointerMask means which buffer bindings don't have a buffer bound.
377     *
378     * NonNullPointerMask means which buffer bindings have a NULL pointer.
379     * Those are not uploaded. This can happen when an attrib is enabled, but
380     * the shader doesn't use it, so it's ignored by mesa/state_tracker.
381     */
382    return vao->BufferEnabled & vao->UserPointerMask & vao->NonNullPointerMask;
383 }
384 
385 static ALWAYS_INLINE void
draw_arrays(GLuint drawid,GLenum mode,GLint first,GLsizei count,GLsizei instance_count,GLuint baseinstance,bool compiled_into_dlist,bool no_error)386 draw_arrays(GLuint drawid, GLenum mode, GLint first, GLsizei count,
387             GLsizei instance_count, GLuint baseinstance,
388             bool compiled_into_dlist, bool no_error)
389 {
390    GET_CURRENT_CONTEXT(ctx);
391 
392    /* The main benefit of no_error is that we can discard no-op draws
393     * immediately.
394     */
395    if (no_error && (count <= 0 || instance_count <= 0))
396       return;
397 
398    if (unlikely(compiled_into_dlist && ctx->GLThread.ListMode)) {
399       _mesa_glthread_finish_before(ctx, "DrawArrays");
400       /* Use the function that's compiled into a display list. */
401       CALL_DrawArrays(ctx->Dispatch.Current, (mode, first, count));
402       return;
403    }
404 
405    unsigned user_buffer_mask =
406       _mesa_is_desktop_gl_core(ctx) ? 0 : get_user_buffer_mask(ctx);
407 
408    /* Fast path when nothing needs to be done.
409     *
410     * This is also an error path. Zero counts should still call the driver
411     * for possible GL errors.
412     */
413    if (!user_buffer_mask ||
414        (!no_error &&
415         (count <= 0 || instance_count <= 0 ||   /* GL_INVALID_VALUE / no-op */
416          ctx->GLThread.inside_begin_end ||      /* GL_INVALID_OPERATION */
417          ctx->Dispatch.Current == ctx->Dispatch.ContextLost || /* GL_INVALID_OPERATION */
418          ctx->GLThread.ListMode))) {            /* GL_INVALID_OPERATION */
419       if (baseinstance == 0 && drawid == 0) {
420          int cmd_size = sizeof(struct marshal_cmd_DrawArraysInstanced);
421          struct marshal_cmd_DrawArraysInstanced *cmd =
422             _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawArraysInstanced, cmd_size);
423 
424          cmd->mode = MIN2(mode, 0xff); /* clamped to 0xff (invalid enum) */
425          cmd->first = first;
426          cmd->count = count;
427          cmd->primcount = instance_count;
428       } else {
429          int cmd_size = sizeof(struct marshal_cmd_DrawArraysInstancedBaseInstanceDrawID);
430          struct marshal_cmd_DrawArraysInstancedBaseInstanceDrawID *cmd =
431             _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawArraysInstancedBaseInstanceDrawID, cmd_size);
432 
433          cmd->mode = MIN2(mode, 0xff); /* clamped to 0xff (invalid enum) */
434          cmd->first = first;
435          cmd->count = count;
436          cmd->instance_count = instance_count;
437          cmd->baseinstance = baseinstance;
438          cmd->drawid = drawid;
439       }
440       return;
441    }
442 
443    /* Upload and draw. */
444    struct gl_buffer_object *buffers[VERT_ATTRIB_MAX];
445    int offsets[VERT_ATTRIB_MAX];
446 
447    if (!upload_vertices(ctx, user_buffer_mask, first, count, baseinstance,
448                         instance_count, buffers, offsets))
449       return; /* the error is set by upload_vertices */
450 
451    unsigned num_buffers = util_bitcount(user_buffer_mask);
452    int buffers_size = num_buffers * sizeof(buffers[0]);
453    int offsets_size = num_buffers * sizeof(int);
454    int cmd_size = sizeof(struct marshal_cmd_DrawArraysUserBuf) +
455                   buffers_size + offsets_size;
456    struct marshal_cmd_DrawArraysUserBuf *cmd;
457 
458    cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawArraysUserBuf,
459                                          cmd_size);
460    cmd->num_slots = align(cmd_size, 8) / 8;
461    cmd->mode = MIN2(mode, 0xff); /* clamped to 0xff (invalid enum) */
462    cmd->first = first;
463    cmd->count = count;
464    cmd->instance_count = instance_count;
465    cmd->baseinstance = baseinstance;
466    cmd->drawid = drawid;
467    cmd->user_buffer_mask = user_buffer_mask;
468 
469    if (user_buffer_mask) {
470       char *variable_data = (char*)(cmd + 1);
471       memcpy(variable_data, buffers, buffers_size);
472       variable_data += buffers_size;
473       memcpy(variable_data, offsets, offsets_size);
474    }
475 }
476 
477 /* MultiDrawArrays with user buffers. */
478 struct marshal_cmd_MultiDrawArraysUserBuf
479 {
480    struct marshal_cmd_base cmd_base;
481    GLenum8 mode;
482    uint16_t num_slots;
483    GLsizei draw_count;
484    GLuint user_buffer_mask;
485 };
486 
487 uint32_t
_mesa_unmarshal_MultiDrawArraysUserBuf(struct gl_context * ctx,const struct marshal_cmd_MultiDrawArraysUserBuf * restrict cmd)488 _mesa_unmarshal_MultiDrawArraysUserBuf(struct gl_context *ctx,
489                                        const struct marshal_cmd_MultiDrawArraysUserBuf *restrict cmd)
490 {
491    const GLenum mode = cmd->mode;
492    const GLsizei draw_count = cmd->draw_count;
493    const GLsizei real_draw_count = MAX2(draw_count, 0);
494    const GLuint user_buffer_mask = cmd->user_buffer_mask;
495 
496    const char *variable_data = (const char *)(cmd + 1);
497    const GLint *first = (GLint *)variable_data;
498    variable_data += sizeof(GLint) * real_draw_count;
499    const GLsizei *count = (GLsizei *)variable_data;
500 
501    /* Bind uploaded buffers if needed. */
502    if (user_buffer_mask) {
503       variable_data += sizeof(GLsizei) * real_draw_count;
504       const int *offsets = (const int *)variable_data;
505       variable_data += sizeof(int) * util_bitcount(user_buffer_mask);
506 
507       /* Align for pointers. */
508       if ((uintptr_t)variable_data % sizeof(uintptr_t))
509          variable_data += 4;
510 
511       struct gl_buffer_object **buffers = (struct gl_buffer_object **)variable_data;
512 
513       _mesa_InternalBindVertexBuffers(ctx, buffers, offsets, user_buffer_mask);
514    }
515 
516    CALL_MultiDrawArrays(ctx->Dispatch.Current,
517                         (mode, first, count, draw_count));
518    return cmd->num_slots;
519 }
520 
521 void GLAPIENTRY
_mesa_marshal_MultiDrawArrays(GLenum mode,const GLint * first,const GLsizei * count,GLsizei draw_count)522 _mesa_marshal_MultiDrawArrays(GLenum mode, const GLint *first,
523                               const GLsizei *count, GLsizei draw_count)
524 {
525    GET_CURRENT_CONTEXT(ctx);
526 
527    if (unlikely(ctx->GLThread.ListMode)) {
528       _mesa_glthread_finish_before(ctx, "MultiDrawArrays");
529       CALL_MultiDrawArrays(ctx->Dispatch.Current,
530                            (mode, first, count, draw_count));
531       return;
532    }
533 
534    struct gl_buffer_object *buffers[VERT_ATTRIB_MAX];
535    int offsets[VERT_ATTRIB_MAX];
536    unsigned user_buffer_mask =
537       _mesa_is_desktop_gl_core(ctx) || draw_count <= 0 ||
538       ctx->Dispatch.Current == ctx->Dispatch.ContextLost ||
539       ctx->GLThread.inside_begin_end ? 0 : get_user_buffer_mask(ctx);
540 
541    if (user_buffer_mask) {
542       unsigned min_index = ~0;
543       unsigned max_index_exclusive = 0;
544 
545       for (int i = 0; i < draw_count; i++) {
546          GLsizei vertex_count = count[i];
547 
548          if (vertex_count < 0) {
549             /* This will just call the driver to set the GL error. */
550             min_index = ~0;
551             break;
552          }
553          if (vertex_count == 0)
554             continue;
555 
556          min_index = MIN2(min_index, first[i]);
557          max_index_exclusive = MAX2(max_index_exclusive, first[i] + vertex_count);
558       }
559 
560       if (min_index >= max_index_exclusive) {
561          /* Nothing to do, but call the driver to set possible GL errors. */
562          user_buffer_mask = 0;
563       } else {
564          /* Upload. */
565          unsigned num_vertices = max_index_exclusive - min_index;
566 
567          if (!upload_vertices(ctx, user_buffer_mask, min_index, num_vertices,
568                               0, 1, buffers, offsets))
569             return; /* the error is set by upload_vertices */
570       }
571    }
572 
573    /* Add the call into the batch buffer. */
574    int real_draw_count = MAX2(draw_count, 0);
575    int first_size = sizeof(GLint) * real_draw_count;
576    int count_size = sizeof(GLsizei) * real_draw_count;
577    unsigned num_buffers = util_bitcount(user_buffer_mask);
578    int buffers_size = num_buffers * sizeof(buffers[0]);
579    int offsets_size = num_buffers * sizeof(int);
580    int cmd_size = sizeof(struct marshal_cmd_MultiDrawArraysUserBuf) +
581                   first_size + count_size + buffers_size + offsets_size;
582    struct marshal_cmd_MultiDrawArraysUserBuf *cmd;
583 
584    /* Make sure cmd can fit in the batch buffer */
585    if (cmd_size <= MARSHAL_MAX_CMD_SIZE) {
586       cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_MultiDrawArraysUserBuf,
587                                             cmd_size);
588       cmd->num_slots = align(cmd_size, 8) / 8;
589       cmd->mode = MIN2(mode, 0xff); /* clamped to 0xff (invalid enum) */
590       cmd->draw_count = draw_count;
591       cmd->user_buffer_mask = user_buffer_mask;
592 
593       char *variable_data = (char*)(cmd + 1);
594       memcpy(variable_data, first, first_size);
595       variable_data += first_size;
596       memcpy(variable_data, count, count_size);
597 
598       if (user_buffer_mask) {
599          variable_data += count_size;
600          memcpy(variable_data, offsets, offsets_size);
601          variable_data += offsets_size;
602 
603          /* Align for pointers. */
604          if ((uintptr_t)variable_data % sizeof(uintptr_t))
605             variable_data += 4;
606 
607          memcpy(variable_data, buffers, buffers_size);
608       }
609    } else {
610       /* The call is too large, so sync and execute the unmarshal code here. */
611       _mesa_glthread_finish_before(ctx, "MultiDrawArrays");
612 
613       if (user_buffer_mask) {
614          _mesa_InternalBindVertexBuffers(ctx, buffers, offsets,
615                                          user_buffer_mask);
616       }
617 
618       CALL_MultiDrawArrays(ctx->Dispatch.Current,
619                            (mode, first, count, draw_count));
620    }
621 }
622 
623 uint32_t
_mesa_unmarshal_DrawElements(struct gl_context * ctx,const struct marshal_cmd_DrawElements * restrict cmd)624 _mesa_unmarshal_DrawElements(struct gl_context *ctx,
625                              const struct marshal_cmd_DrawElements *restrict cmd)
626 {
627    const GLenum mode = cmd->mode;
628    const GLsizei count = cmd->count;
629    const GLenum type = _mesa_decode_index_type(cmd->type);
630    const GLvoid *indices = cmd->indices;
631 
632    CALL_DrawElements(ctx->Dispatch.Current, (mode, count, type, indices));
633    return align(sizeof(*cmd), 8) / 8;
634 }
635 
636 uint32_t
_mesa_unmarshal_DrawElementsPacked(struct gl_context * ctx,const struct marshal_cmd_DrawElementsPacked * restrict cmd)637 _mesa_unmarshal_DrawElementsPacked(struct gl_context *ctx,
638                                    const struct marshal_cmd_DrawElementsPacked *restrict cmd)
639 {
640    const GLenum mode = cmd->mode;
641    const GLsizei count = cmd->count;
642    const GLenum type = _mesa_decode_index_type(cmd->type);
643    const GLvoid *indices = (void*)(uintptr_t)cmd->indices;
644 
645    CALL_DrawElements(ctx->Dispatch.Current, (mode, count, type, indices));
646    return align(sizeof(*cmd), 8) / 8;
647 }
648 
649 uint32_t
_mesa_unmarshal_DrawElementsInstancedBaseVertex(struct gl_context * ctx,const struct marshal_cmd_DrawElementsInstancedBaseVertex * restrict cmd)650 _mesa_unmarshal_DrawElementsInstancedBaseVertex(struct gl_context *ctx,
651                                                 const struct marshal_cmd_DrawElementsInstancedBaseVertex *restrict cmd)
652 {
653    const GLenum mode = cmd->mode;
654    const GLsizei count = cmd->count;
655    const GLenum type = _mesa_decode_index_type(cmd->type);
656    const GLvoid *indices = cmd->indices;
657    const GLsizei instance_count = cmd->primcount;
658    const GLint basevertex = cmd->basevertex;
659 
660    CALL_DrawElementsInstancedBaseVertex(ctx->Dispatch.Current,
661                                         (mode, count, type, indices,
662                                          instance_count, basevertex));
663    return align(sizeof(*cmd), 8) / 8;
664 }
665 
666 uint32_t
_mesa_unmarshal_DrawElementsInstancedBaseInstance(struct gl_context * ctx,const struct marshal_cmd_DrawElementsInstancedBaseInstance * restrict cmd)667 _mesa_unmarshal_DrawElementsInstancedBaseInstance(struct gl_context *ctx,
668                                                   const struct marshal_cmd_DrawElementsInstancedBaseInstance *restrict cmd)
669 {
670    const GLenum mode = cmd->mode;
671    const GLsizei count = cmd->count;
672    const GLenum type = _mesa_decode_index_type(cmd->type);
673    const GLvoid *indices = cmd->indices;
674    const GLsizei instance_count = cmd->primcount;
675    const GLint baseinstance = cmd->baseinstance;
676 
677    CALL_DrawElementsInstancedBaseInstance(ctx->Dispatch.Current,
678                                           (mode, count, type, indices,
679                                            instance_count, baseinstance));
680    return align(sizeof(*cmd), 8) / 8;
681 }
682 
683 uint32_t
_mesa_unmarshal_DrawElementsInstancedBaseVertexBaseInstanceDrawID(struct gl_context * ctx,const struct marshal_cmd_DrawElementsInstancedBaseVertexBaseInstanceDrawID * restrict cmd)684 _mesa_unmarshal_DrawElementsInstancedBaseVertexBaseInstanceDrawID(struct gl_context *ctx,
685                                                                   const struct marshal_cmd_DrawElementsInstancedBaseVertexBaseInstanceDrawID *restrict cmd)
686 {
687    const GLenum mode = cmd->mode;
688    const GLsizei count = cmd->count;
689    const GLenum type = _mesa_decode_index_type(cmd->type);
690    const GLvoid *indices = cmd->indices;
691    const GLsizei instance_count = cmd->instance_count;
692    const GLint basevertex = cmd->basevertex;
693    const GLuint baseinstance = cmd->baseinstance;
694 
695    ctx->DrawID = cmd->drawid;
696    CALL_DrawElementsInstancedBaseVertexBaseInstance(ctx->Dispatch.Current,
697                                                     (mode, count, type, indices,
698                                                      instance_count, basevertex,
699                                                      baseinstance));
700    ctx->DrawID = 0;
701 
702    return align(sizeof(*cmd), 8) / 8;
703 }
704 
705 uint32_t
_mesa_unmarshal_DrawElementsUserBuf(struct gl_context * ctx,const struct marshal_cmd_DrawElementsUserBuf * restrict cmd)706 _mesa_unmarshal_DrawElementsUserBuf(struct gl_context *ctx,
707                                     const struct marshal_cmd_DrawElementsUserBuf *restrict cmd)
708 {
709    const GLuint user_buffer_mask = cmd->user_buffer_mask;
710 
711    /* Bind uploaded buffers if needed. */
712    if (user_buffer_mask) {
713       struct gl_buffer_object **buffers = (struct gl_buffer_object **)(cmd + 1);
714       const int *offsets = (const int *)(buffers + util_bitcount(user_buffer_mask));
715 
716       _mesa_InternalBindVertexBuffers(ctx, buffers, offsets, user_buffer_mask);
717    }
718 
719    /* Draw. */
720    CALL_DrawElementsUserBuf(ctx->Dispatch.Current, (cmd));
721 
722    struct gl_buffer_object *index_buffer = cmd->index_buffer;
723    _mesa_reference_buffer_object(ctx, &index_buffer, NULL);
724    return cmd->num_slots;
725 }
726 
727 uint32_t
_mesa_unmarshal_DrawElementsUserBufPacked(struct gl_context * ctx,const struct marshal_cmd_DrawElementsUserBufPacked * restrict cmd)728 _mesa_unmarshal_DrawElementsUserBufPacked(struct gl_context *ctx,
729                                     const struct marshal_cmd_DrawElementsUserBufPacked *restrict cmd)
730 {
731    const GLuint user_buffer_mask = cmd->user_buffer_mask;
732 
733    /* Bind uploaded buffers if needed. */
734    if (user_buffer_mask) {
735       struct gl_buffer_object **buffers = (struct gl_buffer_object **)(cmd + 1);
736       const int *offsets = (const int *)(buffers + util_bitcount(user_buffer_mask));
737 
738       _mesa_InternalBindVertexBuffers(ctx, buffers, offsets, user_buffer_mask);
739    }
740 
741    /* Draw. */
742    CALL_DrawElementsUserBufPacked(ctx->Dispatch.Current, (cmd));
743 
744    struct gl_buffer_object *index_buffer = cmd->index_buffer;
745    _mesa_reference_buffer_object(ctx, &index_buffer, NULL);
746    return cmd->num_slots;
747 }
748 
749 static inline bool
should_convert_to_begin_end(struct gl_context * ctx,unsigned count,unsigned num_upload_vertices,unsigned instance_count,struct glthread_vao * vao)750 should_convert_to_begin_end(struct gl_context *ctx, unsigned count,
751                             unsigned num_upload_vertices,
752                             unsigned instance_count, struct glthread_vao *vao)
753 {
754    /* Some of these are limitations of _mesa_glthread_UnrollDrawElements.
755     * Others prevent syncing, such as disallowing buffer objects because we
756     * can't map them without syncing.
757     */
758    return ctx->API == API_OPENGL_COMPAT &&
759           util_is_vbo_upload_ratio_too_large(count, num_upload_vertices) &&
760           instance_count == 1 &&                /* no instancing */
761           vao->CurrentElementBufferName == 0 && /* only user indices */
762           !ctx->GLThread._PrimitiveRestart &&   /* no primitive restart */
763           vao->UserPointerMask == vao->BufferEnabled && /* no VBOs */
764           !(vao->NonZeroDivisorMask & vao->BufferEnabled); /* no instanced attribs */
765 }
766 
767 static ALWAYS_INLINE void
draw_elements(GLuint drawid,GLenum mode,GLsizei count,GLenum type,const GLvoid * indices,GLsizei instance_count,GLint basevertex,GLuint baseinstance,bool index_bounds_valid,GLuint min_index,GLuint max_index,bool compiled_into_dlist,bool no_error)768 draw_elements(GLuint drawid, GLenum mode, GLsizei count, GLenum type,
769               const GLvoid *indices, GLsizei instance_count, GLint basevertex,
770               GLuint baseinstance, bool index_bounds_valid, GLuint min_index,
771               GLuint max_index, bool compiled_into_dlist, bool no_error)
772 {
773    GET_CURRENT_CONTEXT(ctx);
774 
775    /* The main benefit of no_error is that we can discard no-op draws
776     * immediately. These are plentiful in Viewperf2020/Catia1.
777     */
778    if (no_error && (count <= 0 || instance_count <= 0))
779       return;
780 
781    if (unlikely(compiled_into_dlist && ctx->GLThread.ListMode)) {
782       _mesa_glthread_finish_before(ctx, "DrawElements");
783 
784       /* Only use the ones that are compiled into display lists. */
785       if (basevertex) {
786          CALL_DrawElementsBaseVertex(ctx->Dispatch.Current,
787                                      (mode, count, type, indices, basevertex));
788       } else if (index_bounds_valid) {
789          CALL_DrawRangeElements(ctx->Dispatch.Current,
790                                 (mode, min_index, max_index, count, type, indices));
791       } else {
792          CALL_DrawElements(ctx->Dispatch.Current, (mode, count, type, indices));
793       }
794       return;
795    }
796 
797    if (unlikely(!no_error && index_bounds_valid && max_index < min_index)) {
798       _mesa_marshal_InternalSetError(GL_INVALID_VALUE);
799       return;
800    }
801 
802    struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
803    unsigned user_buffer_mask =
804       _mesa_is_desktop_gl_core(ctx) ? 0 : get_user_buffer_mask(ctx);
805    bool has_user_indices = vao->CurrentElementBufferName == 0 && indices;
806 
807    /* Fast path when nothing needs to be done.
808     *
809     * This is also an error path. Zero counts should still call the driver
810     * for possible GL errors.
811     */
812    if ((!user_buffer_mask && !has_user_indices) ||
813        (!no_error &&
814         /* zeros are discarded for no_error at the beginning */
815         (count <= 0 || instance_count <= 0 ||   /* GL_INVALID_VALUE / no-op */
816          !_mesa_is_index_type_valid(type) ||    /* GL_INVALID_VALUE */
817          ctx->Dispatch.Current == ctx->Dispatch.ContextLost || /* GL_INVALID_OPERATION */
818          ctx->GLThread.inside_begin_end ||      /* GL_INVALID_OPERATION */
819          ctx->GLThread.ListMode ||              /* GL_INVALID_OPERATION */
820          mode >= 32 || !((1u << mode) & ctx->SupportedPrimMask) /* GL_INVALID_ENUM */
821          ))) {
822       if (drawid == 0 && baseinstance == 0) {
823          if (instance_count == 1 && basevertex == 0) {
824             if ((count & 0xffff) == count && (uintptr_t)indices <= UINT16_MAX) {
825                /* Packed version of DrawElements: 16-bit count and 16-bit index offset,
826                 * reducing the call size by 8 bytes.
827                 * This is the most common case in Viewperf2020/Catia1.
828                 */
829                int cmd_size = sizeof(struct marshal_cmd_DrawElementsPacked);
830                struct marshal_cmd_DrawElementsPacked *cmd =
831                      _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawElementsPacked, cmd_size);
832 
833                cmd->mode = MIN2(mode, 0xff); /* clamped to 0xff (invalid enum) */
834                cmd->type = encode_index_type(type);
835                cmd->count = count;
836                cmd->indices = (uintptr_t)indices;
837             } else {
838                int cmd_size = sizeof(struct marshal_cmd_DrawElements);
839                struct marshal_cmd_DrawElements *cmd =
840                      _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawElements, cmd_size);
841 
842                cmd->mode = MIN2(mode, 0xff); /* clamped to 0xff (invalid enum) */
843                cmd->type = encode_index_type(type);
844                cmd->count = count;
845                cmd->indices = indices;
846             }
847          } else {
848             int cmd_size = sizeof(struct marshal_cmd_DrawElementsInstancedBaseVertex);
849             struct marshal_cmd_DrawElementsInstancedBaseVertex *cmd =
850                   _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawElementsInstancedBaseVertex, cmd_size);
851 
852             cmd->mode = MIN2(mode, 0xff); /* clamped to 0xff (invalid enum) */
853             cmd->type = encode_index_type(type);
854             cmd->count = count;
855             cmd->primcount = instance_count;
856             cmd->basevertex = basevertex;
857             cmd->indices = indices;
858          }
859       } else if (drawid == 0 && basevertex == 0) {
860          int cmd_size = sizeof(struct marshal_cmd_DrawElementsInstancedBaseInstance);
861          struct marshal_cmd_DrawElementsInstancedBaseInstance *cmd =
862                _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawElementsInstancedBaseInstance, cmd_size);
863 
864          cmd->mode = MIN2(mode, 0xff); /* clamped to 0xff (invalid enum) */
865          cmd->type = encode_index_type(type);
866          cmd->count = count;
867          cmd->primcount = instance_count;
868          cmd->baseinstance = baseinstance;
869          cmd->indices = indices;
870       } else {
871          int cmd_size = sizeof(struct marshal_cmd_DrawElementsInstancedBaseVertexBaseInstanceDrawID);
872          struct marshal_cmd_DrawElementsInstancedBaseVertexBaseInstanceDrawID *cmd =
873             _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawElementsInstancedBaseVertexBaseInstanceDrawID, cmd_size);
874 
875          cmd->mode = MIN2(mode, 0xff); /* clamped to 0xff (invalid enum) */
876          cmd->type = encode_index_type(type);
877          cmd->count = count;
878          cmd->instance_count = instance_count;
879          cmd->basevertex = basevertex;
880          cmd->baseinstance = baseinstance;
881          cmd->drawid = drawid;
882          cmd->indices = indices;
883       }
884       return;
885    }
886 
887    bool need_index_bounds = user_buffer_mask & ~vao->NonZeroDivisorMask;
888    unsigned index_size = get_index_size(type);
889 
890    if (need_index_bounds && !index_bounds_valid) {
891       /* Compute the index bounds. */
892       if (has_user_indices) {
893          min_index = ~0;
894          max_index = 0;
895          vbo_get_minmax_index_mapped(count, index_size,
896                                      ctx->GLThread._RestartIndex[index_size - 1],
897                                      ctx->GLThread._PrimitiveRestart, indices,
898                                      &min_index, &max_index);
899       } else {
900          /* Indices in a buffer. */
901          _mesa_glthread_finish_before(ctx, "DrawElements - need index bounds");
902          vbo_get_minmax_index(ctx, ctx->Array.VAO->IndexBufferObj,
903                               NULL, (intptr_t)indices, count, index_size,
904                               ctx->GLThread._PrimitiveRestart,
905                               ctx->GLThread._RestartIndex[index_size - 1],
906                               &min_index, &max_index);
907       }
908       index_bounds_valid = true;
909    }
910 
911    unsigned start_vertex = min_index + basevertex;
912    unsigned num_vertices = max_index + 1 - min_index;
913 
914    /* If the vertex range to upload is much greater than the vertex count (e.g.
915     * only 3 vertices with indices 0, 1, 999999), uploading the whole range
916     * would take too much time. If all buffers are user buffers, have glthread
917     * fetch all indices and vertices and convert the draw into glBegin/glEnd.
918     * For such pathological cases, it's the fastest way.
919     *
920     * The game Cogs benefits from this - its FPS increases from 0 to 197.
921     */
922    if (should_convert_to_begin_end(ctx, count, num_vertices, instance_count,
923                                    vao)) {
924       _mesa_glthread_UnrollDrawElements(ctx, mode, count, type, indices,
925                                         basevertex);
926       return;
927    }
928 
929    struct gl_buffer_object *buffers[VERT_ATTRIB_MAX];
930    int offsets[VERT_ATTRIB_MAX];
931 
932    if (user_buffer_mask) {
933       if (!upload_vertices(ctx, user_buffer_mask, start_vertex, num_vertices,
934                            baseinstance, instance_count, buffers, offsets))
935          return; /* the error is set by upload_vertices */
936    }
937 
938    /* Upload indices. */
939    struct gl_buffer_object *index_buffer = NULL;
940    if (has_user_indices) {
941       index_buffer = upload_indices(ctx, count, index_size, &indices);
942       if (!index_buffer)
943          return; /* the error is set by upload_indices */
944    }
945 
946    /* Draw asynchronously. */
947    unsigned num_buffers = util_bitcount(user_buffer_mask);
948    int buffers_size = num_buffers * sizeof(buffers[0]);
949    int offsets_size = num_buffers * sizeof(int);
950    char *variable_data;
951 
952    if (instance_count == 1 && basevertex == 0 && baseinstance == 0 &&
953        drawid == 0 && (count & 0xffff) == count &&
954        (uintptr_t)indices <= UINT32_MAX) {
955       int cmd_size = sizeof(struct marshal_cmd_DrawElementsUserBufPacked) +
956                      buffers_size + offsets_size;
957       struct marshal_cmd_DrawElementsUserBufPacked *cmd;
958 
959       cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawElementsUserBufPacked, cmd_size);
960       cmd->num_slots = align(cmd_size, 8) / 8;
961       cmd->mode = MIN2(mode, 0xff); /* clamped to 0xff (invalid enum) */
962       cmd->type = encode_index_type(type);
963       cmd->count = count; /* truncated */
964       cmd->indices = (uintptr_t)indices; /* truncated */
965       cmd->user_buffer_mask = user_buffer_mask;
966       cmd->index_buffer = index_buffer;
967       variable_data = (char*)(cmd + 1);
968    } else {
969       int cmd_size = sizeof(struct marshal_cmd_DrawElementsUserBuf) +
970                      buffers_size + offsets_size;
971       struct marshal_cmd_DrawElementsUserBuf *cmd;
972 
973       cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawElementsUserBuf, cmd_size);
974       cmd->num_slots = align(cmd_size, 8) / 8;
975       cmd->mode = MIN2(mode, 0xff); /* clamped to 0xff (invalid enum) */
976       cmd->type = encode_index_type(type);
977       cmd->count = count;
978       cmd->indices = indices;
979       cmd->instance_count = instance_count;
980       cmd->basevertex = basevertex;
981       cmd->baseinstance = baseinstance;
982       cmd->user_buffer_mask = user_buffer_mask;
983       cmd->index_buffer = index_buffer;
984       cmd->drawid = drawid;
985       variable_data = (char*)(cmd + 1);
986    }
987 
988    if (user_buffer_mask) {
989       memcpy(variable_data, buffers, buffers_size);
990       variable_data += buffers_size;
991       memcpy(variable_data, offsets, offsets_size);
992    }
993 }
994 
995 struct marshal_cmd_MultiDrawElementsUserBuf
996 {
997    struct marshal_cmd_base cmd_base;
998    bool has_base_vertex;
999    GLenum8 mode;
1000    GLindextype type;
1001    uint16_t num_slots;
1002    GLsizei draw_count;
1003    GLuint user_buffer_mask;
1004    struct gl_buffer_object *index_buffer;
1005 };
1006 
1007 uint32_t
_mesa_unmarshal_MultiDrawElementsUserBuf(struct gl_context * ctx,const struct marshal_cmd_MultiDrawElementsUserBuf * restrict cmd)1008 _mesa_unmarshal_MultiDrawElementsUserBuf(struct gl_context *ctx,
1009                                          const struct marshal_cmd_MultiDrawElementsUserBuf *restrict cmd)
1010 {
1011    const GLsizei draw_count = cmd->draw_count;
1012    const GLsizei real_draw_count = MAX2(draw_count, 0);
1013    const GLuint user_buffer_mask = cmd->user_buffer_mask;
1014    const bool has_base_vertex = cmd->has_base_vertex;
1015 
1016    const char *variable_data = (const char *)(cmd + 1);
1017    const GLsizei *count = (GLsizei *)variable_data;
1018    variable_data += sizeof(GLsizei) * real_draw_count;
1019    const GLsizei *basevertex = NULL;
1020    if (has_base_vertex) {
1021       basevertex = (GLsizei *)variable_data;
1022       variable_data += sizeof(GLsizei) * real_draw_count;
1023    }
1024    const int *offsets = NULL;
1025    if (user_buffer_mask) {
1026       offsets = (const int *)variable_data;
1027       variable_data += sizeof(int) * util_bitcount(user_buffer_mask);
1028    }
1029 
1030    /* Align for pointers. */
1031    if ((uintptr_t)variable_data % sizeof(uintptr_t))
1032       variable_data += 4;
1033 
1034    const GLvoid *const *indices = (const GLvoid *const *)variable_data;
1035    variable_data += sizeof(const GLvoid *const *) * real_draw_count;
1036 
1037    /* Bind uploaded buffers if needed. */
1038    if (user_buffer_mask) {
1039       struct gl_buffer_object **buffers = (struct gl_buffer_object **)variable_data;
1040 
1041       _mesa_InternalBindVertexBuffers(ctx, buffers, offsets, user_buffer_mask);
1042    }
1043 
1044    /* Draw. */
1045    const GLenum mode = cmd->mode;
1046    const GLenum type = _mesa_decode_index_type(cmd->type);
1047    struct gl_buffer_object *index_buffer = cmd->index_buffer;
1048 
1049    CALL_MultiDrawElementsUserBuf(ctx->Dispatch.Current,
1050                                  ((GLintptr)index_buffer, mode, count, type,
1051                                   indices, draw_count, basevertex));
1052    _mesa_reference_buffer_object(ctx, &index_buffer, NULL);
1053    return cmd->num_slots;
1054 }
1055 
1056 static void
multi_draw_elements_async(struct gl_context * ctx,GLenum mode,const GLsizei * count,GLenum type,const GLvoid * const * indices,GLsizei draw_count,const GLsizei * basevertex,struct gl_buffer_object * index_buffer,unsigned user_buffer_mask,struct gl_buffer_object ** buffers,const int * offsets)1057 multi_draw_elements_async(struct gl_context *ctx, GLenum mode,
1058                           const GLsizei *count, GLenum type,
1059                           const GLvoid *const *indices, GLsizei draw_count,
1060                           const GLsizei *basevertex,
1061                           struct gl_buffer_object *index_buffer,
1062                           unsigned user_buffer_mask,
1063                           struct gl_buffer_object **buffers,
1064                           const int *offsets)
1065 {
1066    int real_draw_count = MAX2(draw_count, 0);
1067    int count_size = sizeof(GLsizei) * real_draw_count;
1068    int indices_size = sizeof(indices[0]) * real_draw_count;
1069    int basevertex_size = basevertex ? sizeof(GLsizei) * real_draw_count : 0;
1070    unsigned num_buffers = util_bitcount(user_buffer_mask);
1071    int buffers_size = num_buffers * sizeof(buffers[0]);
1072    int offsets_size = num_buffers * sizeof(int);
1073    int cmd_size = sizeof(struct marshal_cmd_MultiDrawElementsUserBuf) +
1074                   count_size + indices_size + basevertex_size + buffers_size +
1075                   offsets_size;
1076    struct marshal_cmd_MultiDrawElementsUserBuf *cmd;
1077 
1078    /* Make sure cmd can fit the queue buffer */
1079    if (cmd_size <= MARSHAL_MAX_CMD_SIZE) {
1080       cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_MultiDrawElementsUserBuf, cmd_size);
1081       cmd->num_slots = align(cmd_size, 8) / 8;
1082       cmd->mode = MIN2(mode, 0xff); /* primitive types go from 0 to 14 */
1083       cmd->type = encode_index_type(type);
1084       cmd->draw_count = draw_count;
1085       cmd->user_buffer_mask = user_buffer_mask;
1086       cmd->index_buffer = index_buffer;
1087       cmd->has_base_vertex = basevertex != NULL;
1088 
1089       char *variable_data = (char*)(cmd + 1);
1090       memcpy(variable_data, count, count_size);
1091       variable_data += count_size;
1092       if (basevertex) {
1093          memcpy(variable_data, basevertex, basevertex_size);
1094          variable_data += basevertex_size;
1095       }
1096       if (user_buffer_mask) {
1097          memcpy(variable_data, offsets, offsets_size);
1098          variable_data += offsets_size;
1099       }
1100 
1101       /* Align for pointers. */
1102       if ((uintptr_t)variable_data % sizeof(uintptr_t))
1103          variable_data += 4;
1104 
1105       memcpy(variable_data, indices, indices_size);
1106       variable_data += indices_size;
1107 
1108       if (user_buffer_mask)
1109          memcpy(variable_data, buffers, buffers_size);
1110    } else {
1111       /* The call is too large, so sync and execute the unmarshal code here. */
1112       _mesa_glthread_finish_before(ctx, "DrawElements");
1113 
1114       /* Bind uploaded buffers if needed. */
1115       if (user_buffer_mask) {
1116          _mesa_InternalBindVertexBuffers(ctx, buffers, offsets,
1117                                          user_buffer_mask);
1118       }
1119 
1120       /* Draw. */
1121       CALL_MultiDrawElementsUserBuf(ctx->Dispatch.Current,
1122                                     ((GLintptr)index_buffer, mode, count,
1123                                      type, indices, draw_count, basevertex));
1124       _mesa_reference_buffer_object(ctx, &index_buffer, NULL);
1125    }
1126 }
1127 
1128 void GLAPIENTRY
_mesa_marshal_MultiDrawElementsBaseVertex(GLenum mode,const GLsizei * count,GLenum type,const GLvoid * const * indices,GLsizei draw_count,const GLsizei * basevertex)1129 _mesa_marshal_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
1130                                           GLenum type,
1131                                           const GLvoid *const *indices,
1132                                           GLsizei draw_count,
1133                                           const GLsizei *basevertex)
1134 {
1135    GET_CURRENT_CONTEXT(ctx);
1136 
1137    if (unlikely(ctx->GLThread.ListMode)) {
1138       _mesa_glthread_finish_before(ctx, "MultiDrawElements");
1139 
1140       if (basevertex) {
1141          CALL_MultiDrawElementsBaseVertex(ctx->Dispatch.Current,
1142                                           (mode, count, type, indices, draw_count,
1143                                            basevertex));
1144       } else {
1145          CALL_MultiDrawElements(ctx->Dispatch.Current,
1146                                 (mode, count, type, indices, draw_count));
1147       }
1148       return;
1149    }
1150 
1151    struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
1152    unsigned user_buffer_mask = 0;
1153    bool has_user_indices = false;
1154 
1155    /* Non-VBO vertex arrays are used only if this is true.
1156     * When nothing needs to be uploaded or the draw is no-op or generates
1157     * a GL error, we don't upload anything.
1158     */
1159    if (draw_count > 0 && _mesa_is_index_type_valid(type) &&
1160        ctx->Dispatch.Current != ctx->Dispatch.ContextLost &&
1161        !ctx->GLThread.inside_begin_end &&
1162        !(mode >= 32 || !((1u << mode) & ctx->SupportedPrimMask))) {
1163       user_buffer_mask = _mesa_is_desktop_gl_core(ctx) ? 0 : get_user_buffer_mask(ctx);
1164       has_user_indices = vao->CurrentElementBufferName == 0;
1165    }
1166 
1167    /* Fast path when we don't need to upload anything. */
1168    if (!user_buffer_mask && !has_user_indices) {
1169       multi_draw_elements_async(ctx, mode, count, type, indices,
1170                                 draw_count, basevertex, NULL, 0, NULL, NULL);
1171       return;
1172    }
1173 
1174    bool need_index_bounds = user_buffer_mask & ~vao->NonZeroDivisorMask;
1175    unsigned index_size = get_index_size(type);
1176    unsigned min_index = ~0;
1177    unsigned max_index = 0;
1178    unsigned total_count = 0;
1179    unsigned num_vertices = 0;
1180 
1181    /* This is always true if there is per-vertex data that needs to be
1182     * uploaded.
1183     */
1184    if (need_index_bounds) {
1185       bool synced = false;
1186 
1187       /* Compute the index bounds. */
1188       for (unsigned i = 0; i < draw_count; i++) {
1189          GLsizei vertex_count = count[i];
1190 
1191          if (vertex_count < 0) {
1192             /* Just call the driver to set the error. */
1193             multi_draw_elements_async(ctx, mode, count, type, indices, draw_count,
1194                                       basevertex, NULL, 0, NULL, NULL);
1195             return;
1196          }
1197          if (vertex_count == 0)
1198             continue;
1199 
1200          unsigned min = ~0, max = 0;
1201          if (has_user_indices) {
1202             vbo_get_minmax_index_mapped(vertex_count, index_size,
1203                                         ctx->GLThread._RestartIndex[index_size - 1],
1204                                         ctx->GLThread._PrimitiveRestart, indices[i],
1205                                         &min, &max);
1206          } else {
1207             if (!synced) {
1208                _mesa_glthread_finish_before(ctx, "MultiDrawElements - need index bounds");
1209                synced = true;
1210             }
1211             vbo_get_minmax_index(ctx, ctx->Array.VAO->IndexBufferObj,
1212                                  NULL, (intptr_t)indices[i], vertex_count,
1213                                  index_size, ctx->GLThread._PrimitiveRestart,
1214                                  ctx->GLThread._RestartIndex[index_size - 1],
1215                                  &min, &max);
1216          }
1217 
1218          if (basevertex) {
1219             min += basevertex[i];
1220             max += basevertex[i];
1221          }
1222          min_index = MIN2(min_index, min);
1223          max_index = MAX2(max_index, max);
1224          total_count += vertex_count;
1225       }
1226 
1227       num_vertices = max_index + 1 - min_index;
1228 
1229       if (total_count == 0 || num_vertices == 0) {
1230          /* Nothing to do, but call the driver to set possible GL errors. */
1231          multi_draw_elements_async(ctx, mode, count, type, indices, draw_count,
1232                                    basevertex, NULL, 0, NULL, NULL);
1233          return;
1234       }
1235    } else if (has_user_indices) {
1236       /* Only compute total_count for the upload of indices. */
1237       for (unsigned i = 0; i < draw_count; i++) {
1238          GLsizei vertex_count = count[i];
1239 
1240          if (vertex_count < 0) {
1241             /* Just call the driver to set the error. */
1242             multi_draw_elements_async(ctx, mode, count, type, indices, draw_count,
1243                                       basevertex, NULL, 0, NULL, NULL);
1244             return;
1245          }
1246          if (vertex_count == 0)
1247             continue;
1248 
1249          total_count += vertex_count;
1250       }
1251 
1252       if (total_count == 0) {
1253          /* Nothing to do, but call the driver to set possible GL errors. */
1254          multi_draw_elements_async(ctx, mode, count, type, indices, draw_count,
1255                                    basevertex, NULL, 0, NULL, NULL);
1256          return;
1257       }
1258    }
1259 
1260    /* Upload vertices. */
1261    struct gl_buffer_object *buffers[VERT_ATTRIB_MAX];
1262    int offsets[VERT_ATTRIB_MAX];
1263 
1264    if (user_buffer_mask) {
1265       if (!upload_vertices(ctx, user_buffer_mask, min_index, num_vertices,
1266                            0, 1, buffers, offsets))
1267          return; /* the error is set by upload_vertices */
1268    }
1269 
1270    /* Upload indices. */
1271    struct gl_buffer_object *index_buffer = NULL;
1272    if (has_user_indices) {
1273       const GLvoid **out_indices = alloca(sizeof(indices[0]) * draw_count);
1274 
1275       index_buffer = upload_multi_indices(ctx, total_count, index_size,
1276                                           draw_count, count, indices,
1277                                           out_indices);
1278       if (!index_buffer)
1279          return; /* the error is set by upload_multi_indices */
1280 
1281       indices = out_indices;
1282    }
1283 
1284    /* Draw asynchronously. */
1285    multi_draw_elements_async(ctx, mode, count, type, indices, draw_count,
1286                              basevertex, index_buffer, user_buffer_mask,
1287                              buffers, offsets);
1288 }
1289 
1290 void GLAPIENTRY
_mesa_marshal_MultiModeDrawArraysIBM(const GLenum * mode,const GLint * first,const GLsizei * count,GLsizei primcount,GLint modestride)1291 _mesa_marshal_MultiModeDrawArraysIBM(const GLenum *mode, const GLint *first,
1292                                      const GLsizei *count, GLsizei primcount,
1293                                      GLint modestride)
1294 {
1295    for (int i = 0 ; i < primcount; i++) {
1296       if (count[i] > 0) {
1297          GLenum m = *((GLenum *)((GLubyte *)mode + i * modestride));
1298          _mesa_marshal_DrawArrays(m, first[i], count[i]);
1299       }
1300    }
1301 }
1302 
1303 void GLAPIENTRY
_mesa_marshal_MultiModeDrawElementsIBM(const GLenum * mode,const GLsizei * count,GLenum type,const GLvoid * const * indices,GLsizei primcount,GLint modestride)1304 _mesa_marshal_MultiModeDrawElementsIBM(const GLenum *mode,
1305                                        const GLsizei *count, GLenum type,
1306                                        const GLvoid * const *indices,
1307                                        GLsizei primcount, GLint modestride)
1308 {
1309    for (int i = 0 ; i < primcount; i++) {
1310       if (count[i] > 0) {
1311          GLenum m = *((GLenum *)((GLubyte *)mode + i * modestride));
1312          _mesa_marshal_DrawElements(m, count[i], type, indices[i]);
1313       }
1314    }
1315 }
1316 
1317 static const void *
map_draw_indirect_params(struct gl_context * ctx,GLintptr offset,unsigned count,unsigned stride)1318 map_draw_indirect_params(struct gl_context *ctx, GLintptr offset,
1319                          unsigned count, unsigned stride)
1320 {
1321    struct gl_buffer_object *obj = ctx->DrawIndirectBuffer;
1322 
1323    if (!obj)
1324       return (void*)offset;
1325 
1326    return _mesa_bufferobj_map_range(ctx, offset,
1327                                     MIN2((size_t)count * stride, obj->Size),
1328                                     GL_MAP_READ_BIT, obj, MAP_INTERNAL);
1329 }
1330 
1331 static void
unmap_draw_indirect_params(struct gl_context * ctx)1332 unmap_draw_indirect_params(struct gl_context *ctx)
1333 {
1334    if (ctx->DrawIndirectBuffer)
1335       _mesa_bufferobj_unmap(ctx, ctx->DrawIndirectBuffer, MAP_INTERNAL);
1336 }
1337 
1338 static unsigned
read_draw_indirect_count(struct gl_context * ctx,GLintptr offset)1339 read_draw_indirect_count(struct gl_context *ctx, GLintptr offset)
1340 {
1341    unsigned result = 0;
1342 
1343    if (ctx->ParameterBuffer) {
1344       _mesa_bufferobj_get_subdata(ctx, offset, sizeof(result), &result,
1345                                   ctx->ParameterBuffer);
1346    }
1347    return result;
1348 }
1349 
1350 static void
lower_draw_arrays_indirect(struct gl_context * ctx,GLenum mode,GLintptr indirect,GLsizei stride,unsigned draw_count)1351 lower_draw_arrays_indirect(struct gl_context *ctx, GLenum mode,
1352                            GLintptr indirect, GLsizei stride,
1353                            unsigned draw_count)
1354 {
1355    /* If <stride> is zero, the elements are tightly packed. */
1356    if (stride == 0)
1357       stride = 4 * sizeof(GLuint);      /* sizeof(DrawArraysIndirectCommand) */
1358 
1359    const uint32_t *params =
1360       map_draw_indirect_params(ctx, indirect, draw_count, stride);
1361 
1362    for (unsigned i = 0; i < draw_count; i++) {
1363       draw_arrays(i, mode,
1364                   params[i * stride / 4 + 2],
1365                   params[i * stride / 4 + 0],
1366                   params[i * stride / 4 + 1],
1367                   params[i * stride / 4 + 3], false, false);
1368    }
1369 
1370    unmap_draw_indirect_params(ctx);
1371 }
1372 
1373 static void
lower_draw_elements_indirect(struct gl_context * ctx,GLenum mode,GLenum type,GLintptr indirect,GLsizei stride,unsigned draw_count)1374 lower_draw_elements_indirect(struct gl_context *ctx, GLenum mode, GLenum type,
1375                              GLintptr indirect, GLsizei stride,
1376                              unsigned draw_count)
1377 {
1378    /* If <stride> is zero, the elements are tightly packed. */
1379    if (stride == 0)
1380       stride = 5 * sizeof(GLuint);      /* sizeof(DrawArraysIndirectCommand) */
1381 
1382    const uint32_t *params =
1383       map_draw_indirect_params(ctx, indirect, draw_count, stride);
1384 
1385    for (unsigned i = 0; i < draw_count; i++) {
1386       draw_elements(i, mode,
1387                     params[i * stride / 4 + 0],
1388                     type,
1389                     (GLvoid*)((uintptr_t)params[i * stride / 4 + 2] *
1390                               get_index_size(type)),
1391                     params[i * stride / 4 + 1],
1392                     params[i * stride / 4 + 3],
1393                     params[i * stride / 4 + 4],
1394                     false, 0, 0, false, false);
1395    }
1396    unmap_draw_indirect_params(ctx);
1397 }
1398 
1399 static inline bool
draw_indirect_async_allowed(struct gl_context * ctx,unsigned user_buffer_mask)1400 draw_indirect_async_allowed(struct gl_context *ctx, unsigned user_buffer_mask)
1401 {
1402    return ctx->API != API_OPENGL_COMPAT ||
1403           /* This will just generate GL_INVALID_OPERATION, as it should. */
1404           ctx->GLThread.inside_begin_end ||
1405           ctx->GLThread.ListMode ||
1406           ctx->Dispatch.Current == ctx->Dispatch.ContextLost ||
1407           /* If the DrawIndirect buffer is bound, it behaves like profile != compat
1408            * if there are no user VBOs. */
1409           (ctx->GLThread.CurrentDrawIndirectBufferName && !user_buffer_mask);
1410 }
1411 
1412 uint32_t
_mesa_unmarshal_DrawArraysIndirect(struct gl_context * ctx,const struct marshal_cmd_DrawArraysIndirect * cmd)1413 _mesa_unmarshal_DrawArraysIndirect(struct gl_context *ctx,
1414                                    const struct marshal_cmd_DrawArraysIndirect *cmd)
1415 {
1416    GLenum mode = cmd->mode;
1417    const GLvoid * indirect = cmd->indirect;
1418 
1419    CALL_DrawArraysIndirect(ctx->Dispatch.Current, (mode, indirect));
1420 
1421    return align(sizeof(struct marshal_cmd_DrawArraysIndirect), 8) / 8;
1422 }
1423 
1424 void GLAPIENTRY
_mesa_marshal_DrawArraysIndirect(GLenum mode,const GLvoid * indirect)1425 _mesa_marshal_DrawArraysIndirect(GLenum mode, const GLvoid *indirect)
1426 {
1427    GET_CURRENT_CONTEXT(ctx);
1428    struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
1429    unsigned user_buffer_mask =
1430       _mesa_is_gles31(ctx) ? 0 : vao->UserPointerMask & vao->BufferEnabled;
1431 
1432    if (draw_indirect_async_allowed(ctx, user_buffer_mask)) {
1433       int cmd_size = sizeof(struct marshal_cmd_DrawArraysIndirect);
1434       struct marshal_cmd_DrawArraysIndirect *cmd;
1435 
1436       cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawArraysIndirect, cmd_size);
1437       cmd->mode = MIN2(mode, 0xff); /* clamped to 0xff (invalid enum) */
1438       cmd->indirect = indirect;
1439       return;
1440    }
1441 
1442    _mesa_glthread_finish_before(ctx, "DrawArraysIndirect");
1443    lower_draw_arrays_indirect(ctx, mode, (GLintptr)indirect, 0, 1);
1444 }
1445 
1446 uint32_t
_mesa_unmarshal_DrawElementsIndirect(struct gl_context * ctx,const struct marshal_cmd_DrawElementsIndirect * cmd)1447 _mesa_unmarshal_DrawElementsIndirect(struct gl_context *ctx,
1448                                      const struct marshal_cmd_DrawElementsIndirect *cmd)
1449 {
1450    GLenum mode = cmd->mode;
1451    const GLenum type = _mesa_decode_index_type(cmd->type);
1452    const GLvoid * indirect = cmd->indirect;
1453 
1454    CALL_DrawElementsIndirect(ctx->Dispatch.Current, (mode, type, indirect));
1455    return align(sizeof(struct marshal_cmd_DrawElementsIndirect), 8) / 8;
1456 }
1457 
1458 void GLAPIENTRY
_mesa_marshal_DrawElementsIndirect(GLenum mode,GLenum type,const GLvoid * indirect)1459 _mesa_marshal_DrawElementsIndirect(GLenum mode, GLenum type, const GLvoid *indirect)
1460 {
1461    GET_CURRENT_CONTEXT(ctx);
1462    struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
1463    unsigned user_buffer_mask =
1464       _mesa_is_gles31(ctx) ? 0 : vao->UserPointerMask & vao->BufferEnabled;
1465 
1466    if (draw_indirect_async_allowed(ctx, user_buffer_mask) ||
1467        !_mesa_is_index_type_valid(type)) {
1468       int cmd_size = sizeof(struct marshal_cmd_DrawElementsIndirect);
1469       struct marshal_cmd_DrawElementsIndirect *cmd;
1470 
1471       cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawElementsIndirect, cmd_size);
1472       cmd->mode = MIN2(mode, 0xff); /* clamped to 0xff (invalid enum) */
1473       cmd->type = encode_index_type(type);
1474       cmd->indirect = indirect;
1475       return;
1476    }
1477 
1478    _mesa_glthread_finish_before(ctx, "DrawElementsIndirect");
1479    lower_draw_elements_indirect(ctx, mode, type, (GLintptr)indirect, 0, 1);
1480 }
1481 
1482 uint32_t
_mesa_unmarshal_MultiDrawArraysIndirect(struct gl_context * ctx,const struct marshal_cmd_MultiDrawArraysIndirect * cmd)1483 _mesa_unmarshal_MultiDrawArraysIndirect(struct gl_context *ctx,
1484                                         const struct marshal_cmd_MultiDrawArraysIndirect *cmd)
1485 {
1486    GLenum mode = cmd->mode;
1487    const GLvoid * indirect = cmd->indirect;
1488    GLsizei primcount = cmd->primcount;
1489    GLsizei stride = cmd->stride;
1490 
1491    CALL_MultiDrawArraysIndirect(ctx->Dispatch.Current,
1492                                 (mode, indirect, primcount, stride));
1493    return align(sizeof(struct marshal_cmd_MultiDrawArraysIndirect), 8) / 8;
1494 }
1495 
1496 void GLAPIENTRY
_mesa_marshal_MultiDrawArraysIndirect(GLenum mode,const GLvoid * indirect,GLsizei primcount,GLsizei stride)1497 _mesa_marshal_MultiDrawArraysIndirect(GLenum mode, const GLvoid *indirect,
1498                                       GLsizei primcount, GLsizei stride)
1499 {
1500    GET_CURRENT_CONTEXT(ctx);
1501    struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
1502    unsigned user_buffer_mask =
1503       _mesa_is_gles31(ctx) ? 0 : vao->UserPointerMask & vao->BufferEnabled;
1504 
1505    if (draw_indirect_async_allowed(ctx, user_buffer_mask) ||
1506        primcount <= 0) {
1507       int cmd_size = sizeof(struct marshal_cmd_MultiDrawArraysIndirect);
1508       struct marshal_cmd_MultiDrawArraysIndirect *cmd;
1509 
1510       cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_MultiDrawArraysIndirect,
1511                                             cmd_size);
1512       cmd->mode = MIN2(mode, 0xff); /* clamped to 0xff (invalid enum) */
1513       cmd->indirect = indirect;
1514       cmd->primcount = primcount;
1515       cmd->stride = stride;
1516       return;
1517    }
1518 
1519    /* Lower the draw to direct due to non-VBO vertex arrays. */
1520    _mesa_glthread_finish_before(ctx, "MultiDrawArraysIndirect");
1521    lower_draw_arrays_indirect(ctx, mode, (GLintptr)indirect, stride, primcount);
1522 }
1523 
1524 uint32_t
_mesa_unmarshal_MultiDrawElementsIndirect(struct gl_context * ctx,const struct marshal_cmd_MultiDrawElementsIndirect * cmd)1525 _mesa_unmarshal_MultiDrawElementsIndirect(struct gl_context *ctx,
1526                                           const struct marshal_cmd_MultiDrawElementsIndirect *cmd)
1527 {
1528    GLenum mode = cmd->mode;
1529    const GLenum type = _mesa_decode_index_type(cmd->type);
1530    const GLvoid * indirect = cmd->indirect;
1531    GLsizei primcount = cmd->primcount;
1532    GLsizei stride = cmd->stride;
1533 
1534    CALL_MultiDrawElementsIndirect(ctx->Dispatch.Current,
1535                                   (mode, type, indirect, primcount, stride));
1536    return align(sizeof(struct marshal_cmd_MultiDrawElementsIndirect), 8) / 8;
1537 }
1538 
1539 void GLAPIENTRY
_mesa_marshal_MultiDrawElementsIndirect(GLenum mode,GLenum type,const GLvoid * indirect,GLsizei primcount,GLsizei stride)1540 _mesa_marshal_MultiDrawElementsIndirect(GLenum mode, GLenum type,
1541                                         const GLvoid *indirect,
1542                                         GLsizei primcount, GLsizei stride)
1543 {
1544    GET_CURRENT_CONTEXT(ctx);
1545    struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
1546    unsigned user_buffer_mask =
1547       _mesa_is_gles31(ctx) ? 0 : vao->UserPointerMask & vao->BufferEnabled;
1548 
1549    if (draw_indirect_async_allowed(ctx, user_buffer_mask) ||
1550        primcount <= 0 ||
1551        !_mesa_is_index_type_valid(type)) {
1552       int cmd_size = sizeof(struct marshal_cmd_MultiDrawElementsIndirect);
1553       struct marshal_cmd_MultiDrawElementsIndirect *cmd;
1554 
1555       cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_MultiDrawElementsIndirect,
1556                                             cmd_size);
1557       cmd->mode = MIN2(mode, 0xff); /* clamped to 0xff (invalid enum) */
1558       cmd->type = encode_index_type(type);
1559       cmd->indirect = indirect;
1560       cmd->primcount = primcount;
1561       cmd->stride = stride;
1562       return;
1563    }
1564 
1565    /* Lower the draw to direct due to non-VBO vertex arrays. */
1566    _mesa_glthread_finish_before(ctx, "MultiDrawElementsIndirect");
1567    lower_draw_elements_indirect(ctx, mode, type, (GLintptr)indirect, stride,
1568                                 primcount);
1569 }
1570 
1571 uint32_t
_mesa_unmarshal_MultiDrawArraysIndirectCountARB(struct gl_context * ctx,const struct marshal_cmd_MultiDrawArraysIndirectCountARB * cmd)1572 _mesa_unmarshal_MultiDrawArraysIndirectCountARB(struct gl_context *ctx,
1573                                                 const struct marshal_cmd_MultiDrawArraysIndirectCountARB *cmd)
1574 {
1575    GLenum mode = cmd->mode;
1576    GLintptr indirect = cmd->indirect;
1577    GLintptr drawcount = cmd->drawcount;
1578    GLsizei maxdrawcount = cmd->maxdrawcount;
1579    GLsizei stride = cmd->stride;
1580 
1581    CALL_MultiDrawArraysIndirectCountARB(ctx->Dispatch.Current,
1582                                         (mode, indirect, drawcount,
1583                                          maxdrawcount, stride));
1584    return align(sizeof(struct marshal_cmd_MultiDrawArraysIndirectCountARB), 8) / 8;
1585 }
1586 
1587 void GLAPIENTRY
_mesa_marshal_MultiDrawArraysIndirectCountARB(GLenum mode,GLintptr indirect,GLintptr drawcount,GLsizei maxdrawcount,GLsizei stride)1588 _mesa_marshal_MultiDrawArraysIndirectCountARB(GLenum mode, GLintptr indirect,
1589                                               GLintptr drawcount,
1590                                               GLsizei maxdrawcount,
1591                                               GLsizei stride)
1592 {
1593    GET_CURRENT_CONTEXT(ctx);
1594    struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
1595    unsigned user_buffer_mask =
1596       _mesa_is_gles31(ctx) ? 0 : vao->UserPointerMask & vao->BufferEnabled;
1597 
1598    if (draw_indirect_async_allowed(ctx, user_buffer_mask) ||
1599        /* This will just generate GL_INVALID_OPERATION because Draw*IndirectCount
1600         * functions forbid a user indirect buffer in the Compat profile. */
1601        !ctx->GLThread.CurrentDrawIndirectBufferName) {
1602       int cmd_size =
1603          sizeof(struct marshal_cmd_MultiDrawArraysIndirectCountARB);
1604       struct marshal_cmd_MultiDrawArraysIndirectCountARB *cmd =
1605          _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_MultiDrawArraysIndirectCountARB,
1606                                          cmd_size);
1607 
1608       cmd->mode = MIN2(mode, 0xff); /* clamped to 0xff (invalid enum) */
1609       cmd->indirect = indirect;
1610       cmd->drawcount = drawcount;
1611       cmd->maxdrawcount = maxdrawcount;
1612       cmd->stride = stride;
1613       return;
1614    }
1615 
1616    /* Lower the draw to direct due to non-VBO vertex arrays. */
1617    _mesa_glthread_finish_before(ctx, "MultiDrawArraysIndirectCountARB");
1618    lower_draw_arrays_indirect(ctx, mode, indirect, stride,
1619                               read_draw_indirect_count(ctx, drawcount));
1620 }
1621 
1622 uint32_t
_mesa_unmarshal_MultiDrawElementsIndirectCountARB(struct gl_context * ctx,const struct marshal_cmd_MultiDrawElementsIndirectCountARB * cmd)1623 _mesa_unmarshal_MultiDrawElementsIndirectCountARB(struct gl_context *ctx,
1624                                                   const struct marshal_cmd_MultiDrawElementsIndirectCountARB *cmd)
1625 {
1626    GLenum mode = cmd->mode;
1627    const GLenum type = _mesa_decode_index_type(cmd->type);
1628    GLintptr indirect = cmd->indirect;
1629    GLintptr drawcount = cmd->drawcount;
1630    GLsizei maxdrawcount = cmd->maxdrawcount;
1631    GLsizei stride = cmd->stride;
1632 
1633    CALL_MultiDrawElementsIndirectCountARB(ctx->Dispatch.Current, (mode, type, indirect, drawcount, maxdrawcount, stride));
1634 
1635    return align(sizeof(struct marshal_cmd_MultiDrawElementsIndirectCountARB), 8) / 8;
1636 }
1637 
1638 void GLAPIENTRY
_mesa_marshal_MultiDrawElementsIndirectCountARB(GLenum mode,GLenum type,GLintptr indirect,GLintptr drawcount,GLsizei maxdrawcount,GLsizei stride)1639 _mesa_marshal_MultiDrawElementsIndirectCountARB(GLenum mode, GLenum type,
1640                                                 GLintptr indirect,
1641                                                 GLintptr drawcount,
1642                                                 GLsizei maxdrawcount,
1643                                                 GLsizei stride)
1644 {
1645    GET_CURRENT_CONTEXT(ctx);
1646    struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
1647    unsigned user_buffer_mask =
1648       _mesa_is_gles31(ctx) ? 0 : vao->UserPointerMask & vao->BufferEnabled;
1649 
1650    if (draw_indirect_async_allowed(ctx, user_buffer_mask) ||
1651        /* This will just generate GL_INVALID_OPERATION because Draw*IndirectCount
1652         * functions forbid a user indirect buffer in the Compat profile. */
1653        !ctx->GLThread.CurrentDrawIndirectBufferName ||
1654        !_mesa_is_index_type_valid(type)) {
1655       int cmd_size = sizeof(struct marshal_cmd_MultiDrawElementsIndirectCountARB);
1656       struct marshal_cmd_MultiDrawElementsIndirectCountARB *cmd =
1657          _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_MultiDrawElementsIndirectCountARB, cmd_size);
1658 
1659       cmd->mode = MIN2(mode, 0xff); /* clamped to 0xff (invalid enum) */
1660       cmd->type = encode_index_type(type);
1661       cmd->indirect = indirect;
1662       cmd->drawcount = drawcount;
1663       cmd->maxdrawcount = maxdrawcount;
1664       cmd->stride = stride;
1665       return;
1666    }
1667 
1668    /* Lower the draw to direct due to non-VBO vertex arrays. */
1669    _mesa_glthread_finish_before(ctx, "MultiDrawElementsIndirectCountARB");
1670    lower_draw_elements_indirect(ctx, mode, type, indirect, stride,
1671                                 read_draw_indirect_count(ctx, drawcount));
1672 }
1673 
1674 void GLAPIENTRY
_mesa_marshal_DrawArrays(GLenum mode,GLint first,GLsizei count)1675 _mesa_marshal_DrawArrays(GLenum mode, GLint first, GLsizei count)
1676 {
1677    draw_arrays(0, mode, first, count, 1, 0, true, false);
1678 }
1679 
1680 void GLAPIENTRY
_mesa_marshal_DrawArrays_no_error(GLenum mode,GLint first,GLsizei count)1681 _mesa_marshal_DrawArrays_no_error(GLenum mode, GLint first, GLsizei count)
1682 {
1683    draw_arrays(0, mode, first, count, 1, 0, true, true);
1684 }
1685 
1686 void GLAPIENTRY
_mesa_marshal_DrawArraysInstanced(GLenum mode,GLint first,GLsizei count,GLsizei instance_count)1687 _mesa_marshal_DrawArraysInstanced(GLenum mode, GLint first, GLsizei count,
1688                                   GLsizei instance_count)
1689 {
1690    draw_arrays(0, mode, first, count, instance_count, 0, false, false);
1691 }
1692 
1693 void GLAPIENTRY
_mesa_marshal_DrawArraysInstanced_no_error(GLenum mode,GLint first,GLsizei count,GLsizei instance_count)1694 _mesa_marshal_DrawArraysInstanced_no_error(GLenum mode, GLint first, GLsizei count,
1695                                            GLsizei instance_count)
1696 {
1697    draw_arrays(0, mode, first, count, instance_count, 0, false, true);
1698 }
1699 
1700 void GLAPIENTRY
_mesa_marshal_DrawArraysInstancedBaseInstance(GLenum mode,GLint first,GLsizei count,GLsizei instance_count,GLuint baseinstance)1701 _mesa_marshal_DrawArraysInstancedBaseInstance(GLenum mode, GLint first,
1702                                               GLsizei count, GLsizei instance_count,
1703                                               GLuint baseinstance)
1704 {
1705    draw_arrays(0, mode, first, count, instance_count, baseinstance, false, false);
1706 }
1707 
1708 void GLAPIENTRY
_mesa_marshal_DrawArraysInstancedBaseInstance_no_error(GLenum mode,GLint first,GLsizei count,GLsizei instance_count,GLuint baseinstance)1709 _mesa_marshal_DrawArraysInstancedBaseInstance_no_error(GLenum mode, GLint first,
1710                                                        GLsizei count, GLsizei instance_count,
1711                                                        GLuint baseinstance)
1712 {
1713    draw_arrays(0, mode, first, count, instance_count, baseinstance, false, true);
1714 }
1715 
1716 void GLAPIENTRY
_mesa_marshal_DrawElements(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices)1717 _mesa_marshal_DrawElements(GLenum mode, GLsizei count, GLenum type,
1718                            const GLvoid *indices)
1719 {
1720    draw_elements(0, mode, count, type, indices, 1, 0,
1721                  0, false, 0, 0, true, false);
1722 }
1723 
1724 void GLAPIENTRY
_mesa_marshal_DrawElements_no_error(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices)1725 _mesa_marshal_DrawElements_no_error(GLenum mode, GLsizei count, GLenum type,
1726                                     const GLvoid *indices)
1727 {
1728    draw_elements(0, mode, count, type, indices, 1, 0,
1729                  0, false, 0, 0, true, true);
1730 }
1731 
1732 void GLAPIENTRY
_mesa_marshal_DrawRangeElements(GLenum mode,GLuint start,GLuint end,GLsizei count,GLenum type,const GLvoid * indices)1733 _mesa_marshal_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1734                                 GLsizei count, GLenum type,
1735                                 const GLvoid *indices)
1736 {
1737    draw_elements(0, mode, count, type, indices, 1, 0,
1738                  0, true, start, end, true, false);
1739 }
1740 
1741 void GLAPIENTRY
_mesa_marshal_DrawRangeElements_no_error(GLenum mode,GLuint start,GLuint end,GLsizei count,GLenum type,const GLvoid * indices)1742 _mesa_marshal_DrawRangeElements_no_error(GLenum mode, GLuint start, GLuint end,
1743                                          GLsizei count, GLenum type,
1744                                          const GLvoid *indices)
1745 {
1746    draw_elements(0, mode, count, type, indices, 1, 0,
1747                  0, true, start, end, true, true);
1748 }
1749 
1750 void GLAPIENTRY
_mesa_marshal_DrawElementsInstanced(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices,GLsizei instance_count)1751 _mesa_marshal_DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
1752                                     const GLvoid *indices, GLsizei instance_count)
1753 {
1754    draw_elements(0, mode, count, type, indices, instance_count, 0,
1755                  0, false, 0, 0, false, false);
1756 }
1757 
1758 void GLAPIENTRY
_mesa_marshal_DrawElementsInstanced_no_error(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices,GLsizei instance_count)1759 _mesa_marshal_DrawElementsInstanced_no_error(GLenum mode, GLsizei count,
1760                                              GLenum type, const GLvoid *indices,
1761                                              GLsizei instance_count)
1762 {
1763    draw_elements(0, mode, count, type, indices, instance_count, 0,
1764                  0, false, 0, 0, false, true);
1765 }
1766 
1767 void GLAPIENTRY
_mesa_marshal_DrawElementsBaseVertex(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices,GLint basevertex)1768 _mesa_marshal_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
1769                                      const GLvoid *indices, GLint basevertex)
1770 {
1771    draw_elements(0, mode, count, type, indices, 1, basevertex,
1772                  0, false, 0, 0, true, false);
1773 }
1774 
1775 void GLAPIENTRY
_mesa_marshal_DrawElementsBaseVertex_no_error(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices,GLint basevertex)1776 _mesa_marshal_DrawElementsBaseVertex_no_error(GLenum mode, GLsizei count,
1777                                               GLenum type, const GLvoid *indices,
1778                                               GLint basevertex)
1779 {
1780    draw_elements(0, mode, count, type, indices, 1, basevertex,
1781                  0, false, 0, 0, true, true);
1782 }
1783 
1784 void GLAPIENTRY
_mesa_marshal_DrawRangeElementsBaseVertex(GLenum mode,GLuint start,GLuint end,GLsizei count,GLenum type,const GLvoid * indices,GLint basevertex)1785 _mesa_marshal_DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end,
1786                                           GLsizei count, GLenum type,
1787                                           const GLvoid *indices, GLint basevertex)
1788 {
1789    draw_elements(0, mode, count, type, indices, 1, basevertex,
1790                  0, true, start, end, true, false);
1791 }
1792 
1793 void GLAPIENTRY
_mesa_marshal_DrawRangeElementsBaseVertex_no_error(GLenum mode,GLuint start,GLuint end,GLsizei count,GLenum type,const GLvoid * indices,GLint basevertex)1794 _mesa_marshal_DrawRangeElementsBaseVertex_no_error(GLenum mode, GLuint start,
1795                                                    GLuint end, GLsizei count, GLenum type,
1796                                                    const GLvoid *indices, GLint basevertex)
1797 {
1798    draw_elements(0, mode, count, type, indices, 1, basevertex,
1799                  0, true, start, end, true, true);
1800 }
1801 
1802 void GLAPIENTRY
_mesa_marshal_DrawElementsInstancedBaseVertex(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices,GLsizei instance_count,GLint basevertex)1803 _mesa_marshal_DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count,
1804                                               GLenum type, const GLvoid *indices,
1805                                               GLsizei instance_count, GLint basevertex)
1806 {
1807    draw_elements(0, mode, count, type, indices, instance_count, basevertex,
1808                  0, false, 0, 0, false, false);
1809 }
1810 
1811 void GLAPIENTRY
_mesa_marshal_DrawElementsInstancedBaseVertex_no_error(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices,GLsizei instance_count,GLint basevertex)1812 _mesa_marshal_DrawElementsInstancedBaseVertex_no_error(GLenum mode, GLsizei count,
1813                                                        GLenum type, const GLvoid *indices,
1814                                                        GLsizei instance_count, GLint basevertex)
1815 {
1816    draw_elements(0, mode, count, type, indices, instance_count, basevertex,
1817                  0, false, 0, 0, false, true);
1818 }
1819 
1820 void GLAPIENTRY
_mesa_marshal_DrawElementsInstancedBaseInstance(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices,GLsizei instance_count,GLuint baseinstance)1821 _mesa_marshal_DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count,
1822                                                 GLenum type, const GLvoid *indices,
1823                                                 GLsizei instance_count, GLuint baseinstance)
1824 {
1825    draw_elements(0, mode, count, type, indices, instance_count, 0,
1826                  baseinstance, false, 0, 0, false, false);
1827 }
1828 
1829 void GLAPIENTRY
_mesa_marshal_DrawElementsInstancedBaseInstance_no_error(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices,GLsizei instance_count,GLuint baseinstance)1830 _mesa_marshal_DrawElementsInstancedBaseInstance_no_error(GLenum mode, GLsizei count,
1831                                                          GLenum type, const GLvoid *indices,
1832                                                          GLsizei instance_count, GLuint baseinstance)
1833 {
1834    draw_elements(0, mode, count, type, indices, instance_count, 0,
1835                  baseinstance, false, 0, 0, false, true);
1836 }
1837 
1838 void GLAPIENTRY
_mesa_marshal_DrawElementsInstancedBaseVertexBaseInstance(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices,GLsizei instance_count,GLint basevertex,GLuint baseinstance)1839 _mesa_marshal_DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count,
1840                                                           GLenum type, const GLvoid *indices,
1841                                                           GLsizei instance_count, GLint basevertex,
1842                                                           GLuint baseinstance)
1843 {
1844    draw_elements(0, mode, count, type, indices, instance_count, basevertex,
1845                  baseinstance, false, 0, 0, false, false);
1846 }
1847 
1848 void GLAPIENTRY
_mesa_marshal_DrawElementsInstancedBaseVertexBaseInstance_no_error(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices,GLsizei instance_count,GLint basevertex,GLuint baseinstance)1849 _mesa_marshal_DrawElementsInstancedBaseVertexBaseInstance_no_error(GLenum mode, GLsizei count,
1850                                                                    GLenum type, const GLvoid *indices,
1851                                                                    GLsizei instance_count,
1852                                                                    GLint basevertex, GLuint baseinstance)
1853 {
1854    draw_elements(0, mode, count, type, indices, instance_count, basevertex,
1855                  baseinstance, false, 0, 0, false, true);
1856 }
1857 
1858 void GLAPIENTRY
_mesa_marshal_MultiDrawElements(GLenum mode,const GLsizei * count,GLenum type,const GLvoid * const * indices,GLsizei draw_count)1859 _mesa_marshal_MultiDrawElements(GLenum mode, const GLsizei *count,
1860                                 GLenum type, const GLvoid *const *indices,
1861                                 GLsizei draw_count)
1862 {
1863    _mesa_marshal_MultiDrawElementsBaseVertex(mode, count, type, indices,
1864                                              draw_count, NULL);
1865 }
1866 
1867 uint32_t
_mesa_unmarshal_DrawArrays(struct gl_context * ctx,const struct marshal_cmd_DrawArrays * restrict cmd)1868 _mesa_unmarshal_DrawArrays(struct gl_context *ctx,
1869                            const struct marshal_cmd_DrawArrays *restrict cmd)
1870 {
1871    unreachable("should never end up here");
1872    return 0;
1873 }
1874 
1875 uint32_t
_mesa_unmarshal_DrawArraysInstancedBaseInstance(struct gl_context * ctx,const struct marshal_cmd_DrawArraysInstancedBaseInstance * restrict cmd)1876 _mesa_unmarshal_DrawArraysInstancedBaseInstance(struct gl_context *ctx,
1877                                                 const struct marshal_cmd_DrawArraysInstancedBaseInstance *restrict cmd)
1878 {
1879    unreachable("should never end up here");
1880    return 0;
1881 }
1882 
1883 uint32_t
_mesa_unmarshal_MultiDrawArrays(struct gl_context * ctx,const struct marshal_cmd_MultiDrawArrays * restrict cmd)1884 _mesa_unmarshal_MultiDrawArrays(struct gl_context *ctx,
1885                                 const struct marshal_cmd_MultiDrawArrays *restrict cmd)
1886 {
1887    unreachable("should never end up here");
1888    return 0;
1889 }
1890 
1891 uint32_t
_mesa_unmarshal_DrawRangeElements(struct gl_context * ctx,const struct marshal_cmd_DrawRangeElements * restrict cmd)1892 _mesa_unmarshal_DrawRangeElements(struct gl_context *ctx,
1893                                   const struct marshal_cmd_DrawRangeElements *restrict cmd)
1894 {
1895    unreachable("should never end up here");
1896    return 0;
1897 }
1898 
1899 uint32_t
_mesa_unmarshal_DrawRangeElementsBaseVertex(struct gl_context * ctx,const struct marshal_cmd_DrawRangeElementsBaseVertex * cmd)1900 _mesa_unmarshal_DrawRangeElementsBaseVertex(struct gl_context *ctx,
1901                                             const struct marshal_cmd_DrawRangeElementsBaseVertex *cmd)
1902 {
1903    unreachable("should never end up here");
1904    return 0;
1905 }
1906 
1907 uint32_t
_mesa_unmarshal_DrawElementsInstanced(struct gl_context * ctx,const struct marshal_cmd_DrawElementsInstanced * restrict cmd)1908 _mesa_unmarshal_DrawElementsInstanced(struct gl_context *ctx,
1909                                       const struct marshal_cmd_DrawElementsInstanced *restrict cmd)
1910 {
1911    unreachable("should never end up here");
1912    return 0;
1913 }
1914 
1915 uint32_t
_mesa_unmarshal_DrawElementsBaseVertex(struct gl_context * ctx,const struct marshal_cmd_DrawElementsBaseVertex * restrict cmd)1916 _mesa_unmarshal_DrawElementsBaseVertex(struct gl_context *ctx,
1917                                        const struct marshal_cmd_DrawElementsBaseVertex *restrict cmd)
1918 {
1919    unreachable("should never end up here");
1920    return 0;
1921 }
1922 
1923 uint32_t
_mesa_unmarshal_DrawElementsInstancedBaseVertexBaseInstance(struct gl_context * ctx,const struct marshal_cmd_DrawElementsInstancedBaseVertexBaseInstance * restrict cmd)1924 _mesa_unmarshal_DrawElementsInstancedBaseVertexBaseInstance(struct gl_context *ctx,
1925                                                             const struct marshal_cmd_DrawElementsInstancedBaseVertexBaseInstance *restrict cmd)
1926 {
1927    unreachable("should never end up here");
1928    return 0;
1929 }
1930 
1931 uint32_t
_mesa_unmarshal_MultiDrawElements(struct gl_context * ctx,const struct marshal_cmd_MultiDrawElements * restrict cmd)1932 _mesa_unmarshal_MultiDrawElements(struct gl_context *ctx,
1933                                   const struct marshal_cmd_MultiDrawElements *restrict cmd)
1934 {
1935    unreachable("should never end up here");
1936    return 0;
1937 }
1938 
1939 uint32_t
_mesa_unmarshal_MultiDrawElementsBaseVertex(struct gl_context * ctx,const struct marshal_cmd_MultiDrawElementsBaseVertex * restrict cmd)1940 _mesa_unmarshal_MultiDrawElementsBaseVertex(struct gl_context *ctx,
1941                                             const struct marshal_cmd_MultiDrawElementsBaseVertex *restrict cmd)
1942 {
1943    unreachable("should never end up here");
1944    return 0;
1945 }
1946 
1947 uint32_t
_mesa_unmarshal_MultiModeDrawArraysIBM(struct gl_context * ctx,const struct marshal_cmd_MultiModeDrawArraysIBM * cmd)1948 _mesa_unmarshal_MultiModeDrawArraysIBM(struct gl_context *ctx,
1949                                        const struct marshal_cmd_MultiModeDrawArraysIBM *cmd)
1950 {
1951    unreachable("should never end up here");
1952    return 0;
1953 }
1954 
1955 uint32_t
_mesa_unmarshal_MultiModeDrawElementsIBM(struct gl_context * ctx,const struct marshal_cmd_MultiModeDrawElementsIBM * cmd)1956 _mesa_unmarshal_MultiModeDrawElementsIBM(struct gl_context *ctx,
1957                                          const struct marshal_cmd_MultiModeDrawElementsIBM *cmd)
1958 {
1959    unreachable("should never end up here");
1960    return 0;
1961 }
1962 
1963 void GLAPIENTRY
_mesa_marshal_DrawArraysUserBuf(void)1964 _mesa_marshal_DrawArraysUserBuf(void)
1965 {
1966    unreachable("should never end up here");
1967 }
1968 
1969 void GLAPIENTRY
_mesa_marshal_DrawElementsUserBuf(const GLvoid * cmd)1970 _mesa_marshal_DrawElementsUserBuf(const GLvoid *cmd)
1971 {
1972    unreachable("should never end up here");
1973 }
1974 
1975 void GLAPIENTRY
_mesa_marshal_DrawElementsUserBufPacked(const GLvoid * cmd)1976 _mesa_marshal_DrawElementsUserBufPacked(const GLvoid *cmd)
1977 {
1978    unreachable("should never end up here");
1979 }
1980 
1981 void GLAPIENTRY
_mesa_marshal_MultiDrawArraysUserBuf(void)1982 _mesa_marshal_MultiDrawArraysUserBuf(void)
1983 {
1984    unreachable("should never end up here");
1985 }
1986 
1987 void GLAPIENTRY
_mesa_marshal_MultiDrawElementsUserBuf(GLintptr indexBuf,GLenum mode,const GLsizei * count,GLenum type,const GLvoid * const * indices,GLsizei primcount,const GLint * basevertex)1988 _mesa_marshal_MultiDrawElementsUserBuf(GLintptr indexBuf, GLenum mode,
1989                                        const GLsizei *count, GLenum type,
1990                                        const GLvoid * const *indices,
1991                                        GLsizei primcount,
1992                                        const GLint *basevertex)
1993 {
1994    unreachable("should never end up here");
1995 }
1996 
1997 void GLAPIENTRY
_mesa_marshal_DrawArraysInstancedBaseInstanceDrawID(void)1998 _mesa_marshal_DrawArraysInstancedBaseInstanceDrawID(void)
1999 {
2000    unreachable("should never end up here");
2001 }
2002 
_mesa_marshal_DrawElementsPacked(GLenum mode,GLenum type,GLushort count,GLushort indices)2003 void GLAPIENTRY _mesa_marshal_DrawElementsPacked(GLenum mode, GLenum type,
2004                                                  GLushort count, GLushort indices)
2005 {
2006    unreachable("should never end up here");
2007 }
2008 
2009 void GLAPIENTRY
_mesa_marshal_DrawElementsInstancedBaseVertexBaseInstanceDrawID(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices,GLsizei instance_count,GLint basevertex,GLuint baseinstance,GLuint drawid)2010 _mesa_marshal_DrawElementsInstancedBaseVertexBaseInstanceDrawID(GLenum mode, GLsizei count,
2011                                                                 GLenum type, const GLvoid *indices,
2012                                                                 GLsizei instance_count, GLint basevertex,
2013                                                                 GLuint baseinstance, GLuint drawid)
2014 {
2015    unreachable("should never end up here");
2016 }
2017 
2018 void GLAPIENTRY
_mesa_DrawArraysUserBuf(void)2019 _mesa_DrawArraysUserBuf(void)
2020 {
2021    unreachable("should never end up here");
2022 }
2023 
2024 void GLAPIENTRY
_mesa_MultiDrawArraysUserBuf(void)2025 _mesa_MultiDrawArraysUserBuf(void)
2026 {
2027    unreachable("should never end up here");
2028 }
2029 
2030 void GLAPIENTRY
_mesa_DrawArraysInstancedBaseInstanceDrawID(void)2031 _mesa_DrawArraysInstancedBaseInstanceDrawID(void)
2032 {
2033    unreachable("should never end up here");
2034 }
2035 
_mesa_DrawElementsPacked(GLenum mode,GLenum type,GLushort count,GLushort indices)2036 void GLAPIENTRY _mesa_DrawElementsPacked(GLenum mode, GLenum type,
2037                                          GLushort count, GLushort indices)
2038 {
2039    unreachable("should never end up here");
2040 }
2041 
2042 void GLAPIENTRY
_mesa_DrawElementsInstancedBaseVertexBaseInstanceDrawID(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices,GLsizei instance_count,GLint basevertex,GLuint baseinstance,GLuint drawid)2043 _mesa_DrawElementsInstancedBaseVertexBaseInstanceDrawID(GLenum mode, GLsizei count,
2044                                                         GLenum type, const GLvoid *indices,
2045                                                         GLsizei instance_count, GLint basevertex,
2046                                                         GLuint baseinstance, GLuint drawid)
2047 {
2048    unreachable("should never end up here");
2049 }
2050 
2051 uint32_t
_mesa_unmarshal_PushMatrix(struct gl_context * ctx,const struct marshal_cmd_PushMatrix * restrict cmd)2052 _mesa_unmarshal_PushMatrix(struct gl_context *ctx,
2053                            const struct marshal_cmd_PushMatrix *restrict cmd)
2054 {
2055    const unsigned push_matrix_size = 1;
2056    const unsigned mult_matrixf_size = 9;
2057    const unsigned draw_elements_size =
2058       (align(sizeof(struct marshal_cmd_DrawElements), 8) / 8);
2059    const unsigned draw_elements_packed_size =
2060       (align(sizeof(struct marshal_cmd_DrawElementsPacked), 8) / 8);
2061    const unsigned pop_matrix_size = 1;
2062    uint64_t *next1 = _mesa_glthread_next_cmd((uint64_t *)cmd, push_matrix_size);
2063    uint64_t *next2;
2064 
2065    /* Viewperf has these call patterns. */
2066    switch (_mesa_glthread_get_cmd(next1)->cmd_id) {
2067    case DISPATCH_CMD_DrawElements:
2068       /* Execute this sequence:
2069        *    glPushMatrix
2070        *    (glMultMatrixf with identity is eliminated by the marshal function)
2071        *    glDrawElements
2072        *    glPopMatrix
2073        * as:
2074        *    glDrawElements
2075        */
2076       next2 = _mesa_glthread_next_cmd(next1, draw_elements_size);
2077 
2078       if (_mesa_glthread_get_cmd(next2)->cmd_id == DISPATCH_CMD_PopMatrix) {
2079          /* The beauty of this is that this is inlined. */
2080          _mesa_unmarshal_DrawElements(ctx, (void*)next1);
2081          return push_matrix_size + draw_elements_size + pop_matrix_size;
2082       }
2083       break;
2084 
2085    case DISPATCH_CMD_DrawElementsPacked:
2086       next2 = _mesa_glthread_next_cmd(next1, draw_elements_packed_size);
2087 
2088       if (_mesa_glthread_get_cmd(next2)->cmd_id == DISPATCH_CMD_PopMatrix) {
2089          /* The beauty of this is that this is inlined. */
2090          _mesa_unmarshal_DrawElementsPacked(ctx, (void*)next1);
2091          return push_matrix_size + draw_elements_packed_size + pop_matrix_size;
2092       }
2093       break;
2094 
2095    case DISPATCH_CMD_MultMatrixf:
2096       /* Skip this sequence:
2097        *    glPushMatrix
2098        *    glMultMatrixf
2099        *    glPopMatrix
2100        */
2101       next2 = _mesa_glthread_next_cmd(next1, mult_matrixf_size);
2102 
2103       if (_mesa_glthread_get_cmd(next2)->cmd_id == DISPATCH_CMD_PopMatrix)
2104          return push_matrix_size + mult_matrixf_size + pop_matrix_size;
2105       break;
2106    }
2107 
2108    CALL_PushMatrix(ctx->Dispatch.Current, ());
2109    return push_matrix_size;
2110 }
2111 
2112 void GLAPIENTRY
_mesa_marshal_PushMatrix(void)2113 _mesa_marshal_PushMatrix(void)
2114 {
2115    GET_CURRENT_CONTEXT(ctx);
2116 
2117    _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_PushMatrix,
2118                                    sizeof(struct marshal_cmd_PushMatrix));
2119    _mesa_glthread_PushMatrix(ctx);
2120 }
2121