glthread: add custom marshalling for glNamedBuffer(Sub)DataEXT
[mesa.git] / src / mesa / main / marshal.c
index b01c07399720f20d5a544e70a488a5d32e4efbb9..9c9d67208784e3a2c613f853daa3e6c8c4287f7b 100644 (file)
 #include "main/macros.h"
 #include "marshal.h"
 #include "dispatch.h"
-#include "marshal_generated.h"
 
-#ifdef HAVE_PTHREAD
-
-struct marshal_cmd_Flush
-{
-   struct marshal_cmd_base cmd_base;
-};
-
-
-void
-_mesa_unmarshal_Flush(struct gl_context *ctx,
-                      const struct marshal_cmd_Flush *cmd)
-{
-   CALL_Flush(ctx->CurrentServerDispatch, ());
-}
-
-
-void GLAPIENTRY
-_mesa_marshal_Flush(void)
+static inline void
+_mesa_post_marshal_hook(struct gl_context *ctx)
 {
-   GET_CURRENT_CONTEXT(ctx);
-   struct marshal_cmd_Flush *cmd =
-      _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_Flush,
-                                      sizeof(struct marshal_cmd_Flush));
-   (void) cmd;
-   _mesa_post_marshal_hook(ctx);
-
-   /* Flush() needs to be handled specially.  In addition to telling the
-    * background thread to flush, we need to ensure that our own buffer is
-    * submitted to the background thread so that it will complete in a finite
-    * amount of time.
+   /* This can be enabled for debugging whether a failure is a synchronization
+    * problem between the main thread and the worker thread, or a failure in
+    * how we actually marshal.
     */
-   _mesa_glthread_flush_batch(ctx);
+   if (false)
+      _mesa_glthread_finish(ctx);
 }
 
 
@@ -95,7 +71,7 @@ _mesa_unmarshal_ShaderSource(struct gl_context *ctx,
    }
    CALL_ShaderSource(ctx->CurrentServerDispatch,
                      (cmd->shader, cmd->count, string, cmd_length));
-   free(string);
+   free((void *)string);
 }
 
 
@@ -160,23 +136,6 @@ _mesa_marshal_ShaderSource(GLuint shader, GLsizei count,
 }
 
 
-/* BindBufferBase: marshalled asynchronously */
-struct marshal_cmd_BindBufferBase
-{
-   struct marshal_cmd_base cmd_base;
-   GLenum target;
-   GLuint index;
-   GLuint buffer;
-};
-static inline void
-_mesa_unmarshal_BindBufferBase(struct gl_context *ctx, const struct marshal_cmd_BindBufferBase *cmd)
-{
-   const GLenum target = cmd->target;
-   const GLuint index = cmd->index;
-   const GLuint buffer = cmd->buffer;
-   CALL_BindBufferBase(ctx->CurrentServerDispatch, (target, index, buffer));
-}
-
 /** Tracks the current bindings for the vertex array and index array buffers.
  *
  * This is part of what we need to enable glthread on compat-GL contexts that
@@ -200,8 +159,8 @@ _mesa_unmarshal_BindBufferBase(struct gl_context *ctx, const struct marshal_cmd_
  * feature that if you pass a bad name, it just gens a buffer object for you,
  * so we escape without having to know if things are valid or not.
  */
-static void
-track_vbo_binding(struct gl_context *ctx, GLenum target, GLuint buffer)
+void
+_mesa_glthread_BindBuffer(struct gl_context *ctx, GLenum target, GLuint buffer)
 {
    struct glthread_state *glthread = ctx->GLThread;
 
@@ -214,61 +173,26 @@ track_vbo_binding(struct gl_context *ctx, GLenum target, GLuint buffer)
        * vertex array object instead of the context, so this would need to
        * change on vertex array object updates.
        */
-      glthread->element_array_is_vbo = (buffer != 0);
+      glthread->CurrentVAO->IndexBufferIsUserPointer = buffer != 0;
+      break;
+   case GL_DRAW_INDIRECT_BUFFER:
+      glthread->draw_indirect_buffer_is_vbo = buffer != 0;
       break;
    }
 }
 
 
-struct marshal_cmd_BindBuffer
-{
-   struct marshal_cmd_base cmd_base;
-   GLenum target;
-   GLuint buffer;
-};
-
-/**
- * This is just like the code-generated glBindBuffer() support, except that we
- * call track_vbo_binding().
- */
-void
-_mesa_unmarshal_BindBuffer(struct gl_context *ctx,
-                           const struct marshal_cmd_BindBuffer *cmd)
-{
-   const GLenum target = cmd->target;
-   const GLuint buffer = cmd->buffer;
-   CALL_BindBuffer(ctx->CurrentServerDispatch, (target, buffer));
-}
-void GLAPIENTRY
-_mesa_marshal_BindBuffer(GLenum target, GLuint buffer)
-{
-   GET_CURRENT_CONTEXT(ctx);
-   size_t cmd_size = sizeof(struct marshal_cmd_BindBuffer);
-   struct marshal_cmd_BindBuffer *cmd;
-   debug_print_marshal("BindBuffer");
-
-   track_vbo_binding(ctx, target, buffer);
-
-   if (cmd_size <= MARSHAL_MAX_CMD_SIZE) {
-      cmd = _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_BindBuffer,
-                                            cmd_size);
-      cmd->target = target;
-      cmd->buffer = buffer;
-      _mesa_post_marshal_hook(ctx);
-   } else {
-      _mesa_glthread_finish(ctx);
-      CALL_BindBuffer(ctx->CurrentServerDispatch, (target, buffer));
-   }
-}
-
 /* BufferData: marshalled asynchronously */
 struct marshal_cmd_BufferData
 {
    struct marshal_cmd_base cmd_base;
-   GLenum target;
+   GLuint target_or_name;
    GLsizeiptr size;
    GLenum usage;
+   const GLvoid *data_external_mem;
    bool data_null; /* If set, no data follows for "data" */
+   bool named;
+   bool ext_dsa;
    /* Next size bytes are GLubyte data[size] */
 };
 
@@ -276,63 +200,123 @@ void
 _mesa_unmarshal_BufferData(struct gl_context *ctx,
                            const struct marshal_cmd_BufferData *cmd)
 {
-   const GLenum target = cmd->target;
-   const GLsizeiptr size = cmd->size;
+   const GLuint target_or_name = cmd->target_or_name;
+   const GLsizei size = cmd->size;
    const GLenum usage = cmd->usage;
    const void *data;
 
    if (cmd->data_null)
       data = NULL;
+   else if (!cmd->named && target_or_name == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD)
+      data = cmd->data_external_mem;
    else
       data = (const void *) (cmd + 1);
 
-   CALL_BufferData(ctx->CurrentServerDispatch, (target, size, data, usage));
+   if (cmd->ext_dsa) {
+      CALL_NamedBufferDataEXT(ctx->CurrentServerDispatch,
+                              (target_or_name, size, data, usage));
+   } else if (cmd->named) {
+      CALL_NamedBufferData(ctx->CurrentServerDispatch,
+                           (target_or_name, size, data, usage));
+   } else {
+      CALL_BufferData(ctx->CurrentServerDispatch,
+                      (target_or_name, size, data, usage));
+   }
 }
 
-void GLAPIENTRY
-_mesa_marshal_BufferData(GLenum target, GLsizeiptr size, const GLvoid * data,
-                         GLenum usage)
+void
+_mesa_unmarshal_NamedBufferData(struct gl_context *ctx,
+                                const struct marshal_cmd_BufferData *cmd)
+{
+   unreachable("never used - all BufferData variants use DISPATCH_CMD_BufferData");
+}
+
+void
+_mesa_unmarshal_NamedBufferDataEXT(struct gl_context *ctx,
+                                   const struct marshal_cmd_BufferData *cmd)
+{
+   unreachable("never used - all BufferData variants use DISPATCH_CMD_BufferData");
+}
+
+static void
+_mesa_marshal_BufferData_merged(GLuint target_or_name, GLsizeiptr size,
+                                const GLvoid *data, GLenum usage, bool named,
+                                bool ext_dsa, const char *func)
 {
    GET_CURRENT_CONTEXT(ctx);
-   size_t cmd_size =
-      sizeof(struct marshal_cmd_BufferData) + (data ? size : 0);
+   bool external_mem = !named &&
+                       target_or_name == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD;
+   bool copy_data = data && !external_mem;
+   int cmd_size = sizeof(struct marshal_cmd_BufferData) + (copy_data ? size : 0);
    debug_print_marshal("BufferData");
 
-   if (unlikely(size < 0)) {
-      _mesa_glthread_finish(ctx);
-      _mesa_error(ctx, GL_INVALID_VALUE, "BufferData(size < 0)");
+   if (unlikely(size < 0 || size > INT_MAX || cmd_size < 0 ||
+                cmd_size > MARSHAL_MAX_CMD_SIZE ||
+                (named && target_or_name == 0))) {
+      _mesa_glthread_finish_before(ctx, func);
+      if (named) {
+         CALL_NamedBufferData(ctx->CurrentServerDispatch,
+                              (target_or_name, size, data, usage));
+      } else {
+         CALL_BufferData(ctx->CurrentServerDispatch,
+                         (target_or_name, size, data, usage));
+      }
       return;
    }
 
-   if (target != GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD &&
-       cmd_size <= MARSHAL_MAX_CMD_SIZE) {
-      struct marshal_cmd_BufferData *cmd =
-         _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_BufferData,
-                                         cmd_size);
-
-      cmd->target = target;
-      cmd->size = size;
-      cmd->usage = usage;
-      cmd->data_null = !data;
-      if (data) {
-         char *variable_data = (char *) (cmd + 1);
-         memcpy(variable_data, data, size);
-      }
-      _mesa_post_marshal_hook(ctx);
-   } else {
-      _mesa_glthread_finish(ctx);
-      CALL_BufferData(ctx->CurrentServerDispatch,
-                      (target, size, data, usage));
+   struct marshal_cmd_BufferData *cmd =
+      _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_BufferData,
+                                      cmd_size);
+
+   cmd->target_or_name = target_or_name;
+   cmd->size = size;
+   cmd->usage = usage;
+   cmd->data_null = !data;
+   cmd->named = named;
+   cmd->ext_dsa = ext_dsa;
+   cmd->data_external_mem = data;
+
+   if (copy_data) {
+      char *variable_data = (char *) (cmd + 1);
+      memcpy(variable_data, data, size);
    }
+   _mesa_post_marshal_hook(ctx);
+}
+
+void GLAPIENTRY
+_mesa_marshal_BufferData(GLenum target, GLsizeiptr size, const GLvoid * data,
+                         GLenum usage)
+{
+   _mesa_marshal_BufferData_merged(target, size, data, usage, false, false,
+                                   "BufferData");
 }
 
+void GLAPIENTRY
+_mesa_marshal_NamedBufferData(GLuint buffer, GLsizeiptr size,
+                              const GLvoid * data, GLenum usage)
+{
+   _mesa_marshal_BufferData_merged(buffer, size, data, usage, true, false,
+                                   "NamedBufferData");
+}
+
+void GLAPIENTRY
+_mesa_marshal_NamedBufferDataEXT(GLuint buffer, GLsizeiptr size,
+                                 const GLvoid *data, GLenum usage)
+{
+   _mesa_marshal_BufferData_merged(buffer, size, data, usage, true, true,
+                                   "NamedBufferDataEXT");
+}
+
+
 /* BufferSubData: marshalled asynchronously */
 struct marshal_cmd_BufferSubData
 {
    struct marshal_cmd_base cmd_base;
-   GLenum target;
+   GLenum target_or_name;
    GLintptr offset;
    GLsizeiptr size;
+   bool named;
+   bool ext_dsa;
    /* Next size bytes are GLubyte data[size] */
 };
 
@@ -340,117 +324,94 @@ void
 _mesa_unmarshal_BufferSubData(struct gl_context *ctx,
                               const struct marshal_cmd_BufferSubData *cmd)
 {
-   const GLenum target = cmd->target;
+   const GLenum target_or_name = cmd->target_or_name;
    const GLintptr offset = cmd->offset;
    const GLsizeiptr size = cmd->size;
    const void *data = (const void *) (cmd + 1);
 
-   CALL_BufferSubData(ctx->CurrentServerDispatch,
-                      (target, offset, size, data));
-}
-
-void GLAPIENTRY
-_mesa_marshal_BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size,
-                            const GLvoid * data)
-{
-   GET_CURRENT_CONTEXT(ctx);
-   size_t cmd_size = sizeof(struct marshal_cmd_BufferSubData) + size;
-
-   debug_print_marshal("BufferSubData");
-   if (unlikely(size < 0)) {
-      _mesa_glthread_finish(ctx);
-      _mesa_error(ctx, GL_INVALID_VALUE, "BufferSubData(size < 0)");
-      return;
-   }
-
-   if (target != GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD &&
-       cmd_size <= MARSHAL_MAX_CMD_SIZE) {
-      struct marshal_cmd_BufferSubData *cmd =
-         _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_BufferSubData,
-                                         cmd_size);
-      cmd->target = target;
-      cmd->offset = offset;
-      cmd->size = size;
-      char *variable_data = (char *) (cmd + 1);
-      memcpy(variable_data, data, size);
-      _mesa_post_marshal_hook(ctx);
+   if (cmd->ext_dsa) {
+      CALL_NamedBufferSubDataEXT(ctx->CurrentServerDispatch,
+                                 (target_or_name, offset, size, data));
+   } else if (cmd->named) {
+      CALL_NamedBufferSubData(ctx->CurrentServerDispatch,
+                              (target_or_name, offset, size, data));
    } else {
-      _mesa_glthread_finish(ctx);
       CALL_BufferSubData(ctx->CurrentServerDispatch,
-                         (target, offset, size, data));
+                         (target_or_name, offset, size, data));
    }
 }
 
-/* ClearBufferfv: marshalled asynchronously */
-struct marshal_cmd_ClearBufferfv
+void
+_mesa_unmarshal_NamedBufferSubData(struct gl_context *ctx,
+                                   const struct marshal_cmd_BufferSubData *cmd)
 {
-   struct marshal_cmd_base cmd_base;
-   GLenum buffer;
-   GLint drawbuffer;
-};
+   unreachable("never used - all BufferSubData variants use DISPATCH_CMD_BufferSubData");
+}
 
 void
-_mesa_unmarshal_ClearBufferfv(struct gl_context *ctx,
-                              const struct marshal_cmd_ClearBufferfv *cmd)
+_mesa_unmarshal_NamedBufferSubDataEXT(struct gl_context *ctx,
+                                      const struct marshal_cmd_BufferSubData *cmd)
 {
-   const GLenum buffer = cmd->buffer;
-   const GLint drawbuffer = cmd->drawbuffer;
-   const char *variable_data = (const char *) (cmd + 1);
-   const GLfloat *value = (const GLfloat *) variable_data;
-
-   CALL_ClearBufferfv(ctx->CurrentServerDispatch,
-                      (buffer, drawbuffer, value));
+   unreachable("never used - all BufferSubData variants use DISPATCH_CMD_BufferSubData");
 }
 
-void GLAPIENTRY
-_mesa_marshal_ClearBufferfv(GLenum buffer, GLint drawbuffer,
-                            const GLfloat *value)
+static void
+_mesa_marshal_BufferSubData_merged(GLuint target_or_name, GLintptr offset,
+                                   GLsizeiptr size, const GLvoid *data,
+                                   bool named, bool ext_dsa, const char *func)
 {
    GET_CURRENT_CONTEXT(ctx);
-   debug_print_marshal("ClearBufferfv");
-
-   size_t size;
-   switch (buffer) {
-   case GL_DEPTH:
-      size = sizeof(GLfloat);
-      break;
-   case GL_COLOR:
-      size = sizeof(GLfloat) * 4;
-      break;
-   default:
-      _mesa_glthread_finish(ctx);
-
-      /* Page 498 of the PDF, section '17.4.3.1 Clearing Individual Buffers'
-       * of the OpenGL 4.5 spec states:
-       *
-       *    "An INVALID_ENUM error is generated by ClearBufferfv and
-       *     ClearNamedFramebufferfv if buffer is not COLOR or DEPTH."
-       */
-      _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferfv(buffer=%s)",
-                  _mesa_enum_to_string(buffer));
+   size_t cmd_size = sizeof(struct marshal_cmd_BufferSubData) + size;
+   debug_print_marshal(func);
+
+   if (unlikely(size < 0 || size > INT_MAX || cmd_size < 0 ||
+                cmd_size > MARSHAL_MAX_CMD_SIZE || !data ||
+                (named && target_or_name == 0))) {
+      _mesa_glthread_finish_before(ctx, func);
+      if (named) {
+         CALL_NamedBufferSubData(ctx->CurrentServerDispatch,
+                                 (target_or_name, offset, size, data));
+      } else {
+         CALL_BufferSubData(ctx->CurrentServerDispatch,
+                            (target_or_name, offset, size, data));
+      }
       return;
    }
 
-   size_t cmd_size = sizeof(struct marshal_cmd_ClearBufferfv) + size;
-   if (cmd_size <= MARSHAL_MAX_CMD_SIZE) {
-      struct marshal_cmd_ClearBufferfv *cmd =
-         _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_ClearBufferfv,
-                                         cmd_size);
-      cmd->buffer = buffer;
-      cmd->drawbuffer = drawbuffer;
-      GLfloat *variable_data = (GLfloat *) (cmd + 1);
-      if (buffer == GL_COLOR)
-         COPY_4V(variable_data, value);
-      else
-         *variable_data = *value;
+   struct marshal_cmd_BufferSubData *cmd =
+      _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_BufferSubData,
+                                      cmd_size);
+   cmd->target_or_name = target_or_name;
+   cmd->offset = offset;
+   cmd->size = size;
+   cmd->named = named;
+   cmd->ext_dsa = ext_dsa;
+
+   char *variable_data = (char *) (cmd + 1);
+   memcpy(variable_data, data, size);
+   _mesa_post_marshal_hook(ctx);
+}
 
-      _mesa_post_marshal_hook(ctx);
-   } else {
-      debug_print_sync("ClearBufferfv");
-      _mesa_glthread_finish(ctx);
-      CALL_ClearBufferfv(ctx->CurrentServerDispatch,
-                         (buffer, drawbuffer, value));
-   }
+void GLAPIENTRY
+_mesa_marshal_BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size,
+                            const GLvoid * data)
+{
+   _mesa_marshal_BufferSubData_merged(target, offset, size, data, false,
+                                      false, "BufferSubData");
+}
+
+void GLAPIENTRY
+_mesa_marshal_NamedBufferSubData(GLuint buffer, GLintptr offset,
+                                 GLsizeiptr size, const GLvoid * data)
+{
+   _mesa_marshal_BufferSubData_merged(buffer, offset, size, data, true,
+                                      false, "NamedBufferSubData");
 }
 
-#endif
+void GLAPIENTRY
+_mesa_marshal_NamedBufferSubDataEXT(GLuint buffer, GLintptr offset,
+                                    GLsizeiptr size, const GLvoid * data)
+{
+   _mesa_marshal_BufferSubData_merged(buffer, offset, size, data, true,
+                                      true, "NamedBufferSubDataEXT");
+}