[Mesa-dev] [PATCH v6 1/3] mesa/glthread: track buffer creation/destruction
Gregory Hainaut
gregory.hainaut at gmail.com
Sun May 21 14:57:55 UTC 2017
It would be used in next commit to allow asynchronous PBO transfer.
The tracking saves the buffer name into a hash. Saving pointer
will be more complex as the buffer is created in BindBuffer due to IsBuffer
insanity.
Perf wise DeleteBuffers is now synchronous for robustness.
v5: properly delete hash element with the help of _mesa_HashDeleteAll
v6: rebase
Signed-off-by: Gregory Hainaut <gregory.hainaut at gmail.com>
---
src/mapi/glapi/gen/ARB_direct_state_access.xml | 2 +-
src/mapi/glapi/gen/gl_API.xml | 4 +-
src/mesa/main/glthread.h | 10 +++
src/mesa/main/marshal.c | 113 +++++++++++++++++++++++++
src/mesa/main/marshal.h | 24 ++++++
src/mesa/main/mtypes.h | 5 ++
src/mesa/main/shared.c | 14 +++
7 files changed, 169 insertions(+), 3 deletions(-)
diff --git a/src/mapi/glapi/gen/ARB_direct_state_access.xml b/src/mapi/glapi/gen/ARB_direct_state_access.xml
index b8780f75b3..8761920c91 100644
--- a/src/mapi/glapi/gen/ARB_direct_state_access.xml
+++ b/src/mapi/glapi/gen/ARB_direct_state_access.xml
@@ -42,21 +42,21 @@
<function name="GetTransformFeedbacki64_v">
<param name="xfb" type="GLuint" />
<param name="pname" type="GLenum" />
<param name="index" type="GLuint" />
<param name="param" type="GLint64 *" />
</function>
<!-- Buffer object functions -->
- <function name="CreateBuffers">
+ <function name="CreateBuffers" marshal="custom">
<param name="n" type="GLsizei" />
<param name="buffers" type="GLuint *" />
</function>
<function name="NamedBufferStorage" no_error="true">
<param name="buffer" type="GLuint" />
<param name="size" type="GLsizeiptr" />
<param name="data" type="const GLvoid *" />
<param name="flags" type="GLbitfield" />
</function>
diff --git a/src/mapi/glapi/gen/gl_API.xml b/src/mapi/glapi/gen/gl_API.xml
index 762fb5a676..829f99b0f0 100644
--- a/src/mapi/glapi/gen/gl_API.xml
+++ b/src/mapi/glapi/gen/gl_API.xml
@@ -5053,27 +5053,27 @@
<function name="BufferSubData" es1="1.1" es2="2.0" marshal="custom"
no_error="true">
<param name="target" type="GLenum"/>
<param name="offset" type="GLintptr"/>
<param name="size" type="GLsizeiptr" counter="true"/>
<param name="data" type="const GLvoid *" count="size"/>
<glx ignore="true"/>
</function>
- <function name="DeleteBuffers" es1="1.1" es2="2.0">
+ <function name="DeleteBuffers" es1="1.1" es2="2.0" marshal="custom">
<param name="n" type="GLsizei" counter="true"/>
<param name="buffer" type="const GLuint *" count="n"/>
<glx ignore="true"/>
</function>
- <function name="GenBuffers" es1="1.1" es2="2.0">
+ <function name="GenBuffers" es1="1.1" es2="2.0" marshal="custom">
<param name="n" type="GLsizei" counter="true"/>
<param name="buffer" type="GLuint *" output="true" count="n"/>
<glx ignore="true"/>
</function>
<function name="GetBufferParameteriv" es1="1.1" es2="2.0">
<param name="target" type="GLenum"/>
<param name="pname" type="GLenum"/>
<param name="params" type="GLint *" output="true" variable_param="pname"/>
<glx ignore="true"/>
diff --git a/src/mesa/main/glthread.h b/src/mesa/main/glthread.h
index 50c1db2548..494e94270a 100644
--- a/src/mesa/main/glthread.h
+++ b/src/mesa/main/glthread.h
@@ -85,20 +85,30 @@ struct glthread_state
* Tracks on the main thread side whether the current vertex array binding
* is in a VBO.
*/
bool vertex_array_is_vbo;
/**
* Tracks on the main thread side whether the current element array (index
* buffer) binding is in a VBO.
*/
bool element_array_is_vbo;
+
+ /**
+ * Tracks on the main thread side the bound unpack pixel buffer
+ */
+ GLint pixel_unpack_buffer_bound;
+
+ /**
+ * Tracks on the main thread side the bound pack pixel buffer
+ */
+ GLint pixel_pack_buffer_bound;
};
/**
* A single batch of commands queued up for later execution by a thread pool
* task.
*/
struct glthread_batch
{
/**
* Next batch of commands to execute after this batch, or NULL if this is
diff --git a/src/mesa/main/marshal.c b/src/mesa/main/marshal.c
index ae4efb5ecb..4037b793ee 100644
--- a/src/mesa/main/marshal.c
+++ b/src/mesa/main/marshal.c
@@ -25,20 +25,21 @@
*
* Custom functions for marshalling GL calls from the main thread to a worker
* thread when automatic code generation isn't appropriate.
*/
#include "main/enums.h"
#include "main/macros.h"
#include "marshal.h"
#include "dispatch.h"
#include "marshal_generated.h"
+#include "hash.h"
#ifdef HAVE_PTHREAD
struct marshal_cmd_Flush
{
struct marshal_cmd_base cmd_base;
};
void
@@ -189,20 +190,132 @@ _mesa_marshal_ShaderSource(GLuint shader, GLsizei count,
}
_mesa_post_marshal_hook(ctx);
} else {
_mesa_glthread_finish(ctx);
CALL_ShaderSource(ctx->CurrentServerDispatch,
(shader, count, string, length_tmp));
}
free(length_tmp);
}
+/**
+ * Used as a placeholder for track_buffers_creation/track_buffers_destruction
+ * so we know if buffer really exists in track_buffers_binding.
+ */
+static struct gl_buffer_object DummyBufferObject;
+
+static void track_buffers_creation(GLsizei n, GLuint * buffers)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLsizei i;
+
+ if (n < 0 || !buffers)
+ return;
+
+ _mesa_HashLockMutex(ctx->Shared->ShadowBufferObjects);
+
+ for (i = 0; i < n ; i++) {
+ _mesa_HashInsertLocked(ctx->Shared->ShadowBufferObjects, buffers[i],
+ &DummyBufferObject);
+ }
+
+ _mesa_HashUnlockMutex(ctx->Shared->ShadowBufferObjects);
+}
+
+static void track_buffers_destruction(GLsizei n, const GLuint * buffers)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLsizei i;
+ struct glthread_state *glthread = ctx->GLThread;
+
+ if (n < 0 || !buffers)
+ return;
+
+ _mesa_HashLockMutex(ctx->Shared->ShadowBufferObjects);
+
+ for (i = 0; i < n ; i++) {
+ if (buffers[i] == glthread->pixel_pack_buffer_bound)
+ glthread->pixel_pack_buffer_bound = 0;
+
+ if (buffers[i] == glthread->pixel_unpack_buffer_bound)
+ glthread->pixel_unpack_buffer_bound = 0;
+
+ /* Technically the buffer can still exist if it is bound to another
+ * context. It isn't important as next BindBuffer will consider
+ * the buffer invalid and following PBO transfer will be synchronous
+ * which is always safe.
+ */
+ _mesa_HashRemoveLocked(ctx->Shared->ShadowBufferObjects, buffers[i]);
+ }
+
+ _mesa_HashUnlockMutex(ctx->Shared->ShadowBufferObjects);
+}
+
+
+/* CreateBuffers: custom marshal to track buffers creation */
+void GLAPIENTRY
+_mesa_marshal_CreateBuffers(GLsizei n, GLuint * buffers)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_glthread_finish(ctx);
+ debug_print_sync("CreateBuffers");
+ CALL_CreateBuffers(ctx->CurrentServerDispatch, (n, buffers));
+
+ track_buffers_creation(n, buffers);
+}
+
+void
+_mesa_unmarshal_CreateBuffers(struct gl_context *ctx,
+ const struct marshal_cmd_CreateBuffers *cmd)
+{
+ assert(0);
+}
+
+/* GenBuffers: custom marshal to track buffers creation */
+void GLAPIENTRY
+_mesa_marshal_GenBuffers(GLsizei n, GLuint * buffer)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_glthread_finish(ctx);
+ debug_print_sync("GenBuffers");
+ CALL_GenBuffers(ctx->CurrentServerDispatch, (n, buffer));
+
+ track_buffers_creation(n, buffer);
+}
+
+void
+_mesa_unmarshal_GenBuffers(struct gl_context *ctx,
+ const struct marshal_cmd_GenBuffers *cmd)
+{
+ assert(0);
+}
+
+/* DeleteBuffers: custom marshal to track buffers destruction */
+void GLAPIENTRY
+_mesa_marshal_DeleteBuffers(GLsizei n, const GLuint * buffer)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_glthread_finish(ctx);
+ debug_print_sync("DeleteBuffers");
+
+ // It is done before CALL_DeleteBuffers to avoid any ABA multithread issue.
+ track_buffers_destruction(n, buffer);
+
+ CALL_DeleteBuffers(ctx->CurrentServerDispatch, (n, buffer));
+}
+
+void
+_mesa_unmarshal_DeleteBuffers(struct gl_context *ctx,
+ const struct marshal_cmd_DeleteBuffers *cmd)
+{
+ assert(0);
+}
/* BindBufferBase: marshalled asynchronously */
struct marshal_cmd_BindBufferBase
{
struct marshal_cmd_base cmd_base;
GLenum target;
GLuint index;
GLuint buffer;
};
diff --git a/src/mesa/main/marshal.h b/src/mesa/main/marshal.h
index 4842d27eeb..150581bc4a 100644
--- a/src/mesa/main/marshal.h
+++ b/src/mesa/main/marshal.h
@@ -199,20 +199,23 @@ _mesa_glthread_is_compat_bind_vertex_array(const struct gl_context *ctx)
return ctx->API != API_OPENGL_CORE;
}
struct marshal_cmd_Enable;
struct marshal_cmd_ShaderSource;
struct marshal_cmd_Flush;
struct marshal_cmd_BindBuffer;
struct marshal_cmd_BufferData;
struct marshal_cmd_BufferSubData;
struct marshal_cmd_ClearBufferfv;
+struct marshal_cmd_CreateBuffers;
+struct marshal_cmd_GenBuffers;
+struct marshal_cmd_DeleteBuffers;
void
_mesa_unmarshal_Enable(struct gl_context *ctx,
const struct marshal_cmd_Enable *cmd);
void GLAPIENTRY
_mesa_marshal_Enable(GLenum cap);
void GLAPIENTRY
_mesa_marshal_ShaderSource(GLuint shader, GLsizei count,
@@ -253,11 +256,32 @@ _mesa_marshal_BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size,
const GLvoid * data);
void
_mesa_unmarshal_ClearBufferfv(struct gl_context *ctx,
const struct marshal_cmd_ClearBufferfv *cmd);
void GLAPIENTRY
_mesa_marshal_ClearBufferfv(GLenum buffer, GLint drawbuffer,
const GLfloat *value);
+void GLAPIENTRY
+_mesa_marshal_CreateBuffers(GLsizei n, GLuint * buffers);
+
+void
+_mesa_unmarshal_CreateBuffers(struct gl_context *ctx,
+ const struct marshal_cmd_CreateBuffers *cmd);
+
+void GLAPIENTRY
+_mesa_marshal_GenBuffers(GLsizei n, GLuint * buffer);
+
+void
+_mesa_unmarshal_GenBuffers(struct gl_context *ctx,
+ const struct marshal_cmd_GenBuffers *cmd);
+
+void GLAPIENTRY
+_mesa_marshal_DeleteBuffers(GLsizei n, const GLuint * buffer);
+
+void
+_mesa_unmarshal_DeleteBuffers(struct gl_context *ctx,
+ const struct marshal_cmd_DeleteBuffers *cmd);
+
#endif /* MARSHAL_H */
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 7ac0ee3677..6c29b8d34e 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -3191,20 +3191,25 @@ struct gl_shared_state
struct gl_program *DefaultVertexProgram;
struct gl_program *DefaultFragmentProgram;
/*@}*/
/* GL_ATI_fragment_shader */
struct _mesa_HashTable *ATIShaders;
struct ati_fragment_shader *DefaultFragmentShader;
struct _mesa_HashTable *BufferObjects;
+ /**< shadow of BufferObjects to track buffer in application thread when
+ * glthread is enabled
+ */
+ struct _mesa_HashTable *ShadowBufferObjects;
+
/** Table of both gl_shader and gl_shader_program objects */
struct _mesa_HashTable *ShaderObjects;
/* GL_EXT_framebuffer_object */
struct _mesa_HashTable *RenderBuffers;
struct _mesa_HashTable *FrameBuffers;
/* GL_ARB_sync */
struct set *SyncObjects;
diff --git a/src/mesa/main/shared.c b/src/mesa/main/shared.c
index 5344812738..3bc392d740 100644
--- a/src/mesa/main/shared.c
+++ b/src/mesa/main/shared.c
@@ -74,20 +74,22 @@ _mesa_alloc_shared_state(struct gl_context *ctx)
shared->DefaultFragmentProgram =
ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0, true);
shared->ATIShaders = _mesa_NewHashTable();
shared->DefaultFragmentShader = _mesa_new_ati_fragment_shader(ctx, 0);
shared->ShaderObjects = _mesa_NewHashTable();
shared->BufferObjects = _mesa_NewHashTable();
+ shared->ShadowBufferObjects = _mesa_NewHashTable();
+
/* GL_ARB_sampler_objects */
shared->SamplerObjects = _mesa_NewHashTable();
/* Allocate the default buffer object */
shared->NullBufferObj = ctx->Driver.NewBufferObject(ctx, 0);
/* Create default texture objects */
for (i = 0; i < NUM_TEXTURE_TARGETS; i++) {
/* NOTE: the order of these enums matches the TEXTURE_x_INDEX values */
static const GLenum targets[] = {
@@ -286,20 +288,29 @@ delete_renderbuffer_cb(GLuint id, void *data, void *userData)
static void
delete_sampler_object_cb(GLuint id, void *data, void *userData)
{
struct gl_context *ctx = (struct gl_context *) userData;
struct gl_sampler_object *sampObj = (struct gl_sampler_object *) data;
_mesa_reference_sampler_object(ctx, &sampObj, NULL);
}
/**
+ * Dummy Callback. Called by _mesa_HashDeleteAll()
+ */
+static void
+delete_dummy_cb(GLuint id, void *data, void *userData)
+{
+}
+
+
+/**
* Deallocate a shared state object and all children structures.
*
* \param ctx GL context.
* \param shared shared state pointer.
*
* Frees the display lists, the texture objects (calling the driver texture
* deletion callback to free its private data) and the vertex programs, as well
* as their hash tables.
*
* \sa alloc_shared_state().
@@ -333,20 +344,23 @@ free_shared_state(struct gl_context *ctx, struct gl_shared_state *shared)
_mesa_reference_program(ctx, &shared->DefaultVertexProgram, NULL);
_mesa_reference_program(ctx, &shared->DefaultFragmentProgram, NULL);
_mesa_HashDeleteAll(shared->ATIShaders, delete_fragshader_cb, ctx);
_mesa_DeleteHashTable(shared->ATIShaders);
_mesa_delete_ati_fragment_shader(ctx, shared->DefaultFragmentShader);
_mesa_HashDeleteAll(shared->BufferObjects, delete_bufferobj_cb, ctx);
_mesa_DeleteHashTable(shared->BufferObjects);
+ _mesa_HashDeleteAll(shared->ShadowBufferObjects, delete_dummy_cb, ctx);
+ _mesa_DeleteHashTable(shared->ShadowBufferObjects);
+
_mesa_HashDeleteAll(shared->FrameBuffers, delete_framebuffer_cb, ctx);
_mesa_DeleteHashTable(shared->FrameBuffers);
_mesa_HashDeleteAll(shared->RenderBuffers, delete_renderbuffer_cb, ctx);
_mesa_DeleteHashTable(shared->RenderBuffers);
_mesa_reference_buffer_object(ctx, &shared->NullBufferObj, NULL);
{
struct set_entry *entry;
--
2.11.0
More information about the mesa-dev
mailing list