<div dir="auto">Hello Fredrik,<div dir="auto"><br></div><div dir="auto">Yes the shadow hash feels useless now. I will update the patch in a couple of days (vacation currently).</div><div dir="auto"><br></div><div dir="auto">Cheers,</div><div dir="auto">Gregory</div></div><div class="gmail_extra"><br><div class="gmail_quote">Le 22 juin 2017 2:24 PM, "Fredrik Höglund" <<a href="mailto:fredrik@kde.org">fredrik@kde.org</a>> a écrit :<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On Thursday 22 June 2017, Timothy Arceri wrote:<br>
> From: Gregory Hainaut <<a href="mailto:gregory.hainaut@gmail.com">gregory.hainaut@gmail.com</a>><br>
><br>
> It would be used in next commit to allow asynchronous PBO transfer.<br>
><br>
> The tracking saves the buffer name into a hash. Saving pointer<br>
> will be more complex as the buffer is created in BindBuffer due to IsBuffer<br>
> insanity.<br>
><br>
> Perf wise DeleteBuffers is now synchronous for robustness.<br>
><br>
> v5: properly delete hash element with the help of _mesa_HashDeleteAll<br>
><br>
> v6: rebase<br>
> Signed-off-by: Gregory Hainaut <<a href="mailto:gregory.hainaut@gmail.com">gregory.hainaut@gmail.com</a>><br>
> ---<br>
>  src/mapi/glapi/gen/ARB_direct_<wbr>state_access.xml |   2 +-<br>
>  src/mapi/glapi/gen/gl_API.xml                  |   4 +-<br>
>  src/mesa/main/glthread.h                       |  10 +++<br>
>  src/mesa/main/marshal.c                        | 113 +++++++++++++++++++++++++<br>
>  src/mesa/main/marshal.h                        |  24 ++++++<br>
>  src/mesa/main/mtypes.h                         |   5 ++<br>
>  src/mesa/main/shared.c                         |  14 +++<br>
>  7 files changed, 169 insertions(+), 3 deletions(-)<br>
><br>
> diff --git a/src/mapi/glapi/gen/ARB_<wbr>direct_state_access.xml b/src/mapi/glapi/gen/ARB_<wbr>direct_state_access.xml<br>
> index cb24d79..b75c772a 100644<br>
> --- a/src/mapi/glapi/gen/ARB_<wbr>direct_state_access.xml<br>
> +++ b/src/mapi/glapi/gen/ARB_<wbr>direct_state_access.xml<br>
> @@ -42,21 +42,21 @@<br>
><br>
>     <function name="GetTransformFeedbacki64_<wbr>v"><br>
>        <param name="xfb" type="GLuint" /><br>
>        <param name="pname" type="GLenum" /><br>
>        <param name="index" type="GLuint" /><br>
>        <param name="param" type="GLint64 *" /><br>
>     </function><br>
><br>
>     <!-- Buffer object functions --><br>
><br>
> -   <function name="CreateBuffers"><br>
> +   <function name="CreateBuffers" marshal="custom"><br>
>        <param name="n" type="GLsizei" /><br>
>        <param name="buffers" type="GLuint *" /><br>
>     </function><br>
><br>
>     <function name="NamedBufferStorage" no_error="true"><br>
>        <param name="buffer" type="GLuint" /><br>
>        <param name="size" type="GLsizeiptr" /><br>
>        <param name="data" type="const GLvoid *" /><br>
>        <param name="flags" type="GLbitfield" /><br>
>     </function><br>
> diff --git a/src/mapi/glapi/gen/gl_API.<wbr>xml b/src/mapi/glapi/gen/gl_API.<wbr>xml<br>
> index 8784f05..aa34c04 100644<br>
> --- a/src/mapi/glapi/gen/gl_API.<wbr>xml<br>
> +++ b/src/mapi/glapi/gen/gl_API.<wbr>xml<br>
> @@ -5053,27 +5053,27 @@<br>
><br>
>      <function name="BufferSubData" es1="1.1" es2="2.0" marshal="custom"<br>
>                no_error="true"><br>
>          <param name="target" type="GLenum"/><br>
>          <param name="offset" type="GLintptr"/><br>
>          <param name="size" type="GLsizeiptr" counter="true"/><br>
>          <param name="data" type="const GLvoid *" count="size"/><br>
>          <glx ignore="true"/><br>
>      </function><br>
><br>
> -    <function name="DeleteBuffers" es1="1.1" es2="2.0"><br>
> +    <function name="DeleteBuffers" es1="1.1" es2="2.0" marshal="custom"><br>
>          <param name="n" type="GLsizei" counter="true"/><br>
>          <param name="buffer" type="const GLuint *" count="n"/><br>
>          <glx ignore="true"/><br>
>      </function><br>
><br>
> -    <function name="GenBuffers" es1="1.1" es2="2.0"><br>
> +    <function name="GenBuffers" es1="1.1" es2="2.0" marshal="custom"><br>
>          <param name="n" type="GLsizei" counter="true"/><br>
>          <param name="buffer" type="GLuint *" output="true" count="n"/><br>
>          <glx ignore="true"/><br>
>      </function><br>
><br>
>      <function name="GetBufferParameteriv" es1="1.1" es2="2.0"><br>
>          <param name="target" type="GLenum"/><br>
>          <param name="pname" type="GLenum"/><br>
>          <param name="params" type="GLint *" output="true" variable_param="pname"/><br>
>          <glx ignore="true"/><br>
> diff --git a/src/mesa/main/glthread.h b/src/mesa/main/glthread.h<br>
> index dd65931..351be6c 100644<br>
> --- a/src/mesa/main/glthread.h<br>
> +++ b/src/mesa/main/glthread.h<br>
> @@ -89,20 +89,30 @@ struct glthread_state<br>
>      * Tracks on the main thread side whether the current vertex array binding<br>
>      * is in a VBO.<br>
>      */<br>
>     bool vertex_array_is_vbo;<br>
><br>
>     /**<br>
>      * Tracks on the main thread side whether the current element array (index<br>
>      * buffer) binding is in a VBO.<br>
>      */<br>
>     bool element_array_is_vbo;<br>
> +<br>
> +   /**<br>
> +    * Tracks on the main thread side the bound unpack pixel buffer<br>
> +    */<br>
> +   GLint pixel_unpack_buffer_bound;<br>
> +<br>
> +   /**<br>
> +    * Tracks on the main thread side the bound pack pixel buffer<br>
> +    */<br>
> +   GLint pixel_pack_buffer_bound;<br>
>  };<br>
<br>
I suggest naming these bound_pixel_unpack_buffer and<br>
bound_pixel_pack_buffer, respectively.  The name pixel_pack_buffer_bound<br>
suggests that this is a boolean value.<br>
<br>
The type should also be GLuint.<br>
<br>
One more comment below:<br>
<br>
><br>
>  void _mesa_glthread_init(struct gl_context *ctx);<br>
>  void _mesa_glthread_destroy(struct gl_context *ctx);<br>
><br>
>  void _mesa_glthread_restore_<wbr>dispatch(struct gl_context *ctx);<br>
>  void _mesa_glthread_flush_batch(<wbr>struct gl_context *ctx);<br>
>  void _mesa_glthread_finish(struct gl_context *ctx);<br>
><br>
>  #endif /* _GLTHREAD_H*/<br>
> diff --git a/src/mesa/main/marshal.c b/src/mesa/main/marshal.c<br>
> index 4840f32..b1731ab 100644<br>
> --- a/src/mesa/main/marshal.c<br>
> +++ b/src/mesa/main/marshal.c<br>
> @@ -25,20 +25,21 @@<br>
>   *<br>
>   * Custom functions for marshalling GL calls from the main thread to a worker<br>
>   * thread when automatic code generation isn't appropriate.<br>
>   */<br>
><br>
>  #include "main/enums.h"<br>
>  #include "main/macros.h"<br>
>  #include "marshal.h"<br>
>  #include "dispatch.h"<br>
>  #include "marshal_generated.h"<br>
> +#include "hash.h"<br>
><br>
>  struct marshal_cmd_Flush<br>
>  {<br>
>     struct marshal_cmd_base cmd_base;<br>
>  };<br>
><br>
><br>
>  void<br>
>  _mesa_unmarshal_Flush(struct gl_context *ctx,<br>
>                        const struct marshal_cmd_Flush *cmd)<br>
> @@ -187,20 +188,132 @@ _mesa_marshal_ShaderSource(<wbr>GLuint shader, GLsizei count,<br>
>        }<br>
>        _mesa_post_marshal_hook(ctx);<br>
>     } else {<br>
>        _mesa_glthread_finish(ctx);<br>
>        CALL_ShaderSource(ctx-><wbr>CurrentServerDispatch,<br>
>                          (shader, count, string, length_tmp));<br>
>     }<br>
>     free(length_tmp);<br>
>  }<br>
><br>
> +/**<br>
> + * Used as a placeholder for track_buffers_creation/track_<wbr>buffers_destruction<br>
> + * so we know if buffer really exists in track_buffers_binding.<br>
> + */<br>
> +static struct gl_buffer_object DummyBufferObject;<br>
> +<br>
> +static void track_buffers_creation(GLsizei n, GLuint * buffers)<br>
> +{<br>
> +   GET_CURRENT_CONTEXT(ctx);<br>
> +   GLsizei i;<br>
> +<br>
> +   if (n < 0 || !buffers)<br>
> +      return;<br>
> +<br>
> +   _mesa_HashLockMutex(ctx-><wbr>Shared->ShadowBufferObjects);<br>
> +<br>
> +   for (i = 0; i < n ; i++) {<br>
> +      _mesa_HashInsertLocked(ctx-><wbr>Shared->ShadowBufferObjects, buffers[i],<br>
> +            &DummyBufferObject);<br>
> +   }<br>
> +<br>
> +   _mesa_HashUnlockMutex(ctx-><wbr>Shared->ShadowBufferObjects);<br>
> +}<br>
> +<br>
> +static void track_buffers_destruction(<wbr>GLsizei n, const GLuint * buffers)<br>
> +{<br>
> +   GET_CURRENT_CONTEXT(ctx);<br>
> +   GLsizei i;<br>
> +   struct glthread_state *glthread = ctx->GLThread;<br>
> +<br>
> +   if (n < 0 || !buffers)<br>
> +      return;<br>
> +<br>
> +   _mesa_HashLockMutex(ctx-><wbr>Shared->ShadowBufferObjects);<br>
> +<br>
> +   for (i = 0; i < n ; i++) {<br>
> +      if (buffers[i] == glthread->pixel_pack_buffer_<wbr>bound)<br>
> +         glthread->pixel_pack_buffer_<wbr>bound = 0;<br>
> +<br>
> +      if (buffers[i] == glthread->pixel_unpack_buffer_<wbr>bound)<br>
> +         glthread->pixel_unpack_buffer_<wbr>bound = 0;<br>
> +<br>
> +      /* Technically the buffer can still exist if it is bound to another<br>
> +       * context. It isn't important as next BindBuffer will consider<br>
> +       * the buffer invalid and following PBO transfer will be synchronous<br>
> +       * which is always safe.<br>
> +       */<br>
> +      _mesa_HashRemoveLocked(ctx-><wbr>Shared->ShadowBufferObjects, buffers[i]);<br>
> +   }<br>
> +<br>
> +   _mesa_HashUnlockMutex(ctx-><wbr>Shared->ShadowBufferObjects);<br>
> +}<br>
> +<br>
> +<br>
> +/* CreateBuffers: custom marshal to track buffers creation */<br>
> +void GLAPIENTRY<br>
> +_mesa_marshal_CreateBuffers(<wbr>GLsizei n, GLuint * buffers)<br>
> +{<br>
> +   GET_CURRENT_CONTEXT(ctx);<br>
> +   _mesa_glthread_finish(ctx);<br>
> +   debug_print_sync("<wbr>CreateBuffers");<br>
> +   CALL_CreateBuffers(ctx-><wbr>CurrentServerDispatch, (n, buffers));<br>
> +<br>
> +   track_buffers_creation(n, buffers);<br>
> +}<br>
> +<br>
> +void<br>
> +_mesa_unmarshal_<wbr>CreateBuffers(struct gl_context *ctx,<br>
> +                           const struct marshal_cmd_CreateBuffers *cmd)<br>
> +{<br>
> +   assert(0);<br>
> +}<br>
> +<br>
> +/* GenBuffers: custom marshal to track buffers creation */<br>
> +void GLAPIENTRY<br>
> +_mesa_marshal_GenBuffers(<wbr>GLsizei n, GLuint * buffer)<br>
> +{<br>
> +   GET_CURRENT_CONTEXT(ctx);<br>
> +   _mesa_glthread_finish(ctx);<br>
> +   debug_print_sync("GenBuffers")<wbr>;<br>
> +   CALL_GenBuffers(ctx-><wbr>CurrentServerDispatch, (n, buffer));<br>
> +<br>
> +   track_buffers_creation(n, buffer);<br>
> +}<br>
> +<br>
> +void<br>
> +_mesa_unmarshal_GenBuffers(<wbr>struct gl_context *ctx,<br>
> +                           const struct marshal_cmd_GenBuffers *cmd)<br>
> +{<br>
> +   assert(0);<br>
> +}<br>
> +<br>
> +/* DeleteBuffers: custom marshal to track buffers destruction */<br>
> +void GLAPIENTRY<br>
> +_mesa_marshal_DeleteBuffers(<wbr>GLsizei n, const GLuint * buffer)<br>
> +{<br>
> +   GET_CURRENT_CONTEXT(ctx);<br>
> +   _mesa_glthread_finish(ctx);<br>
> +   debug_print_sync("<wbr>DeleteBuffers");<br>
> +<br>
> +   // It is done before CALL_DeleteBuffers to avoid any ABA multithread issue.<br>
> +   track_buffers_destruction(n, buffer);<br>
> +<br>
> +   CALL_DeleteBuffers(ctx-><wbr>CurrentServerDispatch, (n, buffer));<br>
> +}<br>
> +<br>
> +void<br>
> +_mesa_unmarshal_<wbr>DeleteBuffers(struct gl_context *ctx,<br>
> +                           const struct marshal_cmd_DeleteBuffers *cmd)<br>
> +{<br>
> +   assert(0);<br>
> +}<br>
><br>
>  /* BindBufferBase: marshalled asynchronously */<br>
>  struct marshal_cmd_BindBufferBase<br>
>  {<br>
>     struct marshal_cmd_base cmd_base;<br>
>     GLenum target;<br>
>     GLuint index;<br>
>     GLuint buffer;<br>
>  };<br>
><br>
> diff --git a/src/mesa/main/marshal.h b/src/mesa/main/marshal.h<br>
> index ddfa834..8a8b8da 100644<br>
> --- a/src/mesa/main/marshal.h<br>
> +++ b/src/mesa/main/marshal.h<br>
> @@ -174,20 +174,23 @@ _mesa_glthread_is_compat_bind_<wbr>vertex_array(const struct gl_context *ctx)<br>
>     return ctx->API != API_OPENGL_CORE;<br>
>  }<br>
><br>
>  struct marshal_cmd_Enable;<br>
>  struct marshal_cmd_ShaderSource;<br>
>  struct marshal_cmd_Flush;<br>
>  struct marshal_cmd_BindBuffer;<br>
>  struct marshal_cmd_BufferData;<br>
>  struct marshal_cmd_BufferSubData;<br>
>  struct marshal_cmd_ClearBufferfv;<br>
> +struct marshal_cmd_CreateBuffers;<br>
> +struct marshal_cmd_GenBuffers;<br>
> +struct marshal_cmd_DeleteBuffers;<br>
><br>
>  void<br>
>  _mesa_unmarshal_Enable(struct gl_context *ctx,<br>
>                         const struct marshal_cmd_Enable *cmd);<br>
><br>
>  void GLAPIENTRY<br>
>  _mesa_marshal_Enable(GLenum cap);<br>
><br>
>  void GLAPIENTRY<br>
>  _mesa_marshal_ShaderSource(<wbr>GLuint shader, GLsizei count,<br>
> @@ -228,11 +231,32 @@ _mesa_marshal_BufferSubData(<wbr>GLenum target, GLintptr offset, GLsizeiptr size,<br>
>                              const GLvoid * data);<br>
><br>
>  void<br>
>  _mesa_unmarshal_ClearBufferfv(<wbr>struct gl_context *ctx,<br>
>                                const struct marshal_cmd_ClearBufferfv *cmd);<br>
><br>
>  void GLAPIENTRY<br>
>  _mesa_marshal_ClearBufferfv(<wbr>GLenum buffer, GLint drawbuffer,<br>
>                              const GLfloat *value);<br>
><br>
> +void GLAPIENTRY<br>
> +_mesa_marshal_CreateBuffers(<wbr>GLsizei n, GLuint * buffers);<br>
> +<br>
> +void<br>
> +_mesa_unmarshal_<wbr>CreateBuffers(struct gl_context *ctx,<br>
> +                           const struct marshal_cmd_CreateBuffers *cmd);<br>
> +<br>
> +void GLAPIENTRY<br>
> +_mesa_marshal_GenBuffers(<wbr>GLsizei n, GLuint * buffer);<br>
> +<br>
> +void<br>
> +_mesa_unmarshal_GenBuffers(<wbr>struct gl_context *ctx,<br>
> +                           const struct marshal_cmd_GenBuffers *cmd);<br>
> +<br>
> +void GLAPIENTRY<br>
> +_mesa_marshal_DeleteBuffers(<wbr>GLsizei n, const GLuint * buffer);<br>
> +<br>
> +void<br>
> +_mesa_unmarshal_<wbr>DeleteBuffers(struct gl_context *ctx,<br>
> +                           const struct marshal_cmd_DeleteBuffers *cmd);<br>
> +<br>
>  #endif /* MARSHAL_H */<br>
> diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h<br>
> index 0cb0024..7b9334c 100644<br>
> --- a/src/mesa/main/mtypes.h<br>
> +++ b/src/mesa/main/mtypes.h<br>
> @@ -3249,20 +3249,25 @@ struct gl_shared_state<br>
>     struct gl_program *DefaultVertexProgram;<br>
>     struct gl_program *DefaultFragmentProgram;<br>
>     /*@}*/<br>
><br>
>     /* GL_ATI_fragment_shader */<br>
>     struct _mesa_HashTable *ATIShaders;<br>
>     struct ati_fragment_shader *DefaultFragmentShader;<br>
><br>
>     struct _mesa_HashTable *BufferObjects;<br>
><br>
> +   /**< shadow of BufferObjects to track buffer in application thread when<br>
> +    * glthread is enabled<br>
> +    */<br>
> +   struct _mesa_HashTable *ShadowBufferObjects;<br>
> +<br>
<br>
The hash value is never used, so this should be a set, not a hash table.<br>
<br>
However, seeing as this patch makes Create/GenBuffers and DeleteBuffers<br>
synchronous, do we need a shadow hash table?  When is it not in sync with<br>
Shared->BufferObjects?<br>
<br>
>     /** Table of both gl_shader and gl_shader_program objects */<br>
>     struct _mesa_HashTable *ShaderObjects;<br>
><br>
>     /* GL_EXT_framebuffer_object */<br>
>     struct _mesa_HashTable *RenderBuffers;<br>
>     struct _mesa_HashTable *FrameBuffers;<br>
><br>
>     /* GL_ARB_sync */<br>
>     struct set *SyncObjects;<br>
><br>
> diff --git a/src/mesa/main/shared.c b/src/mesa/main/shared.c<br>
> index 6926d40..5766a9f 100644<br>
> --- a/src/mesa/main/shared.c<br>
> +++ b/src/mesa/main/shared.c<br>
> @@ -75,20 +75,22 @@ _mesa_alloc_shared_state(<wbr>struct gl_context *ctx)<br>
>     shared->DefaultFragmentProgram =<br>
>        ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0, true);<br>
><br>
>     shared->ATIShaders = _mesa_NewHashTable();<br>
>     shared->DefaultFragmentShader = _mesa_new_ati_fragment_shader(<wbr>ctx, 0);<br>
><br>
>     shared->ShaderObjects = _mesa_NewHashTable();<br>
><br>
>     shared->BufferObjects = _mesa_NewHashTable();<br>
><br>
> +   shared->ShadowBufferObjects = _mesa_NewHashTable();<br>
> +<br>
>     /* GL_ARB_sampler_objects */<br>
>     shared->SamplerObjects = _mesa_NewHashTable();<br>
><br>
>     /* GL_ARB_bindless_texture */<br>
>     _mesa_init_shared_handles(<wbr>shared);<br>
><br>
>     /* Allocate the default buffer object */<br>
>     shared->NullBufferObj = ctx->Driver.NewBufferObject(<wbr>ctx, 0);<br>
><br>
>     /* Create default texture objects */<br>
> @@ -290,20 +292,29 @@ delete_renderbuffer_cb(GLuint id, void *data, void *userData)<br>
>  static void<br>
>  delete_sampler_object_cb(<wbr>GLuint id, void *data, void *userData)<br>
>  {<br>
>     struct gl_context *ctx = (struct gl_context *) userData;<br>
>     struct gl_sampler_object *sampObj = (struct gl_sampler_object *) data;<br>
>     _mesa_reference_sampler_<wbr>object(ctx, &sampObj, NULL);<br>
>  }<br>
><br>
><br>
>  /**<br>
> + * Dummy Callback. Called by _mesa_HashDeleteAll()<br>
> + */<br>
> +static void<br>
> +delete_dummy_cb(GLuint id, void *data, void *userData)<br>
> +{<br>
> +}<br>
> +<br>
> +<br>
> +/**<br>
>   * Deallocate a shared state object and all children structures.<br>
>   *<br>
>   * \param ctx GL context.<br>
>   * \param shared shared state pointer.<br>
>   *<br>
>   * Frees the display lists, the texture objects (calling the driver texture<br>
>   * deletion callback to free its private data) and the vertex programs, as well<br>
>   * as their hash tables.<br>
>   *<br>
>   * \sa alloc_shared_state().<br>
> @@ -337,20 +348,23 @@ free_shared_state(struct gl_context *ctx, struct gl_shared_state *shared)<br>
>     _mesa_reference_program(ctx, &shared->DefaultVertexProgram, NULL);<br>
>     _mesa_reference_program(ctx, &shared-><wbr>DefaultFragmentProgram, NULL);<br>
><br>
>     _mesa_HashDeleteAll(shared-><wbr>ATIShaders, delete_fragshader_cb, ctx);<br>
>     _mesa_DeleteHashTable(shared-><wbr>ATIShaders);<br>
>     _mesa_delete_ati_fragment_<wbr>shader(ctx, shared->DefaultFragmentShader)<wbr>;<br>
><br>
>     _mesa_HashDeleteAll(shared-><wbr>BufferObjects, delete_bufferobj_cb, ctx);<br>
>     _mesa_DeleteHashTable(shared-><wbr>BufferObjects);<br>
><br>
> +   _mesa_HashDeleteAll(shared-><wbr>ShadowBufferObjects, delete_dummy_cb, ctx);<br>
> +   _mesa_DeleteHashTable(shared-><wbr>ShadowBufferObjects);<br>
> +<br>
>     _mesa_HashDeleteAll(shared-><wbr>FrameBuffers, delete_framebuffer_cb, ctx);<br>
>     _mesa_DeleteHashTable(shared-><wbr>FrameBuffers);<br>
>     _mesa_HashDeleteAll(shared-><wbr>RenderBuffers, delete_renderbuffer_cb, ctx);<br>
>     _mesa_DeleteHashTable(shared-><wbr>RenderBuffers);<br>
><br>
>     _mesa_reference_buffer_object(<wbr>ctx, &shared->NullBufferObj, NULL);<br>
><br>
>     {<br>
>        struct set_entry *entry;<br>
><br>
><br>
<br>
</blockquote></div></div>