17ec681f3Smrg/*
27ec681f3Smrg * Copyright © 2020 Advanced Micro Devices, Inc.
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice (including the next
127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg * Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
217ec681f3Smrg * IN THE SOFTWARE.
227ec681f3Smrg */
237ec681f3Smrg
247ec681f3Smrg/* Draw function marshalling for glthread.
257ec681f3Smrg *
267ec681f3Smrg * The purpose of these glDraw wrappers is to upload non-VBO vertex and
277ec681f3Smrg * index data, so that glthread doesn't have to execute synchronously.
287ec681f3Smrg */
297ec681f3Smrg
307ec681f3Smrg#include "c99_alloca.h"
317ec681f3Smrg
327ec681f3Smrg#include "main/glthread_marshal.h"
337ec681f3Smrg#include "main/dispatch.h"
347ec681f3Smrg#include "main/varray.h"
357ec681f3Smrg
367ec681f3Smrgstatic inline unsigned
377ec681f3Smrgget_index_size(GLenum type)
387ec681f3Smrg{
397ec681f3Smrg   /* GL_UNSIGNED_BYTE  - GL_UNSIGNED_BYTE = 0
407ec681f3Smrg    * GL_UNSIGNED_SHORT - GL_UNSIGNED_BYTE = 2
417ec681f3Smrg    * GL_UNSIGNED_INT   - GL_UNSIGNED_BYTE = 4
427ec681f3Smrg    *
437ec681f3Smrg    * Divide by 2 to get n=0,1,2, then the index size is: 1 << n
447ec681f3Smrg    */
457ec681f3Smrg   return 1 << ((type - GL_UNSIGNED_BYTE) >> 1);
467ec681f3Smrg}
477ec681f3Smrg
487ec681f3Smrgstatic inline bool
497ec681f3Smrgis_index_type_valid(GLenum type)
507ec681f3Smrg{
517ec681f3Smrg   /* GL_UNSIGNED_BYTE  = 0x1401
527ec681f3Smrg    * GL_UNSIGNED_SHORT = 0x1403
537ec681f3Smrg    * GL_UNSIGNED_INT   = 0x1405
547ec681f3Smrg    *
557ec681f3Smrg    * The trick is that bit 1 and bit 2 mean USHORT and UINT, respectively.
567ec681f3Smrg    * After clearing those two bits (with ~6), we should get UBYTE.
577ec681f3Smrg    * Both bits can't be set, because the enum would be greater than UINT.
587ec681f3Smrg    */
597ec681f3Smrg   return type <= GL_UNSIGNED_INT && (type & ~6) == GL_UNSIGNED_BYTE;
607ec681f3Smrg}
617ec681f3Smrg
627ec681f3Smrgstatic ALWAYS_INLINE struct gl_buffer_object *
637ec681f3Smrgupload_indices(struct gl_context *ctx, unsigned count, unsigned index_size,
647ec681f3Smrg               const GLvoid **indices)
657ec681f3Smrg{
667ec681f3Smrg   struct gl_buffer_object *upload_buffer = NULL;
677ec681f3Smrg   unsigned upload_offset = 0;
687ec681f3Smrg
697ec681f3Smrg   assert(count);
707ec681f3Smrg
717ec681f3Smrg   _mesa_glthread_upload(ctx, *indices, index_size * count,
727ec681f3Smrg                         &upload_offset, &upload_buffer, NULL);
737ec681f3Smrg   assert(upload_buffer);
747ec681f3Smrg   *indices = (const GLvoid*)(intptr_t)upload_offset;
757ec681f3Smrg
767ec681f3Smrg   return upload_buffer;
777ec681f3Smrg}
787ec681f3Smrg
797ec681f3Smrgstatic ALWAYS_INLINE struct gl_buffer_object *
807ec681f3Smrgupload_multi_indices(struct gl_context *ctx, unsigned total_count,
817ec681f3Smrg                     unsigned index_size, unsigned draw_count,
827ec681f3Smrg                     const GLsizei *count, const GLvoid *const *indices,
837ec681f3Smrg                     const GLvoid **out_indices)
847ec681f3Smrg{
857ec681f3Smrg   struct gl_buffer_object *upload_buffer = NULL;
867ec681f3Smrg   unsigned upload_offset = 0;
877ec681f3Smrg   uint8_t *upload_ptr = NULL;
887ec681f3Smrg
897ec681f3Smrg   assert(total_count);
907ec681f3Smrg
917ec681f3Smrg   _mesa_glthread_upload(ctx, NULL, index_size * total_count,
927ec681f3Smrg                         &upload_offset, &upload_buffer, &upload_ptr);
937ec681f3Smrg   assert(upload_buffer);
947ec681f3Smrg
957ec681f3Smrg   for (unsigned i = 0, offset = 0; i < draw_count; i++) {
967ec681f3Smrg      if (count[i] == 0)
977ec681f3Smrg         continue;
987ec681f3Smrg
997ec681f3Smrg      unsigned size = count[i] * index_size;
1007ec681f3Smrg
1017ec681f3Smrg      memcpy(upload_ptr + offset, indices[i], size);
1027ec681f3Smrg      out_indices[i] = (const GLvoid*)(intptr_t)(upload_offset + offset);
1037ec681f3Smrg      offset += size;
1047ec681f3Smrg   }
1057ec681f3Smrg
1067ec681f3Smrg   return upload_buffer;
1077ec681f3Smrg}
1087ec681f3Smrg
1097ec681f3Smrgstatic ALWAYS_INLINE bool
1107ec681f3Smrgupload_vertices(struct gl_context *ctx, unsigned user_buffer_mask,
1117ec681f3Smrg                unsigned start_vertex, unsigned num_vertices,
1127ec681f3Smrg                unsigned start_instance, unsigned num_instances,
1137ec681f3Smrg                struct glthread_attrib_binding *buffers)
1147ec681f3Smrg{
1157ec681f3Smrg   struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
1167ec681f3Smrg   unsigned attrib_mask_iter = vao->Enabled;
1177ec681f3Smrg   unsigned num_buffers = 0;
1187ec681f3Smrg
1197ec681f3Smrg   assert((num_vertices || !(user_buffer_mask & ~vao->NonZeroDivisorMask)) &&
1207ec681f3Smrg          (num_instances || !(user_buffer_mask & vao->NonZeroDivisorMask)));
1217ec681f3Smrg
1227ec681f3Smrg   if (unlikely(vao->BufferInterleaved & user_buffer_mask)) {
1237ec681f3Smrg      /* Slower upload path where some buffers reference multiple attribs,
1247ec681f3Smrg       * so we have to use 2 while loops instead of 1.
1257ec681f3Smrg       */
1267ec681f3Smrg      unsigned start_offset[VERT_ATTRIB_MAX];
1277ec681f3Smrg      unsigned end_offset[VERT_ATTRIB_MAX];
1287ec681f3Smrg      uint32_t buffer_mask = 0;
1297ec681f3Smrg
1307ec681f3Smrg      while (attrib_mask_iter) {
1317ec681f3Smrg         unsigned i = u_bit_scan(&attrib_mask_iter);
1327ec681f3Smrg         unsigned binding_index = vao->Attrib[i].BufferIndex;
1337ec681f3Smrg
1347ec681f3Smrg         if (!(user_buffer_mask & (1 << binding_index)))
1357ec681f3Smrg            continue;
1367ec681f3Smrg
1377ec681f3Smrg         unsigned stride = vao->Attrib[binding_index].Stride;
1387ec681f3Smrg         unsigned instance_div = vao->Attrib[binding_index].Divisor;
1397ec681f3Smrg         unsigned element_size = vao->Attrib[i].ElementSize;
1407ec681f3Smrg         unsigned offset = vao->Attrib[i].RelativeOffset;
1417ec681f3Smrg         unsigned size;
1427ec681f3Smrg
1437ec681f3Smrg         if (instance_div) {
1447ec681f3Smrg            /* Per-instance attrib. */
1457ec681f3Smrg
1467ec681f3Smrg            /* Figure out how many instances we'll render given instance_div.  We
1477ec681f3Smrg             * can't use the typical div_round_up() pattern because the CTS uses
1487ec681f3Smrg             * instance_div = ~0 for a test, which overflows div_round_up()'s
1497ec681f3Smrg             * addition.
1507ec681f3Smrg             */
1517ec681f3Smrg            unsigned count = num_instances / instance_div;
1527ec681f3Smrg            if (count * instance_div != num_instances)
1537ec681f3Smrg               count++;
1547ec681f3Smrg
1557ec681f3Smrg            offset += stride * start_instance;
1567ec681f3Smrg            size = stride * (count - 1) + element_size;
1577ec681f3Smrg         } else {
1587ec681f3Smrg            /* Per-vertex attrib. */
1597ec681f3Smrg            offset += stride * start_vertex;
1607ec681f3Smrg            size = stride * (num_vertices - 1) + element_size;
1617ec681f3Smrg         }
1627ec681f3Smrg
1637ec681f3Smrg         unsigned binding_index_bit = 1u << binding_index;
1647ec681f3Smrg
1657ec681f3Smrg         /* Update upload offsets. */
1667ec681f3Smrg         if (!(buffer_mask & binding_index_bit)) {
1677ec681f3Smrg            start_offset[binding_index] = offset;
1687ec681f3Smrg            end_offset[binding_index] = offset + size;
1697ec681f3Smrg         } else {
1707ec681f3Smrg            if (offset < start_offset[binding_index])
1717ec681f3Smrg               start_offset[binding_index] = offset;
1727ec681f3Smrg            if (offset + size > end_offset[binding_index])
1737ec681f3Smrg               end_offset[binding_index] = offset + size;
1747ec681f3Smrg         }
1757ec681f3Smrg
1767ec681f3Smrg         buffer_mask |= binding_index_bit;
1777ec681f3Smrg      }
1787ec681f3Smrg
1797ec681f3Smrg      /* Upload buffers. */
1807ec681f3Smrg      while (buffer_mask) {
1817ec681f3Smrg         struct gl_buffer_object *upload_buffer = NULL;
1827ec681f3Smrg         unsigned upload_offset = 0;
1837ec681f3Smrg         unsigned start, end;
1847ec681f3Smrg
1857ec681f3Smrg         unsigned binding_index = u_bit_scan(&buffer_mask);
1867ec681f3Smrg
1877ec681f3Smrg         start = start_offset[binding_index];
1887ec681f3Smrg         end = end_offset[binding_index];
1897ec681f3Smrg         assert(start < end);
1907ec681f3Smrg
1917ec681f3Smrg         const void *ptr = vao->Attrib[binding_index].Pointer;
1927ec681f3Smrg         _mesa_glthread_upload(ctx, (uint8_t*)ptr + start,
1937ec681f3Smrg                               end - start, &upload_offset,
1947ec681f3Smrg                               &upload_buffer, NULL);
1957ec681f3Smrg         assert(upload_buffer);
1967ec681f3Smrg
1977ec681f3Smrg         buffers[num_buffers].buffer = upload_buffer;
1987ec681f3Smrg         buffers[num_buffers].offset = upload_offset - start;
1997ec681f3Smrg         buffers[num_buffers].original_pointer = ptr;
2007ec681f3Smrg         num_buffers++;
2017ec681f3Smrg      }
2027ec681f3Smrg
2037ec681f3Smrg      return true;
2047ec681f3Smrg   }
2057ec681f3Smrg
2067ec681f3Smrg   /* Faster path where all attribs are separate. */
2077ec681f3Smrg   while (attrib_mask_iter) {
2087ec681f3Smrg      unsigned i = u_bit_scan(&attrib_mask_iter);
2097ec681f3Smrg      unsigned binding_index = vao->Attrib[i].BufferIndex;
2107ec681f3Smrg
2117ec681f3Smrg      if (!(user_buffer_mask & (1 << binding_index)))
2127ec681f3Smrg         continue;
2137ec681f3Smrg
2147ec681f3Smrg      struct gl_buffer_object *upload_buffer = NULL;
2157ec681f3Smrg      unsigned upload_offset = 0;
2167ec681f3Smrg      unsigned stride = vao->Attrib[binding_index].Stride;
2177ec681f3Smrg      unsigned instance_div = vao->Attrib[binding_index].Divisor;
2187ec681f3Smrg      unsigned element_size = vao->Attrib[i].ElementSize;
2197ec681f3Smrg      unsigned offset = vao->Attrib[i].RelativeOffset;
2207ec681f3Smrg      unsigned size;
2217ec681f3Smrg
2227ec681f3Smrg      if (instance_div) {
2237ec681f3Smrg         /* Per-instance attrib. */
2247ec681f3Smrg
2257ec681f3Smrg         /* Figure out how many instances we'll render given instance_div.  We
2267ec681f3Smrg          * can't use the typical div_round_up() pattern because the CTS uses
2277ec681f3Smrg          * instance_div = ~0 for a test, which overflows div_round_up()'s
2287ec681f3Smrg          * addition.
2297ec681f3Smrg          */
2307ec681f3Smrg         unsigned count = num_instances / instance_div;
2317ec681f3Smrg         if (count * instance_div != num_instances)
2327ec681f3Smrg            count++;
2337ec681f3Smrg
2347ec681f3Smrg         offset += stride * start_instance;
2357ec681f3Smrg         size = stride * (count - 1) + element_size;
2367ec681f3Smrg      } else {
2377ec681f3Smrg         /* Per-vertex attrib. */
2387ec681f3Smrg         offset += stride * start_vertex;
2397ec681f3Smrg         size = stride * (num_vertices - 1) + element_size;
2407ec681f3Smrg      }
2417ec681f3Smrg
2427ec681f3Smrg      const void *ptr = vao->Attrib[binding_index].Pointer;
2437ec681f3Smrg      _mesa_glthread_upload(ctx, (uint8_t*)ptr + offset,
2447ec681f3Smrg                            size, &upload_offset, &upload_buffer, NULL);
2457ec681f3Smrg      assert(upload_buffer);
2467ec681f3Smrg
2477ec681f3Smrg      buffers[num_buffers].buffer = upload_buffer;
2487ec681f3Smrg      buffers[num_buffers].offset = upload_offset - offset;
2497ec681f3Smrg      buffers[num_buffers].original_pointer = ptr;
2507ec681f3Smrg      num_buffers++;
2517ec681f3Smrg   }
2527ec681f3Smrg
2537ec681f3Smrg   return true;
2547ec681f3Smrg}
2557ec681f3Smrg
2567ec681f3Smrg/* Generic DrawArrays structure NOT supporting user buffers. Ignore the name. */
2577ec681f3Smrgstruct marshal_cmd_DrawArrays
2587ec681f3Smrg{
2597ec681f3Smrg   struct marshal_cmd_base cmd_base;
2607ec681f3Smrg   GLenum mode;
2617ec681f3Smrg   GLint first;
2627ec681f3Smrg   GLsizei count;
2637ec681f3Smrg   GLsizei instance_count;
2647ec681f3Smrg   GLuint baseinstance;
2657ec681f3Smrg};
2667ec681f3Smrg
2677ec681f3Smrguint32_t
2687ec681f3Smrg_mesa_unmarshal_DrawArrays(struct gl_context *ctx,
2697ec681f3Smrg                           const struct marshal_cmd_DrawArrays *cmd,
2707ec681f3Smrg                           const uint64_t *last)
2717ec681f3Smrg{
2727ec681f3Smrg   /* Ignore the function name. We use DISPATCH_CMD_DrawArrays
2737ec681f3Smrg    * for all DrawArrays variants without user buffers, and
2747ec681f3Smrg    * DISPATCH_CMD_DrawArraysInstancedBaseInstance for all DrawArrays
2757ec681f3Smrg    * variants with user buffrs.
2767ec681f3Smrg    */
2777ec681f3Smrg   const GLenum mode = cmd->mode;
2787ec681f3Smrg   const GLint first = cmd->first;
2797ec681f3Smrg   const GLsizei count = cmd->count;
2807ec681f3Smrg   const GLsizei instance_count = cmd->instance_count;
2817ec681f3Smrg   const GLuint baseinstance = cmd->baseinstance;
2827ec681f3Smrg
2837ec681f3Smrg   CALL_DrawArraysInstancedBaseInstance(ctx->CurrentServerDispatch,
2847ec681f3Smrg                                        (mode, first, count, instance_count,
2857ec681f3Smrg                                         baseinstance));
2867ec681f3Smrg   return cmd->cmd_base.cmd_size;
2877ec681f3Smrg}
2887ec681f3Smrg
2897ec681f3Smrgstatic ALWAYS_INLINE void
2907ec681f3Smrgdraw_arrays_async(struct gl_context *ctx, GLenum mode, GLint first,
2917ec681f3Smrg                  GLsizei count, GLsizei instance_count, GLuint baseinstance)
2927ec681f3Smrg{
2937ec681f3Smrg   int cmd_size = sizeof(struct marshal_cmd_DrawArrays);
2947ec681f3Smrg   struct marshal_cmd_DrawArrays *cmd =
2957ec681f3Smrg      _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawArrays, cmd_size);
2967ec681f3Smrg
2977ec681f3Smrg   cmd->mode = mode;
2987ec681f3Smrg   cmd->first = first;
2997ec681f3Smrg   cmd->count = count;
3007ec681f3Smrg   cmd->instance_count = instance_count;
3017ec681f3Smrg   cmd->baseinstance = baseinstance;
3027ec681f3Smrg}
3037ec681f3Smrg
3047ec681f3Smrg/* Generic DrawArrays structure supporting user buffers. Ignore the name. */
3057ec681f3Smrgstruct marshal_cmd_DrawArraysInstancedBaseInstance
3067ec681f3Smrg{
3077ec681f3Smrg   struct marshal_cmd_base cmd_base;
3087ec681f3Smrg   GLenum mode;
3097ec681f3Smrg   GLint first;
3107ec681f3Smrg   GLsizei count;
3117ec681f3Smrg   GLsizei instance_count;
3127ec681f3Smrg   GLuint baseinstance;
3137ec681f3Smrg   GLuint user_buffer_mask;
3147ec681f3Smrg};
3157ec681f3Smrg
3167ec681f3Smrguint32_t
3177ec681f3Smrg_mesa_unmarshal_DrawArraysInstancedBaseInstance(struct gl_context *ctx,
3187ec681f3Smrg                                                const struct marshal_cmd_DrawArraysInstancedBaseInstance *cmd,
3197ec681f3Smrg                                                const uint64_t *last)
3207ec681f3Smrg{
3217ec681f3Smrg   /* Ignore the function name. We use DISPATCH_CMD_DrawArrays
3227ec681f3Smrg    * for all DrawArrays variants without user buffers, and
3237ec681f3Smrg    * DISPATCH_CMD_DrawArraysInstancedBaseInstance for all DrawArrays
3247ec681f3Smrg    * variants with user buffrs.
3257ec681f3Smrg    */
3267ec681f3Smrg   const GLenum mode = cmd->mode;
3277ec681f3Smrg   const GLint first = cmd->first;
3287ec681f3Smrg   const GLsizei count = cmd->count;
3297ec681f3Smrg   const GLsizei instance_count = cmd->instance_count;
3307ec681f3Smrg   const GLuint baseinstance = cmd->baseinstance;
3317ec681f3Smrg   const GLuint user_buffer_mask = cmd->user_buffer_mask;
3327ec681f3Smrg   const struct glthread_attrib_binding *buffers =
3337ec681f3Smrg      (const struct glthread_attrib_binding *)(cmd + 1);
3347ec681f3Smrg
3357ec681f3Smrg   /* Bind uploaded buffers if needed. */
3367ec681f3Smrg   if (user_buffer_mask) {
3377ec681f3Smrg      _mesa_InternalBindVertexBuffers(ctx, buffers, user_buffer_mask,
3387ec681f3Smrg                                      false);
3397ec681f3Smrg   }
3407ec681f3Smrg
3417ec681f3Smrg   CALL_DrawArraysInstancedBaseInstance(ctx->CurrentServerDispatch,
3427ec681f3Smrg                                        (mode, first, count, instance_count,
3437ec681f3Smrg                                         baseinstance));
3447ec681f3Smrg
3457ec681f3Smrg   /* Restore states. */
3467ec681f3Smrg   if (user_buffer_mask) {
3477ec681f3Smrg      _mesa_InternalBindVertexBuffers(ctx, buffers, user_buffer_mask,
3487ec681f3Smrg                                      true);
3497ec681f3Smrg   }
3507ec681f3Smrg   return cmd->cmd_base.cmd_size;
3517ec681f3Smrg}
3527ec681f3Smrg
3537ec681f3Smrgstatic ALWAYS_INLINE void
3547ec681f3Smrgdraw_arrays_async_user(struct gl_context *ctx, GLenum mode, GLint first,
3557ec681f3Smrg                       GLsizei count, GLsizei instance_count, GLuint baseinstance,
3567ec681f3Smrg                       unsigned user_buffer_mask,
3577ec681f3Smrg                       const struct glthread_attrib_binding *buffers)
3587ec681f3Smrg{
3597ec681f3Smrg   int buffers_size = util_bitcount(user_buffer_mask) * sizeof(buffers[0]);
3607ec681f3Smrg   int cmd_size = sizeof(struct marshal_cmd_DrawArraysInstancedBaseInstance) +
3617ec681f3Smrg                  buffers_size;
3627ec681f3Smrg   struct marshal_cmd_DrawArraysInstancedBaseInstance *cmd;
3637ec681f3Smrg
3647ec681f3Smrg   cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawArraysInstancedBaseInstance,
3657ec681f3Smrg                                         cmd_size);
3667ec681f3Smrg   cmd->mode = mode;
3677ec681f3Smrg   cmd->first = first;
3687ec681f3Smrg   cmd->count = count;
3697ec681f3Smrg   cmd->instance_count = instance_count;
3707ec681f3Smrg   cmd->baseinstance = baseinstance;
3717ec681f3Smrg   cmd->user_buffer_mask = user_buffer_mask;
3727ec681f3Smrg
3737ec681f3Smrg   if (user_buffer_mask)
3747ec681f3Smrg      memcpy(cmd + 1, buffers, buffers_size);
3757ec681f3Smrg}
3767ec681f3Smrg
3777ec681f3Smrgstatic ALWAYS_INLINE void
3787ec681f3Smrgdraw_arrays(GLenum mode, GLint first, GLsizei count, GLsizei instance_count,
3797ec681f3Smrg            GLuint baseinstance, bool compiled_into_dlist)
3807ec681f3Smrg{
3817ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
3827ec681f3Smrg
3837ec681f3Smrg   struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
3847ec681f3Smrg   unsigned user_buffer_mask = vao->UserPointerMask & vao->BufferEnabled;
3857ec681f3Smrg
3867ec681f3Smrg   if (compiled_into_dlist && ctx->GLThread.ListMode) {
3877ec681f3Smrg      _mesa_glthread_finish_before(ctx, "DrawArrays");
3887ec681f3Smrg      /* Use the function that's compiled into a display list. */
3897ec681f3Smrg      CALL_DrawArrays(ctx->CurrentServerDispatch, (mode, first, count));
3907ec681f3Smrg      return;
3917ec681f3Smrg   }
3927ec681f3Smrg
3937ec681f3Smrg   /* Fast path when nothing needs to be done.
3947ec681f3Smrg    *
3957ec681f3Smrg    * This is also an error path. Zero counts should still call the driver
3967ec681f3Smrg    * for possible GL errors.
3977ec681f3Smrg    */
3987ec681f3Smrg   if (ctx->API == API_OPENGL_CORE || !user_buffer_mask ||
3997ec681f3Smrg       count <= 0 || instance_count <= 0) {
4007ec681f3Smrg      draw_arrays_async(ctx, mode, first, count, instance_count, baseinstance);
4017ec681f3Smrg      return;
4027ec681f3Smrg   }
4037ec681f3Smrg
4047ec681f3Smrg   /* Upload and draw. */
4057ec681f3Smrg   struct glthread_attrib_binding buffers[VERT_ATTRIB_MAX];
4067ec681f3Smrg   if (!ctx->GLThread.SupportsNonVBOUploads ||
4077ec681f3Smrg       !upload_vertices(ctx, user_buffer_mask, first, count, baseinstance,
4087ec681f3Smrg                        instance_count, buffers)) {
4097ec681f3Smrg      _mesa_glthread_finish_before(ctx, "DrawArrays");
4107ec681f3Smrg      CALL_DrawArraysInstancedBaseInstance(ctx->CurrentServerDispatch,
4117ec681f3Smrg                                           (mode, first, count, instance_count,
4127ec681f3Smrg                                            baseinstance));
4137ec681f3Smrg      return;
4147ec681f3Smrg   }
4157ec681f3Smrg
4167ec681f3Smrg   draw_arrays_async_user(ctx, mode, first, count, instance_count, baseinstance,
4177ec681f3Smrg                          user_buffer_mask, buffers);
4187ec681f3Smrg}
4197ec681f3Smrg
4207ec681f3Smrgstruct marshal_cmd_MultiDrawArrays
4217ec681f3Smrg{
4227ec681f3Smrg   struct marshal_cmd_base cmd_base;
4237ec681f3Smrg   GLenum mode;
4247ec681f3Smrg   GLsizei draw_count;
4257ec681f3Smrg   GLuint user_buffer_mask;
4267ec681f3Smrg};
4277ec681f3Smrg
4287ec681f3Smrguint32_t
4297ec681f3Smrg_mesa_unmarshal_MultiDrawArrays(struct gl_context *ctx,
4307ec681f3Smrg                                const struct marshal_cmd_MultiDrawArrays *cmd,
4317ec681f3Smrg                                const uint64_t *last)
4327ec681f3Smrg{
4337ec681f3Smrg   const GLenum mode = cmd->mode;
4347ec681f3Smrg   const GLsizei draw_count = cmd->draw_count;
4357ec681f3Smrg   const GLuint user_buffer_mask = cmd->user_buffer_mask;
4367ec681f3Smrg
4377ec681f3Smrg   const char *variable_data = (const char *)(cmd + 1);
4387ec681f3Smrg   const GLint *first = (GLint *)variable_data;
4397ec681f3Smrg   variable_data += sizeof(GLint) * draw_count;
4407ec681f3Smrg   const GLsizei *count = (GLsizei *)variable_data;
4417ec681f3Smrg   variable_data += sizeof(GLsizei) * draw_count;
4427ec681f3Smrg   const struct glthread_attrib_binding *buffers =
4437ec681f3Smrg      (const struct glthread_attrib_binding *)variable_data;
4447ec681f3Smrg
4457ec681f3Smrg   /* Bind uploaded buffers if needed. */
4467ec681f3Smrg   if (user_buffer_mask) {
4477ec681f3Smrg      _mesa_InternalBindVertexBuffers(ctx, buffers, user_buffer_mask,
4487ec681f3Smrg                                      false);
4497ec681f3Smrg   }
4507ec681f3Smrg
4517ec681f3Smrg   CALL_MultiDrawArrays(ctx->CurrentServerDispatch,
4527ec681f3Smrg                        (mode, first, count, draw_count));
4537ec681f3Smrg
4547ec681f3Smrg   /* Restore states. */
4557ec681f3Smrg   if (user_buffer_mask) {
4567ec681f3Smrg      _mesa_InternalBindVertexBuffers(ctx, buffers, user_buffer_mask,
4577ec681f3Smrg                                      true);
4587ec681f3Smrg   }
4597ec681f3Smrg   return cmd->cmd_base.cmd_size;
4607ec681f3Smrg}
4617ec681f3Smrg
4627ec681f3Smrgstatic ALWAYS_INLINE void
4637ec681f3Smrgmulti_draw_arrays_async(struct gl_context *ctx, GLenum mode,
4647ec681f3Smrg                        const GLint *first, const GLsizei *count,
4657ec681f3Smrg                        GLsizei draw_count, unsigned user_buffer_mask,
4667ec681f3Smrg                        const struct glthread_attrib_binding *buffers)
4677ec681f3Smrg{
4687ec681f3Smrg   int first_size = sizeof(GLint) * draw_count;
4697ec681f3Smrg   int count_size = sizeof(GLsizei) * draw_count;
4707ec681f3Smrg   int buffers_size = util_bitcount(user_buffer_mask) * sizeof(buffers[0]);
4717ec681f3Smrg   int cmd_size = sizeof(struct marshal_cmd_MultiDrawArrays) +
4727ec681f3Smrg                  first_size + count_size + buffers_size;
4737ec681f3Smrg   struct marshal_cmd_MultiDrawArrays *cmd;
4747ec681f3Smrg
4757ec681f3Smrg   cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_MultiDrawArrays,
4767ec681f3Smrg                                         cmd_size);
4777ec681f3Smrg   cmd->mode = mode;
4787ec681f3Smrg   cmd->draw_count = draw_count;
4797ec681f3Smrg   cmd->user_buffer_mask = user_buffer_mask;
4807ec681f3Smrg
4817ec681f3Smrg   char *variable_data = (char*)(cmd + 1);
4827ec681f3Smrg   memcpy(variable_data, first, first_size);
4837ec681f3Smrg   variable_data += first_size;
4847ec681f3Smrg   memcpy(variable_data, count, count_size);
4857ec681f3Smrg
4867ec681f3Smrg   if (user_buffer_mask) {
4877ec681f3Smrg      variable_data += count_size;
4887ec681f3Smrg      memcpy(variable_data, buffers, buffers_size);
4897ec681f3Smrg   }
4907ec681f3Smrg}
4917ec681f3Smrg
4927ec681f3Smrgvoid GLAPIENTRY
4937ec681f3Smrg_mesa_marshal_MultiDrawArrays(GLenum mode, const GLint *first,
4947ec681f3Smrg                              const GLsizei *count, GLsizei draw_count)
4957ec681f3Smrg{
4967ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
4977ec681f3Smrg
4987ec681f3Smrg   struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
4997ec681f3Smrg   unsigned user_buffer_mask = vao->UserPointerMask & vao->BufferEnabled;
5007ec681f3Smrg
5017ec681f3Smrg   if (ctx->GLThread.ListMode)
5027ec681f3Smrg      goto sync;
5037ec681f3Smrg
5047ec681f3Smrg   if (draw_count >= 0 &&
5057ec681f3Smrg       (ctx->API == API_OPENGL_CORE || !user_buffer_mask)) {
5067ec681f3Smrg      multi_draw_arrays_async(ctx, mode, first, count, draw_count, 0, NULL);
5077ec681f3Smrg      return;
5087ec681f3Smrg   }
5097ec681f3Smrg
5107ec681f3Smrg   /* If the draw count is too high or negative, the queue can't be used. */
5117ec681f3Smrg   if (!ctx->GLThread.SupportsNonVBOUploads ||
5127ec681f3Smrg       draw_count < 0 || draw_count > MARSHAL_MAX_CMD_SIZE / 16)
5137ec681f3Smrg      goto sync;
5147ec681f3Smrg
5157ec681f3Smrg   unsigned min_index = ~0;
5167ec681f3Smrg   unsigned max_index_exclusive = 0;
5177ec681f3Smrg
5187ec681f3Smrg   for (unsigned i = 0; i < draw_count; i++) {
5197ec681f3Smrg      GLsizei vertex_count = count[i];
5207ec681f3Smrg
5217ec681f3Smrg      if (vertex_count < 0) {
5227ec681f3Smrg         /* Just call the driver to set the error. */
5237ec681f3Smrg         multi_draw_arrays_async(ctx, mode, first, count, draw_count, 0, NULL);
5247ec681f3Smrg         return;
5257ec681f3Smrg      }
5267ec681f3Smrg      if (vertex_count == 0)
5277ec681f3Smrg         continue;
5287ec681f3Smrg
5297ec681f3Smrg      min_index = MIN2(min_index, first[i]);
5307ec681f3Smrg      max_index_exclusive = MAX2(max_index_exclusive, first[i] + vertex_count);
5317ec681f3Smrg   }
5327ec681f3Smrg
5337ec681f3Smrg   unsigned num_vertices = max_index_exclusive - min_index;
5347ec681f3Smrg   if (num_vertices == 0) {
5357ec681f3Smrg      /* Nothing to do, but call the driver to set possible GL errors. */
5367ec681f3Smrg      multi_draw_arrays_async(ctx, mode, first, count, draw_count, 0, NULL);
5377ec681f3Smrg      return;
5387ec681f3Smrg   }
5397ec681f3Smrg
5407ec681f3Smrg   /* Upload and draw. */
5417ec681f3Smrg   struct glthread_attrib_binding buffers[VERT_ATTRIB_MAX];
5427ec681f3Smrg   if (!upload_vertices(ctx, user_buffer_mask, min_index, num_vertices,
5437ec681f3Smrg                        0, 1, buffers))
5447ec681f3Smrg      goto sync;
5457ec681f3Smrg
5467ec681f3Smrg   multi_draw_arrays_async(ctx, mode, first, count, draw_count,
5477ec681f3Smrg                           user_buffer_mask, buffers);
5487ec681f3Smrg   return;
5497ec681f3Smrg
5507ec681f3Smrgsync:
5517ec681f3Smrg   _mesa_glthread_finish_before(ctx, "MultiDrawArrays");
5527ec681f3Smrg   CALL_MultiDrawArrays(ctx->CurrentServerDispatch,
5537ec681f3Smrg                        (mode, first, count, draw_count));
5547ec681f3Smrg}
5557ec681f3Smrg
5567ec681f3Smrg/* DrawElementsInstancedBaseVertexBaseInstance not supporting user buffers.
5577ec681f3Smrg * Ignore the name.
5587ec681f3Smrg */
5597ec681f3Smrgstruct marshal_cmd_DrawElementsInstancedARB
5607ec681f3Smrg{
5617ec681f3Smrg   struct marshal_cmd_base cmd_base;
5627ec681f3Smrg   GLenum mode;
5637ec681f3Smrg   GLenum type;
5647ec681f3Smrg   GLsizei count;
5657ec681f3Smrg   GLsizei instance_count;
5667ec681f3Smrg   GLint basevertex;
5677ec681f3Smrg   GLuint baseinstance;
5687ec681f3Smrg   const GLvoid *indices;
5697ec681f3Smrg};
5707ec681f3Smrg
5717ec681f3Smrguint32_t
5727ec681f3Smrg_mesa_unmarshal_DrawElementsInstancedARB(struct gl_context *ctx,
5737ec681f3Smrg                                         const struct marshal_cmd_DrawElementsInstancedARB *cmd,
5747ec681f3Smrg                                         const uint64_t *last)
5757ec681f3Smrg{
5767ec681f3Smrg   /* Ignore the function name. We use DISPATCH_CMD_DrawElementsInstanced-
5777ec681f3Smrg    * BaseVertexBaseInstance for all DrawElements variants with user buffers,
5787ec681f3Smrg    * and both DISPATCH_CMD_DrawElementsInstancedARB and DISPATCH_CMD_Draw-
5797ec681f3Smrg    * RangeElementsBaseVertex for all draw elements variants without user
5807ec681f3Smrg    * buffers.
5817ec681f3Smrg    */
5827ec681f3Smrg   const GLenum mode = cmd->mode;
5837ec681f3Smrg   const GLsizei count = cmd->count;
5847ec681f3Smrg   const GLenum type = cmd->type;
5857ec681f3Smrg   const GLvoid *indices = cmd->indices;
5867ec681f3Smrg   const GLsizei instance_count = cmd->instance_count;
5877ec681f3Smrg   const GLint basevertex = cmd->basevertex;
5887ec681f3Smrg   const GLuint baseinstance = cmd->baseinstance;
5897ec681f3Smrg
5907ec681f3Smrg   CALL_DrawElementsInstancedBaseVertexBaseInstance(ctx->CurrentServerDispatch,
5917ec681f3Smrg                                                    (mode, count, type, indices,
5927ec681f3Smrg                                                     instance_count, basevertex,
5937ec681f3Smrg                                                     baseinstance));
5947ec681f3Smrg   return cmd->cmd_base.cmd_size;
5957ec681f3Smrg}
5967ec681f3Smrg
5977ec681f3Smrgstruct marshal_cmd_DrawRangeElementsBaseVertex
5987ec681f3Smrg{
5997ec681f3Smrg   struct marshal_cmd_base cmd_base;
6007ec681f3Smrg   GLenum mode;
6017ec681f3Smrg   GLenum type;
6027ec681f3Smrg   GLsizei count;
6037ec681f3Smrg   GLint basevertex;
6047ec681f3Smrg   GLuint min_index;
6057ec681f3Smrg   GLuint max_index;
6067ec681f3Smrg   const GLvoid *indices;
6077ec681f3Smrg};
6087ec681f3Smrg
6097ec681f3Smrguint32_t
6107ec681f3Smrg_mesa_unmarshal_DrawRangeElementsBaseVertex(struct gl_context *ctx,
6117ec681f3Smrg                                            const struct marshal_cmd_DrawRangeElementsBaseVertex *cmd,
6127ec681f3Smrg                                            const uint64_t *last)
6137ec681f3Smrg{
6147ec681f3Smrg   const GLenum mode = cmd->mode;
6157ec681f3Smrg   const GLsizei count = cmd->count;
6167ec681f3Smrg   const GLenum type = cmd->type;
6177ec681f3Smrg   const GLvoid *indices = cmd->indices;
6187ec681f3Smrg   const GLint basevertex = cmd->basevertex;
6197ec681f3Smrg   const GLuint min_index = cmd->min_index;
6207ec681f3Smrg   const GLuint max_index = cmd->max_index;
6217ec681f3Smrg
6227ec681f3Smrg   CALL_DrawRangeElementsBaseVertex(ctx->CurrentServerDispatch,
6237ec681f3Smrg                                    (mode, min_index, max_index, count,
6247ec681f3Smrg                                     type, indices, basevertex));
6257ec681f3Smrg   return cmd->cmd_base.cmd_size;
6267ec681f3Smrg}
6277ec681f3Smrg
6287ec681f3Smrgstatic ALWAYS_INLINE void
6297ec681f3Smrgdraw_elements_async(struct gl_context *ctx, GLenum mode, GLsizei count,
6307ec681f3Smrg                    GLenum type, const GLvoid *indices, GLsizei instance_count,
6317ec681f3Smrg                    GLint basevertex, GLuint baseinstance,
6327ec681f3Smrg                    bool index_bounds_valid, GLuint min_index, GLuint max_index)
6337ec681f3Smrg{
6347ec681f3Smrg   if (index_bounds_valid) {
6357ec681f3Smrg      int cmd_size = sizeof(struct marshal_cmd_DrawRangeElementsBaseVertex);
6367ec681f3Smrg      struct marshal_cmd_DrawRangeElementsBaseVertex *cmd =
6377ec681f3Smrg         _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawRangeElementsBaseVertex, cmd_size);
6387ec681f3Smrg
6397ec681f3Smrg      cmd->mode = mode;
6407ec681f3Smrg      cmd->count = count;
6417ec681f3Smrg      cmd->type = type;
6427ec681f3Smrg      cmd->indices = indices;
6437ec681f3Smrg      cmd->basevertex = basevertex;
6447ec681f3Smrg      cmd->min_index = min_index;
6457ec681f3Smrg      cmd->max_index = max_index;
6467ec681f3Smrg   } else {
6477ec681f3Smrg      int cmd_size = sizeof(struct marshal_cmd_DrawElementsInstancedARB);
6487ec681f3Smrg      struct marshal_cmd_DrawElementsInstancedARB *cmd =
6497ec681f3Smrg         _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawElementsInstancedARB, cmd_size);
6507ec681f3Smrg
6517ec681f3Smrg      cmd->mode = mode;
6527ec681f3Smrg      cmd->count = count;
6537ec681f3Smrg      cmd->type = type;
6547ec681f3Smrg      cmd->indices = indices;
6557ec681f3Smrg      cmd->instance_count = instance_count;
6567ec681f3Smrg      cmd->basevertex = basevertex;
6577ec681f3Smrg      cmd->baseinstance = baseinstance;
6587ec681f3Smrg   }
6597ec681f3Smrg}
6607ec681f3Smrg
6617ec681f3Smrgstruct marshal_cmd_DrawElementsInstancedBaseVertexBaseInstance
6627ec681f3Smrg{
6637ec681f3Smrg   struct marshal_cmd_base cmd_base;
6647ec681f3Smrg   bool index_bounds_valid;
6657ec681f3Smrg   GLenum mode;
6667ec681f3Smrg   GLenum type;
6677ec681f3Smrg   GLsizei count;
6687ec681f3Smrg   GLsizei instance_count;
6697ec681f3Smrg   GLint basevertex;
6707ec681f3Smrg   GLuint baseinstance;
6717ec681f3Smrg   GLuint min_index;
6727ec681f3Smrg   GLuint max_index;
6737ec681f3Smrg   GLuint user_buffer_mask;
6747ec681f3Smrg   const GLvoid *indices;
6757ec681f3Smrg   struct gl_buffer_object *index_buffer;
6767ec681f3Smrg};
6777ec681f3Smrg
6787ec681f3Smrguint32_t
6797ec681f3Smrg_mesa_unmarshal_DrawElementsInstancedBaseVertexBaseInstance(struct gl_context *ctx,
6807ec681f3Smrg                                                            const struct marshal_cmd_DrawElementsInstancedBaseVertexBaseInstance *cmd,
6817ec681f3Smrg                                                            const uint64_t *last)
6827ec681f3Smrg{
6837ec681f3Smrg   /* Ignore the function name. We use DISPATCH_CMD_DrawElementsInstanced-
6847ec681f3Smrg    * BaseVertexBaseInstance for all DrawElements variants with user buffers,
6857ec681f3Smrg    * and both DISPATCH_CMD_DrawElementsInstancedARB and DISPATCH_CMD_Draw-
6867ec681f3Smrg    * RangeElementsBaseVertex for all draw elements variants without user
6877ec681f3Smrg    * buffers.
6887ec681f3Smrg    */
6897ec681f3Smrg   const GLenum mode = cmd->mode;
6907ec681f3Smrg   const GLsizei count = cmd->count;
6917ec681f3Smrg   const GLenum type = cmd->type;
6927ec681f3Smrg   const GLvoid *indices = cmd->indices;
6937ec681f3Smrg   const GLsizei instance_count = cmd->instance_count;
6947ec681f3Smrg   const GLint basevertex = cmd->basevertex;
6957ec681f3Smrg   const GLuint baseinstance = cmd->baseinstance;
6967ec681f3Smrg   const GLuint min_index = cmd->min_index;
6977ec681f3Smrg   const GLuint max_index = cmd->max_index;
6987ec681f3Smrg   const GLuint user_buffer_mask = cmd->user_buffer_mask;
6997ec681f3Smrg   struct gl_buffer_object *index_buffer = cmd->index_buffer;
7007ec681f3Smrg   const struct glthread_attrib_binding *buffers =
7017ec681f3Smrg      (const struct glthread_attrib_binding *)(cmd + 1);
7027ec681f3Smrg
7037ec681f3Smrg   /* Bind uploaded buffers if needed. */
7047ec681f3Smrg   if (user_buffer_mask) {
7057ec681f3Smrg      _mesa_InternalBindVertexBuffers(ctx, buffers, user_buffer_mask,
7067ec681f3Smrg                                      false);
7077ec681f3Smrg   }
7087ec681f3Smrg   if (index_buffer) {
7097ec681f3Smrg      _mesa_InternalBindElementBuffer(ctx, index_buffer);
7107ec681f3Smrg   }
7117ec681f3Smrg
7127ec681f3Smrg   /* Draw. */
7137ec681f3Smrg   if (cmd->index_bounds_valid && instance_count == 1 && baseinstance == 0) {
7147ec681f3Smrg      CALL_DrawRangeElementsBaseVertex(ctx->CurrentServerDispatch,
7157ec681f3Smrg                                       (mode, min_index, max_index, count,
7167ec681f3Smrg                                        type, indices, basevertex));
7177ec681f3Smrg   } else {
7187ec681f3Smrg      CALL_DrawElementsInstancedBaseVertexBaseInstance(ctx->CurrentServerDispatch,
7197ec681f3Smrg                                                       (mode, count, type, indices,
7207ec681f3Smrg                                                        instance_count, basevertex,
7217ec681f3Smrg                                                        baseinstance));
7227ec681f3Smrg   }
7237ec681f3Smrg
7247ec681f3Smrg   /* Restore states. */
7257ec681f3Smrg   if (index_buffer) {
7267ec681f3Smrg      _mesa_InternalBindElementBuffer(ctx, NULL);
7277ec681f3Smrg   }
7287ec681f3Smrg   if (user_buffer_mask) {
7297ec681f3Smrg      _mesa_InternalBindVertexBuffers(ctx, buffers, user_buffer_mask,
7307ec681f3Smrg                                      true);
7317ec681f3Smrg   }
7327ec681f3Smrg   return cmd->cmd_base.cmd_size;
7337ec681f3Smrg}
7347ec681f3Smrg
7357ec681f3Smrgstatic ALWAYS_INLINE void
7367ec681f3Smrgdraw_elements_async_user(struct gl_context *ctx, GLenum mode, GLsizei count,
7377ec681f3Smrg                         GLenum type, const GLvoid *indices, GLsizei instance_count,
7387ec681f3Smrg                         GLint basevertex, GLuint baseinstance,
7397ec681f3Smrg                         bool index_bounds_valid, GLuint min_index, GLuint max_index,
7407ec681f3Smrg                         struct gl_buffer_object *index_buffer,
7417ec681f3Smrg                         unsigned user_buffer_mask,
7427ec681f3Smrg                         const struct glthread_attrib_binding *buffers)
7437ec681f3Smrg{
7447ec681f3Smrg   int buffers_size = util_bitcount(user_buffer_mask) * sizeof(buffers[0]);
7457ec681f3Smrg   int cmd_size = sizeof(struct marshal_cmd_DrawElementsInstancedBaseVertexBaseInstance) +
7467ec681f3Smrg                  buffers_size;
7477ec681f3Smrg   struct marshal_cmd_DrawElementsInstancedBaseVertexBaseInstance *cmd;
7487ec681f3Smrg
7497ec681f3Smrg   cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_DrawElementsInstancedBaseVertexBaseInstance, cmd_size);
7507ec681f3Smrg   cmd->mode = mode;
7517ec681f3Smrg   cmd->count = count;
7527ec681f3Smrg   cmd->type = type;
7537ec681f3Smrg   cmd->indices = indices;
7547ec681f3Smrg   cmd->instance_count = instance_count;
7557ec681f3Smrg   cmd->basevertex = basevertex;
7567ec681f3Smrg   cmd->baseinstance = baseinstance;
7577ec681f3Smrg   cmd->min_index = min_index;
7587ec681f3Smrg   cmd->max_index = max_index;
7597ec681f3Smrg   cmd->user_buffer_mask = user_buffer_mask;
7607ec681f3Smrg   cmd->index_bounds_valid = index_bounds_valid;
7617ec681f3Smrg   cmd->index_buffer = index_buffer;
7627ec681f3Smrg
7637ec681f3Smrg   if (user_buffer_mask)
7647ec681f3Smrg      memcpy(cmd + 1, buffers, buffers_size);
7657ec681f3Smrg}
7667ec681f3Smrg
7677ec681f3Smrgstatic void
7687ec681f3Smrgdraw_elements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
7697ec681f3Smrg              GLsizei instance_count, GLint basevertex, GLuint baseinstance,
7707ec681f3Smrg              bool index_bounds_valid, GLuint min_index, GLuint max_index,
7717ec681f3Smrg              bool compiled_into_dlist)
7727ec681f3Smrg{
7737ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
7747ec681f3Smrg
7757ec681f3Smrg   struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
7767ec681f3Smrg   unsigned user_buffer_mask = vao->UserPointerMask & vao->BufferEnabled;
7777ec681f3Smrg   bool has_user_indices = vao->CurrentElementBufferName == 0;
7787ec681f3Smrg
7797ec681f3Smrg   if (compiled_into_dlist && ctx->GLThread.ListMode)
7807ec681f3Smrg      goto sync;
7817ec681f3Smrg
7827ec681f3Smrg   /* Fast path when nothing needs to be done.
7837ec681f3Smrg    *
7847ec681f3Smrg    * This is also an error path. Zero counts should still call the driver
7857ec681f3Smrg    * for possible GL errors.
7867ec681f3Smrg    */
7877ec681f3Smrg   if (ctx->API == API_OPENGL_CORE ||
7887ec681f3Smrg       count <= 0 || instance_count <= 0 || max_index < min_index ||
7897ec681f3Smrg       !is_index_type_valid(type) ||
7907ec681f3Smrg       (!user_buffer_mask && !has_user_indices)) {
7917ec681f3Smrg      draw_elements_async(ctx, mode, count, type, indices, instance_count,
7927ec681f3Smrg                          basevertex, baseinstance, index_bounds_valid,
7937ec681f3Smrg                          min_index, max_index);
7947ec681f3Smrg      return;
7957ec681f3Smrg   }
7967ec681f3Smrg
7977ec681f3Smrg   if (!ctx->GLThread.SupportsNonVBOUploads)
7987ec681f3Smrg      goto sync;
7997ec681f3Smrg
8007ec681f3Smrg   bool need_index_bounds = user_buffer_mask & ~vao->NonZeroDivisorMask;
8017ec681f3Smrg   unsigned index_size = get_index_size(type);
8027ec681f3Smrg
8037ec681f3Smrg   if (need_index_bounds && !index_bounds_valid) {
8047ec681f3Smrg      /* Sync if indices come from a buffer and vertices come from memory
8057ec681f3Smrg       * and index bounds are not valid.
8067ec681f3Smrg       *
8077ec681f3Smrg       * We would have to map the indices to compute the index bounds, and
8087ec681f3Smrg       * for that we would have to sync anyway.
8097ec681f3Smrg       */
8107ec681f3Smrg      if (!has_user_indices)
8117ec681f3Smrg         goto sync;
8127ec681f3Smrg
8137ec681f3Smrg      /* Compute the index bounds. */
8147ec681f3Smrg      min_index = ~0;
8157ec681f3Smrg      max_index = 0;
8167ec681f3Smrg      vbo_get_minmax_index_mapped(count, index_size,
8177ec681f3Smrg                                  ctx->GLThread._RestartIndex[index_size - 1],
8187ec681f3Smrg                                  ctx->GLThread._PrimitiveRestart, indices,
8197ec681f3Smrg                                  &min_index, &max_index);
8207ec681f3Smrg      index_bounds_valid = true;
8217ec681f3Smrg   }
8227ec681f3Smrg
8237ec681f3Smrg   unsigned start_vertex = min_index + basevertex;
8247ec681f3Smrg   unsigned num_vertices = max_index + 1 - min_index;
8257ec681f3Smrg
8267ec681f3Smrg   /* If there is too much data to upload, sync and let the driver unroll
8277ec681f3Smrg    * indices. */
8287ec681f3Smrg   if (util_is_vbo_upload_ratio_too_large(count, num_vertices))
8297ec681f3Smrg      goto sync;
8307ec681f3Smrg
8317ec681f3Smrg   struct glthread_attrib_binding buffers[VERT_ATTRIB_MAX];
8327ec681f3Smrg   if (user_buffer_mask &&
8337ec681f3Smrg       !upload_vertices(ctx, user_buffer_mask, start_vertex, num_vertices,
8347ec681f3Smrg                        baseinstance, instance_count, buffers))
8357ec681f3Smrg      goto sync;
8367ec681f3Smrg
8377ec681f3Smrg   /* Upload indices. */
8387ec681f3Smrg   struct gl_buffer_object *index_buffer = NULL;
8397ec681f3Smrg   if (has_user_indices)
8407ec681f3Smrg      index_buffer = upload_indices(ctx, count, index_size, &indices);
8417ec681f3Smrg
8427ec681f3Smrg   /* Draw asynchronously. */
8437ec681f3Smrg   draw_elements_async_user(ctx, mode, count, type, indices, instance_count,
8447ec681f3Smrg                            basevertex, baseinstance, index_bounds_valid,
8457ec681f3Smrg                            min_index, max_index, index_buffer,
8467ec681f3Smrg                            user_buffer_mask, buffers);
8477ec681f3Smrg   return;
8487ec681f3Smrg
8497ec681f3Smrgsync:
8507ec681f3Smrg   _mesa_glthread_finish_before(ctx, "DrawElements");
8517ec681f3Smrg
8527ec681f3Smrg   if (compiled_into_dlist && ctx->GLThread.ListMode) {
8537ec681f3Smrg      /* Only use the ones that are compiled into display lists. */
8547ec681f3Smrg      if (basevertex) {
8557ec681f3Smrg         CALL_DrawElementsBaseVertex(ctx->CurrentServerDispatch,
8567ec681f3Smrg                                     (mode, count, type, indices, basevertex));
8577ec681f3Smrg      } else if (index_bounds_valid) {
8587ec681f3Smrg         CALL_DrawRangeElements(ctx->CurrentServerDispatch,
8597ec681f3Smrg                                (mode, min_index, max_index, count, type, indices));
8607ec681f3Smrg      } else {
8617ec681f3Smrg         CALL_DrawElements(ctx->CurrentServerDispatch, (mode, count, type, indices));
8627ec681f3Smrg      }
8637ec681f3Smrg   } else if (index_bounds_valid && instance_count == 1 && baseinstance == 0) {
8647ec681f3Smrg      CALL_DrawRangeElementsBaseVertex(ctx->CurrentServerDispatch,
8657ec681f3Smrg                                       (mode, min_index, max_index, count,
8667ec681f3Smrg                                        type, indices, basevertex));
8677ec681f3Smrg   } else {
8687ec681f3Smrg      CALL_DrawElementsInstancedBaseVertexBaseInstance(ctx->CurrentServerDispatch,
8697ec681f3Smrg                                                       (mode, count, type, indices,
8707ec681f3Smrg                                                        instance_count, basevertex,
8717ec681f3Smrg                                                        baseinstance));
8727ec681f3Smrg   }
8737ec681f3Smrg}
8747ec681f3Smrg
8757ec681f3Smrgstruct marshal_cmd_MultiDrawElementsBaseVertex
8767ec681f3Smrg{
8777ec681f3Smrg   struct marshal_cmd_base cmd_base;
8787ec681f3Smrg   bool has_base_vertex;
8797ec681f3Smrg   GLenum mode;
8807ec681f3Smrg   GLenum type;
8817ec681f3Smrg   GLsizei draw_count;
8827ec681f3Smrg   GLuint user_buffer_mask;
8837ec681f3Smrg   struct gl_buffer_object *index_buffer;
8847ec681f3Smrg};
8857ec681f3Smrg
8867ec681f3Smrguint32_t
8877ec681f3Smrg_mesa_unmarshal_MultiDrawElementsBaseVertex(struct gl_context *ctx,
8887ec681f3Smrg                                            const struct marshal_cmd_MultiDrawElementsBaseVertex *cmd,
8897ec681f3Smrg                                            const uint64_t *last)
8907ec681f3Smrg{
8917ec681f3Smrg   const GLenum mode = cmd->mode;
8927ec681f3Smrg   const GLenum type = cmd->type;
8937ec681f3Smrg   const GLsizei draw_count = cmd->draw_count;
8947ec681f3Smrg   const GLuint user_buffer_mask = cmd->user_buffer_mask;
8957ec681f3Smrg   struct gl_buffer_object *index_buffer = cmd->index_buffer;
8967ec681f3Smrg   const bool has_base_vertex = cmd->has_base_vertex;
8977ec681f3Smrg
8987ec681f3Smrg   const char *variable_data = (const char *)(cmd + 1);
8997ec681f3Smrg   const GLsizei *count = (GLsizei *)variable_data;
9007ec681f3Smrg   variable_data += sizeof(GLsizei) * draw_count;
9017ec681f3Smrg   const GLvoid *const *indices = (const GLvoid *const *)variable_data;
9027ec681f3Smrg   variable_data += sizeof(const GLvoid *const *) * draw_count;
9037ec681f3Smrg   const GLsizei *basevertex = NULL;
9047ec681f3Smrg   if (has_base_vertex) {
9057ec681f3Smrg      basevertex = (GLsizei *)variable_data;
9067ec681f3Smrg      variable_data += sizeof(GLsizei) * draw_count;
9077ec681f3Smrg   }
9087ec681f3Smrg   const struct glthread_attrib_binding *buffers =
9097ec681f3Smrg      (const struct glthread_attrib_binding *)variable_data;
9107ec681f3Smrg
9117ec681f3Smrg   /* Bind uploaded buffers if needed. */
9127ec681f3Smrg   if (user_buffer_mask) {
9137ec681f3Smrg      _mesa_InternalBindVertexBuffers(ctx, buffers, user_buffer_mask,
9147ec681f3Smrg                                      false);
9157ec681f3Smrg   }
9167ec681f3Smrg   if (index_buffer) {
9177ec681f3Smrg      _mesa_InternalBindElementBuffer(ctx, index_buffer);
9187ec681f3Smrg   }
9197ec681f3Smrg
9207ec681f3Smrg   /* Draw. */
9217ec681f3Smrg   if (has_base_vertex) {
9227ec681f3Smrg      CALL_MultiDrawElementsBaseVertex(ctx->CurrentServerDispatch,
9237ec681f3Smrg                                       (mode, count, type, indices, draw_count,
9247ec681f3Smrg                                        basevertex));
9257ec681f3Smrg   } else {
9267ec681f3Smrg      CALL_MultiDrawElementsEXT(ctx->CurrentServerDispatch,
9277ec681f3Smrg                                (mode, count, type, indices, draw_count));
9287ec681f3Smrg   }
9297ec681f3Smrg
9307ec681f3Smrg   /* Restore states. */
9317ec681f3Smrg   if (index_buffer) {
9327ec681f3Smrg      _mesa_InternalBindElementBuffer(ctx, NULL);
9337ec681f3Smrg   }
9347ec681f3Smrg   if (user_buffer_mask) {
9357ec681f3Smrg      _mesa_InternalBindVertexBuffers(ctx, buffers, user_buffer_mask,
9367ec681f3Smrg                                      true);
9377ec681f3Smrg   }
9387ec681f3Smrg   return cmd->cmd_base.cmd_size;
9397ec681f3Smrg}
9407ec681f3Smrg
9417ec681f3Smrgstatic ALWAYS_INLINE void
9427ec681f3Smrgmulti_draw_elements_async(struct gl_context *ctx, GLenum mode,
9437ec681f3Smrg                          const GLsizei *count, GLenum type,
9447ec681f3Smrg                          const GLvoid *const *indices, GLsizei draw_count,
9457ec681f3Smrg                          const GLsizei *basevertex,
9467ec681f3Smrg                          struct gl_buffer_object *index_buffer,
9477ec681f3Smrg                          unsigned user_buffer_mask,
9487ec681f3Smrg                          const struct glthread_attrib_binding *buffers)
9497ec681f3Smrg{
9507ec681f3Smrg   int count_size = sizeof(GLsizei) * draw_count;
9517ec681f3Smrg   int indices_size = sizeof(indices[0]) * draw_count;
9527ec681f3Smrg   int basevertex_size = basevertex ? sizeof(GLsizei) * draw_count : 0;
9537ec681f3Smrg   int buffers_size = util_bitcount(user_buffer_mask) * sizeof(buffers[0]);
9547ec681f3Smrg   int cmd_size = sizeof(struct marshal_cmd_MultiDrawElementsBaseVertex) +
9557ec681f3Smrg                  count_size + indices_size + basevertex_size + buffers_size;
9567ec681f3Smrg   struct marshal_cmd_MultiDrawElementsBaseVertex *cmd;
9577ec681f3Smrg
9587ec681f3Smrg   cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_MultiDrawElementsBaseVertex, cmd_size);
9597ec681f3Smrg   cmd->mode = mode;
9607ec681f3Smrg   cmd->type = type;
9617ec681f3Smrg   cmd->draw_count = draw_count;
9627ec681f3Smrg   cmd->user_buffer_mask = user_buffer_mask;
9637ec681f3Smrg   cmd->index_buffer = index_buffer;
9647ec681f3Smrg   cmd->has_base_vertex = basevertex != NULL;
9657ec681f3Smrg
9667ec681f3Smrg   char *variable_data = (char*)(cmd + 1);
9677ec681f3Smrg   memcpy(variable_data, count, count_size);
9687ec681f3Smrg   variable_data += count_size;
9697ec681f3Smrg   memcpy(variable_data, indices, indices_size);
9707ec681f3Smrg   variable_data += indices_size;
9717ec681f3Smrg
9727ec681f3Smrg   if (basevertex) {
9737ec681f3Smrg      memcpy(variable_data, basevertex, basevertex_size);
9747ec681f3Smrg      variable_data += basevertex_size;
9757ec681f3Smrg   }
9767ec681f3Smrg
9777ec681f3Smrg   if (user_buffer_mask)
9787ec681f3Smrg      memcpy(variable_data, buffers, buffers_size);
9797ec681f3Smrg}
9807ec681f3Smrg
9817ec681f3Smrgvoid GLAPIENTRY
9827ec681f3Smrg_mesa_marshal_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
9837ec681f3Smrg                                          GLenum type,
9847ec681f3Smrg                                          const GLvoid *const *indices,
9857ec681f3Smrg                                          GLsizei draw_count,
9867ec681f3Smrg                                          const GLsizei *basevertex)
9877ec681f3Smrg{
9887ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
9897ec681f3Smrg
9907ec681f3Smrg   struct glthread_vao *vao = ctx->GLThread.CurrentVAO;
9917ec681f3Smrg   unsigned user_buffer_mask = vao->UserPointerMask & vao->BufferEnabled;
9927ec681f3Smrg   bool has_user_indices = vao->CurrentElementBufferName == 0;
9937ec681f3Smrg
9947ec681f3Smrg   if (ctx->GLThread.ListMode)
9957ec681f3Smrg      goto sync;
9967ec681f3Smrg
9977ec681f3Smrg   /* Fast path when nothing needs to be done. */
9987ec681f3Smrg   if (draw_count >= 0 &&
9997ec681f3Smrg       (ctx->API == API_OPENGL_CORE ||
10007ec681f3Smrg        !is_index_type_valid(type) ||
10017ec681f3Smrg        (!user_buffer_mask && !has_user_indices))) {
10027ec681f3Smrg      multi_draw_elements_async(ctx, mode, count, type, indices, draw_count,
10037ec681f3Smrg                                basevertex, 0, 0, NULL);
10047ec681f3Smrg      return;
10057ec681f3Smrg   }
10067ec681f3Smrg
10077ec681f3Smrg   bool need_index_bounds = user_buffer_mask & ~vao->NonZeroDivisorMask;
10087ec681f3Smrg
10097ec681f3Smrg   /* If the draw count is too high or negative, the queue can't be used.
10107ec681f3Smrg    *
10117ec681f3Smrg    * Sync if indices come from a buffer and vertices come from memory
10127ec681f3Smrg    * and index bounds are not valid. We would have to map the indices
10137ec681f3Smrg    * to compute the index bounds, and for that we would have to sync anyway.
10147ec681f3Smrg    */
10157ec681f3Smrg   if (!ctx->GLThread.SupportsNonVBOUploads ||
10167ec681f3Smrg       draw_count < 0 || draw_count > MARSHAL_MAX_CMD_SIZE / 32 ||
10177ec681f3Smrg       (need_index_bounds && !has_user_indices))
10187ec681f3Smrg      goto sync;
10197ec681f3Smrg
10207ec681f3Smrg   unsigned index_size = get_index_size(type);
10217ec681f3Smrg   unsigned min_index = ~0;
10227ec681f3Smrg   unsigned max_index = 0;
10237ec681f3Smrg   unsigned total_count = 0;
10247ec681f3Smrg   unsigned num_vertices = 0;
10257ec681f3Smrg
10267ec681f3Smrg   /* This is always true if there is per-vertex data that needs to be
10277ec681f3Smrg    * uploaded.
10287ec681f3Smrg    */
10297ec681f3Smrg   if (need_index_bounds) {
10307ec681f3Smrg      /* Compute the index bounds. */
10317ec681f3Smrg      for (unsigned i = 0; i < draw_count; i++) {
10327ec681f3Smrg         GLsizei vertex_count = count[i];
10337ec681f3Smrg
10347ec681f3Smrg         if (vertex_count < 0) {
10357ec681f3Smrg            /* Just call the driver to set the error. */
10367ec681f3Smrg            multi_draw_elements_async(ctx, mode, count, type, indices, draw_count,
10377ec681f3Smrg                                      basevertex, 0, 0, NULL);
10387ec681f3Smrg            return;
10397ec681f3Smrg         }
10407ec681f3Smrg         if (vertex_count == 0)
10417ec681f3Smrg            continue;
10427ec681f3Smrg
10437ec681f3Smrg         unsigned min = ~0, max = 0;
10447ec681f3Smrg         vbo_get_minmax_index_mapped(vertex_count, index_size,
10457ec681f3Smrg                                     ctx->GLThread._RestartIndex[index_size - 1],
10467ec681f3Smrg                                     ctx->GLThread._PrimitiveRestart, indices[i],
10477ec681f3Smrg                                     &min, &max);
10487ec681f3Smrg         if (basevertex) {
10497ec681f3Smrg            min += basevertex[i];
10507ec681f3Smrg            max += basevertex[i];
10517ec681f3Smrg         }
10527ec681f3Smrg         min_index = MIN2(min_index, min);
10537ec681f3Smrg         max_index = MAX2(max_index, max);
10547ec681f3Smrg         total_count += vertex_count;
10557ec681f3Smrg      }
10567ec681f3Smrg
10577ec681f3Smrg      num_vertices = max_index + 1 - min_index;
10587ec681f3Smrg
10597ec681f3Smrg      if (total_count == 0 || num_vertices == 0) {
10607ec681f3Smrg         /* Nothing to do, but call the driver to set possible GL errors. */
10617ec681f3Smrg         multi_draw_elements_async(ctx, mode, count, type, indices, draw_count,
10627ec681f3Smrg                                   basevertex, 0, 0, NULL);
10637ec681f3Smrg         return;
10647ec681f3Smrg      }
10657ec681f3Smrg
10667ec681f3Smrg      /* If there is too much data to upload, sync and let the driver unroll
10677ec681f3Smrg       * indices. */
10687ec681f3Smrg      if (util_is_vbo_upload_ratio_too_large(total_count, num_vertices))
10697ec681f3Smrg         goto sync;
10707ec681f3Smrg   } else if (has_user_indices) {
10717ec681f3Smrg      /* Only compute total_count for the upload of indices. */
10727ec681f3Smrg      for (unsigned i = 0; i < draw_count; i++) {
10737ec681f3Smrg         GLsizei vertex_count = count[i];
10747ec681f3Smrg
10757ec681f3Smrg         if (vertex_count < 0) {
10767ec681f3Smrg            /* Just call the driver to set the error. */
10777ec681f3Smrg            multi_draw_elements_async(ctx, mode, count, type, indices, draw_count,
10787ec681f3Smrg                                      basevertex, 0, 0, NULL);
10797ec681f3Smrg            return;
10807ec681f3Smrg         }
10817ec681f3Smrg         if (vertex_count == 0)
10827ec681f3Smrg            continue;
10837ec681f3Smrg
10847ec681f3Smrg         total_count += vertex_count;
10857ec681f3Smrg      }
10867ec681f3Smrg
10877ec681f3Smrg      if (total_count == 0) {
10887ec681f3Smrg         /* Nothing to do, but call the driver to set possible GL errors. */
10897ec681f3Smrg         multi_draw_elements_async(ctx, mode, count, type, indices, draw_count,
10907ec681f3Smrg                                   basevertex, 0, 0, NULL);
10917ec681f3Smrg         return;
10927ec681f3Smrg      }
10937ec681f3Smrg   }
10947ec681f3Smrg
10957ec681f3Smrg   /* Upload vertices. */
10967ec681f3Smrg   struct glthread_attrib_binding buffers[VERT_ATTRIB_MAX];
10977ec681f3Smrg   if (user_buffer_mask &&
10987ec681f3Smrg       !upload_vertices(ctx, user_buffer_mask, min_index, num_vertices,
10997ec681f3Smrg                        0, 1, buffers))
11007ec681f3Smrg      goto sync;
11017ec681f3Smrg
11027ec681f3Smrg   /* Upload indices. */
11037ec681f3Smrg   struct gl_buffer_object *index_buffer = NULL;
11047ec681f3Smrg   if (has_user_indices) {
11057ec681f3Smrg      const GLvoid **out_indices = alloca(sizeof(indices[0]) * draw_count);
11067ec681f3Smrg
11077ec681f3Smrg      index_buffer = upload_multi_indices(ctx, total_count, index_size,
11087ec681f3Smrg                                          draw_count, count, indices,
11097ec681f3Smrg                                          out_indices);
11107ec681f3Smrg      indices = out_indices;
11117ec681f3Smrg   }
11127ec681f3Smrg
11137ec681f3Smrg   /* Draw asynchronously. */
11147ec681f3Smrg   multi_draw_elements_async(ctx, mode, count, type, indices, draw_count,
11157ec681f3Smrg                             basevertex, index_buffer, user_buffer_mask,
11167ec681f3Smrg                             buffers);
11177ec681f3Smrg   return;
11187ec681f3Smrg
11197ec681f3Smrgsync:
11207ec681f3Smrg   _mesa_glthread_finish_before(ctx, "DrawElements");
11217ec681f3Smrg
11227ec681f3Smrg   if (basevertex) {
11237ec681f3Smrg      CALL_MultiDrawElementsBaseVertex(ctx->CurrentServerDispatch,
11247ec681f3Smrg                                       (mode, count, type, indices, draw_count,
11257ec681f3Smrg                                        basevertex));
11267ec681f3Smrg   } else {
11277ec681f3Smrg      CALL_MultiDrawElementsEXT(ctx->CurrentServerDispatch,
11287ec681f3Smrg                                (mode, count, type, indices, draw_count));
11297ec681f3Smrg   }
11307ec681f3Smrg}
11317ec681f3Smrg
11327ec681f3Smrgvoid GLAPIENTRY
11337ec681f3Smrg_mesa_marshal_DrawArrays(GLenum mode, GLint first, GLsizei count)
11347ec681f3Smrg{
11357ec681f3Smrg   draw_arrays(mode, first, count, 1, 0, true);
11367ec681f3Smrg}
11377ec681f3Smrg
11387ec681f3Smrgvoid GLAPIENTRY
11397ec681f3Smrg_mesa_marshal_DrawArraysInstancedARB(GLenum mode, GLint first, GLsizei count,
11407ec681f3Smrg                                     GLsizei instance_count)
11417ec681f3Smrg{
11427ec681f3Smrg   draw_arrays(mode, first, count, instance_count, 0, false);
11437ec681f3Smrg}
11447ec681f3Smrg
11457ec681f3Smrgvoid GLAPIENTRY
11467ec681f3Smrg_mesa_marshal_DrawArraysInstancedBaseInstance(GLenum mode, GLint first,
11477ec681f3Smrg                                              GLsizei count, GLsizei instance_count,
11487ec681f3Smrg                                              GLuint baseinstance)
11497ec681f3Smrg{
11507ec681f3Smrg   draw_arrays(mode, first, count, instance_count, baseinstance, false);
11517ec681f3Smrg}
11527ec681f3Smrg
11537ec681f3Smrgvoid GLAPIENTRY
11547ec681f3Smrg_mesa_marshal_DrawElements(GLenum mode, GLsizei count, GLenum type,
11557ec681f3Smrg                           const GLvoid *indices)
11567ec681f3Smrg{
11577ec681f3Smrg   draw_elements(mode, count, type, indices, 1, 0, 0, false, 0, 0, true);
11587ec681f3Smrg}
11597ec681f3Smrg
11607ec681f3Smrgvoid GLAPIENTRY
11617ec681f3Smrg_mesa_marshal_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
11627ec681f3Smrg                                GLsizei count, GLenum type,
11637ec681f3Smrg                                const GLvoid *indices)
11647ec681f3Smrg{
11657ec681f3Smrg   draw_elements(mode, count, type, indices, 1, 0, 0, true, start, end, true);
11667ec681f3Smrg}
11677ec681f3Smrg
11687ec681f3Smrgvoid GLAPIENTRY
11697ec681f3Smrg_mesa_marshal_DrawElementsInstancedARB(GLenum mode, GLsizei count, GLenum type,
11707ec681f3Smrg                                       const GLvoid *indices, GLsizei instance_count)
11717ec681f3Smrg{
11727ec681f3Smrg   draw_elements(mode, count, type, indices, instance_count, 0, 0, false, 0, 0, false);
11737ec681f3Smrg}
11747ec681f3Smrg
11757ec681f3Smrgvoid GLAPIENTRY
11767ec681f3Smrg_mesa_marshal_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
11777ec681f3Smrg                                     const GLvoid *indices, GLint basevertex)
11787ec681f3Smrg{
11797ec681f3Smrg   draw_elements(mode, count, type, indices, 1, basevertex, 0, false, 0, 0, true);
11807ec681f3Smrg}
11817ec681f3Smrg
11827ec681f3Smrgvoid GLAPIENTRY
11837ec681f3Smrg_mesa_marshal_DrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end,
11847ec681f3Smrg                                          GLsizei count, GLenum type,
11857ec681f3Smrg                                          const GLvoid *indices, GLint basevertex)
11867ec681f3Smrg{
11877ec681f3Smrg   draw_elements(mode, count, type, indices, 1, basevertex, 0, true, start, end, false);
11887ec681f3Smrg}
11897ec681f3Smrg
11907ec681f3Smrgvoid GLAPIENTRY
11917ec681f3Smrg_mesa_marshal_DrawElementsInstancedBaseVertex(GLenum mode, GLsizei count,
11927ec681f3Smrg                                              GLenum type, const GLvoid *indices,
11937ec681f3Smrg                                              GLsizei instance_count, GLint basevertex)
11947ec681f3Smrg{
11957ec681f3Smrg   draw_elements(mode, count, type, indices, instance_count, basevertex, 0, false, 0, 0, false);
11967ec681f3Smrg}
11977ec681f3Smrg
11987ec681f3Smrgvoid GLAPIENTRY
11997ec681f3Smrg_mesa_marshal_DrawElementsInstancedBaseInstance(GLenum mode, GLsizei count,
12007ec681f3Smrg                                                GLenum type, const GLvoid *indices,
12017ec681f3Smrg                                                GLsizei instance_count, GLuint baseinstance)
12027ec681f3Smrg{
12037ec681f3Smrg   draw_elements(mode, count, type, indices, instance_count, 0, baseinstance, false, 0, 0, false);
12047ec681f3Smrg}
12057ec681f3Smrg
12067ec681f3Smrgvoid GLAPIENTRY
12077ec681f3Smrg_mesa_marshal_DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count,
12087ec681f3Smrg                                                          GLenum type, const GLvoid *indices,
12097ec681f3Smrg                                                          GLsizei instance_count, GLint basevertex,
12107ec681f3Smrg                                                          GLuint baseinstance)
12117ec681f3Smrg{
12127ec681f3Smrg   draw_elements(mode, count, type, indices, instance_count, basevertex, baseinstance, false, 0, 0, false);
12137ec681f3Smrg}
12147ec681f3Smrg
12157ec681f3Smrgvoid GLAPIENTRY
12167ec681f3Smrg_mesa_marshal_MultiDrawElementsEXT(GLenum mode, const GLsizei *count,
12177ec681f3Smrg                                   GLenum type, const GLvoid *const *indices,
12187ec681f3Smrg                                   GLsizei draw_count)
12197ec681f3Smrg{
12207ec681f3Smrg   _mesa_marshal_MultiDrawElementsBaseVertex(mode, count, type, indices,
12217ec681f3Smrg                                             draw_count, NULL);
12227ec681f3Smrg}
12237ec681f3Smrg
12247ec681f3Smrguint32_t
12257ec681f3Smrg_mesa_unmarshal_DrawArraysInstancedARB(struct gl_context *ctx, const struct marshal_cmd_DrawArraysInstancedARB *cmd, const uint64_t *last)
12267ec681f3Smrg{
12277ec681f3Smrg   unreachable("never used - DrawArraysInstancedBaseInstance is used instead");
12287ec681f3Smrg   return 0;
12297ec681f3Smrg}
12307ec681f3Smrg
12317ec681f3Smrguint32_t
12327ec681f3Smrg_mesa_unmarshal_DrawElements(struct gl_context *ctx, const struct marshal_cmd_DrawElements *cmd, const uint64_t *last)
12337ec681f3Smrg{
12347ec681f3Smrg   unreachable("never used - DrawElementsInstancedBaseVertexBaseInstance is used instead");
12357ec681f3Smrg   return 0;
12367ec681f3Smrg}
12377ec681f3Smrg
12387ec681f3Smrguint32_t
12397ec681f3Smrg_mesa_unmarshal_DrawRangeElements(struct gl_context *ctx, const struct marshal_cmd_DrawRangeElements *cmd, const uint64_t *last)
12407ec681f3Smrg{
12417ec681f3Smrg   unreachable("never used - DrawElementsInstancedBaseVertexBaseInstance is used instead");
12427ec681f3Smrg   return 0;
12437ec681f3Smrg}
12447ec681f3Smrg
12457ec681f3Smrguint32_t
12467ec681f3Smrg_mesa_unmarshal_DrawElementsBaseVertex(struct gl_context *ctx, const struct marshal_cmd_DrawElementsBaseVertex *cmd, const uint64_t *last)
12477ec681f3Smrg{
12487ec681f3Smrg   unreachable("never used - DrawElementsInstancedBaseVertexBaseInstance is used instead");
12497ec681f3Smrg   return 0;
12507ec681f3Smrg}
12517ec681f3Smrg
12527ec681f3Smrguint32_t
12537ec681f3Smrg_mesa_unmarshal_DrawElementsInstancedBaseVertex(struct gl_context *ctx, const struct marshal_cmd_DrawElementsInstancedBaseVertex *cmd, const uint64_t *last)
12547ec681f3Smrg{
12557ec681f3Smrg   unreachable("never used - DrawElementsInstancedBaseVertexBaseInstance is used instead");
12567ec681f3Smrg   return 0;
12577ec681f3Smrg}
12587ec681f3Smrg
12597ec681f3Smrguint32_t
12607ec681f3Smrg_mesa_unmarshal_DrawElementsInstancedBaseInstance(struct gl_context *ctx, const struct marshal_cmd_DrawElementsInstancedBaseInstance *cmd, const uint64_t *last)
12617ec681f3Smrg{
12627ec681f3Smrg   unreachable("never used - DrawElementsInstancedBaseVertexBaseInstance is used instead");
12637ec681f3Smrg   return 0;
12647ec681f3Smrg}
12657ec681f3Smrg
12667ec681f3Smrguint32_t
12677ec681f3Smrg_mesa_unmarshal_MultiDrawElementsEXT(struct gl_context *ctx, const struct marshal_cmd_MultiDrawElementsEXT *cmd, const uint64_t *last)
12687ec681f3Smrg{
12697ec681f3Smrg   unreachable("never used - MultiDrawElementsBaseVertex is used instead");
12707ec681f3Smrg   return 0;
12717ec681f3Smrg}
1272