Module: Mesa
Branch: main
Commit: ed7d3b33b0fb5f6ee49e236f5a8b0c3a021df027
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=ed7d3b33b0fb5f6ee49e236f5a8b0c3a021df027

Author: Marek Olšák <[email protected]>
Date:   Mon Dec 12 23:31:16 2022 -0500

glthread: change multi_draw_elements_async() to never fail due to large size

Some callers (not visible here) silently ignore the return value. Remove
the return value and handle the failure in multi_draw_elements_async.

Reviewed-by: Pierre-Eric Pelloux-Prayer <[email protected]>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/20824>

---

 src/mesa/main/glthread_draw.c | 85 ++++++++++++++++++++++++++++---------------
 1 file changed, 56 insertions(+), 29 deletions(-)

diff --git a/src/mesa/main/glthread_draw.c b/src/mesa/main/glthread_draw.c
index f467f4a4fa3..8907047906d 100644
--- a/src/mesa/main/glthread_draw.c
+++ b/src/mesa/main/glthread_draw.c
@@ -1074,7 +1074,7 @@ _mesa_unmarshal_MultiDrawElementsUserBuf(struct 
gl_context *ctx,
    return cmd->cmd_base.cmd_size;
 }
 
-static ALWAYS_INLINE bool
+static void
 multi_draw_elements_async(struct gl_context *ctx, GLenum mode,
                           const GLsizei *count, GLenum type,
                           const GLvoid *const *indices, GLsizei draw_count,
@@ -1092,33 +1092,61 @@ multi_draw_elements_async(struct gl_context *ctx, 
GLenum mode,
    struct marshal_cmd_MultiDrawElementsUserBuf *cmd;
 
    /* Make sure cmd can fit the queue buffer */
-   if (cmd_size > MARSHAL_MAX_CMD_SIZE) {
-      return false;
-   }
+   if (cmd_size <= MARSHAL_MAX_CMD_SIZE) {
+      cmd = _mesa_glthread_allocate_command(ctx, 
DISPATCH_CMD_MultiDrawElementsUserBuf, cmd_size);
+      cmd->mode = MIN2(mode, 0xff); /* primitive types go from 0 to 14 */
+      cmd->type = MIN2(type, 0xffff);
+      cmd->draw_count = draw_count;
+      cmd->user_buffer_mask = user_buffer_mask;
+      cmd->index_buffer = index_buffer;
+      cmd->has_base_vertex = basevertex != NULL;
+
+      char *variable_data = (char*)(cmd + 1);
+      memcpy(variable_data, count, count_size);
+      variable_data += count_size;
+      memcpy(variable_data, indices, indices_size);
+      variable_data += indices_size;
 
-   cmd = _mesa_glthread_allocate_command(ctx, 
DISPATCH_CMD_MultiDrawElementsUserBuf, cmd_size);
-   cmd->mode = MIN2(mode, 0xff); /* primitive types go from 0 to 14 */
-   cmd->type = MIN2(type, 0xffff);
-   cmd->draw_count = draw_count;
-   cmd->user_buffer_mask = user_buffer_mask;
-   cmd->index_buffer = index_buffer;
-   cmd->has_base_vertex = basevertex != NULL;
+      if (basevertex) {
+         memcpy(variable_data, basevertex, basevertex_size);
+         variable_data += basevertex_size;
+      }
 
-   char *variable_data = (char*)(cmd + 1);
-   memcpy(variable_data, count, count_size);
-   variable_data += count_size;
-   memcpy(variable_data, indices, indices_size);
-   variable_data += indices_size;
+      if (user_buffer_mask)
+         memcpy(variable_data, buffers, buffers_size);
+   } else {
+      /* The call is too large, so sync and execute the unmarshal code here. */
+      _mesa_glthread_finish_before(ctx, "DrawElements");
 
-   if (basevertex) {
-      memcpy(variable_data, basevertex, basevertex_size);
-      variable_data += basevertex_size;
-   }
+      /* Bind uploaded buffers if needed. */
+      if (user_buffer_mask) {
+         _mesa_InternalBindVertexBuffers(ctx, buffers, user_buffer_mask,
+                                         false);
+      }
+      if (index_buffer) {
+         _mesa_InternalBindElementBuffer(ctx, index_buffer);
+      }
 
-   if (user_buffer_mask)
-      memcpy(variable_data, buffers, buffers_size);
+      /* Draw. */
+      if (basevertex != NULL) {
+         CALL_MultiDrawElementsBaseVertex(ctx->CurrentServerDispatch,
+                                          (mode, count, type, indices, 
draw_count,
+                                           basevertex));
+      } else {
+         CALL_MultiDrawElements(ctx->CurrentServerDispatch,
+                                (mode, count, type, indices, draw_count));
+      }
 
-   return true;
+      /* Restore states. */
+      /* TODO: remove this after glthread takes over all uploading */
+      if (index_buffer) {
+         _mesa_InternalBindElementBuffer(ctx, NULL);
+      }
+      if (user_buffer_mask) {
+         _mesa_InternalBindVertexBuffers(ctx, buffers, user_buffer_mask,
+                                         true);
+      }
+   }
 }
 
 void GLAPIENTRY
@@ -1142,21 +1170,20 @@ _mesa_marshal_MultiDrawElementsBaseVertex(GLenum mode, 
const GLsizei *count,
        (ctx->API == API_OPENGL_CORE ||
         !is_index_type_valid(type) ||
         (!user_buffer_mask && !has_user_indices))) {
-      if (multi_draw_elements_async(ctx, mode, count, type, indices,
-                              draw_count, basevertex, NULL, 0, NULL))
-         return;
+      multi_draw_elements_async(ctx, mode, count, type, indices,
+                                draw_count, basevertex, NULL, 0, NULL);
+      return;
    }
 
    bool need_index_bounds = user_buffer_mask & ~vao->NonZeroDivisorMask;
 
-   /* If the draw count is too high or negative, the queue can't be used.
+   /* If the draw count is negative, the queue can't be used.
     *
     * Sync if indices come from a buffer and vertices come from memory
     * and index bounds are not valid. We would have to map the indices
     * to compute the index bounds, and for that we would have to sync anyway.
     */
-   if (!ctx->GLThread.SupportsBufferUploads ||
-       draw_count < 0 || draw_count > MARSHAL_MAX_CMD_SIZE / 32 ||
+   if (!ctx->GLThread.SupportsBufferUploads || draw_count < 0 ||
        (need_index_bounds && !has_user_indices))
       goto sync;
 

Reply via email to