<category name="GL_ARB_base_instance" number="107">
- <function name="DrawArraysInstancedBaseInstance" exec="dynamic" marshal="draw">
+ <function name="DrawArraysInstancedBaseInstance" exec="dynamic" marshal="draw"
+ marshal_fail="_mesa_glthread_is_non_vbo_draw_arrays(ctx)">
<param name="mode" type="GLenum"/>
<param name="first" type="GLint"/>
<param name="count" type="GLsizei"/>
<category name="GL_ARB_draw_instanced" number="44">
- <function name="DrawArraysInstancedARB" exec="dynamic" marshal="draw">
+ <function name="DrawArraysInstancedARB" exec="dynamic" marshal="draw"
+ marshal_fail="_mesa_glthread_is_non_vbo_draw_arrays(ctx)">
<param name="mode" type="GLenum"/>
<param name="first" type="GLint"/>
<param name="count" type="GLsizei"/>
<enum name="PARAMETER_BUFFER_ARB" value="0x80EE"/>
<enum name="PARAMETER_BUFFER_BINDING_ARB" value="0x80EF"/>
- <function name="MultiDrawArraysIndirectCountARB" exec="dynamic">
+ <function name="MultiDrawArraysIndirectCountARB" exec="dynamic" marshal="draw"
+ marshal_fail="_mesa_glthread_is_non_vbo_draw_arrays(ctx)">
<param name="mode" type="GLenum"/>
<param name="indirect" type="GLintptr"/>
<param name="drawcount" type="GLintptr"/>
<param name="stride" type="GLsizei"/>
</function>
- <function name="MultiDrawElementsIndirectCountARB" exec="dynamic">
+ <!-- Use "...vbo_draw_arrays", because indices always come from a buffer object. -->
+ <function name="MultiDrawElementsIndirectCountARB" exec="dynamic" marshal="draw"
+ marshal_fail="_mesa_glthread_is_non_vbo_draw_arrays(ctx)">
<param name="mode" type="GLenum"/>
<param name="type" type="GLenum"/>
<param name="indirect" type="GLintptr"/>
<enum name="VERTEX_ARRAY_BINDING" value="0x85B5"/>
<function name="BindVertexArray" es2="3.0" no_error="true"
- marshal_fail="_mesa_glthread_is_compat_bind_vertex_array(ctx)">
+ marshal_call_after="_mesa_glthread_BindVertexArray(ctx, array);">
<param name="array" type="GLuint"/>
</function>
- <function name="DeleteVertexArrays" es2="3.0" no_error="true">
+ <function name="DeleteVertexArrays" es2="3.0" no_error="true"
+ marshal_call_after="_mesa_glthread_DeleteVertexArrays(ctx, n, arrays);">
<param name="n" type="GLsizei"/>
<param name="arrays" type="const GLuint *" count="n"/>
</function>
- <function name="GenVertexArrays" es2="3.0" no_error="true">
+ <function name="GenVertexArrays" es2="3.0" no_error="true"
+ marshal_call_after="_mesa_glthread_GenVertexArrays(ctx, n, arrays);">
<param name="n" type="GLsizei"/>
<param name="arrays" type="GLuint *"/>
</function>
</function>
<function name="VertexAttribLPointer" no_error="true" marshal="async"
- marshal_fail="_mesa_glthread_is_non_vbo_vertex_attrib_pointer(ctx)">
+ marshal_call_after="_mesa_glthread_AttribPointer(ctx);">
<param name="index" type="GLuint"/>
<param name="size" type="GLint"/>
<param name="type" type="GLenum"/>
</function>
<function name="MultiTexCoordPointerEXT" marshal="async"
- marshal_fail="_mesa_glthread_is_non_vbo_vertex_attrib_pointer(ctx)">
+ marshal_call_after="_mesa_glthread_AttribPointer(ctx);">
<param name="texunit" type="GLenum" />
<param name="size" type="GLint" />
<param name="type" type="GLenum" />
<function name="VertexAttribIPointer" es2="3.0" marshal="async"
no_error="true"
- marshal_fail="_mesa_glthread_is_non_vbo_vertex_attrib_pointer(ctx)">
+ marshal_call_after="_mesa_glthread_AttribPointer(ctx);">
<param name="index" type="GLuint"/>
<param name="size" type="GLint"/>
<param name="type" type="GLenum"/>
<function name="PointSizePointerOES" es1="1.0" desktop="false"
no_error="true" marshal="async"
- marshal_fail="_mesa_glthread_is_non_vbo_vertex_attrib_pointer(ctx)">
+ marshal_call_after="_mesa_glthread_AttribPointer(ctx);">
<param name="type" type="GLenum"/>
<param name="stride" type="GLsizei"/>
<param name="pointer" type="const GLvoid *"/>
<function name="ColorPointer" es1="1.0" deprecated="3.1" marshal="async"
no_error="true"
- marshal_fail="_mesa_glthread_is_non_vbo_vertex_attrib_pointer(ctx)">
+ marshal_call_after="_mesa_glthread_AttribPointer(ctx);">
<param name="size" type="GLint"/>
<param name="type" type="GLenum"/>
<param name="stride" type="GLsizei"/>
<glx handcode="true"/>
</function>
- <function name="DrawArrays" es1="1.0" es2="2.0" exec="dynamic" marshal="draw">
+ <function name="DrawArrays" es1="1.0" es2="2.0" exec="dynamic" marshal="draw"
+ marshal_fail="_mesa_glthread_is_non_vbo_draw_arrays(ctx)">
<param name="mode" type="GLenum"/>
<param name="first" type="GLint"/>
<param name="count" type="GLsizei"/>
<function name="EdgeFlagPointer" deprecated="3.1" marshal="async"
no_error="true"
- marshal_fail="_mesa_glthread_is_non_vbo_vertex_attrib_pointer(ctx)">
+ marshal_call_after="_mesa_glthread_AttribPointer(ctx);">
<param name="stride" type="GLsizei"/>
<param name="pointer" type="const GLvoid *"/>
<glx handcode="true"/>
<function name="IndexPointer" deprecated="3.1" marshal="async"
no_error="true"
- marshal_fail="_mesa_glthread_is_non_vbo_vertex_attrib_pointer(ctx)">
+ marshal_call_after="_mesa_glthread_AttribPointer(ctx);">
<param name="type" type="GLenum"/>
<param name="stride" type="GLsizei"/>
<param name="pointer" type="const GLvoid *"/>
<function name="NormalPointer" es1="1.0" deprecated="3.1" marshal="async"
no_error="true"
- marshal_fail="_mesa_glthread_is_non_vbo_vertex_attrib_pointer(ctx)">
+ marshal_call_after="_mesa_glthread_AttribPointer(ctx);">
<param name="type" type="GLenum"/>
<param name="stride" type="GLsizei"/>
<param name="pointer" type="const GLvoid *"/>
<function name="TexCoordPointer" es1="1.0" deprecated="3.1" marshal="async"
no_error="true"
- marshal_fail="_mesa_glthread_is_non_vbo_vertex_attrib_pointer(ctx)">
+ marshal_call_after="_mesa_glthread_AttribPointer(ctx);">
<param name="size" type="GLint"/>
<param name="type" type="GLenum"/>
<param name="stride" type="GLsizei"/>
<function name="VertexPointer" es1="1.0" deprecated="3.1" marshal="async"
no_error="true"
- marshal_fail="_mesa_glthread_is_non_vbo_vertex_attrib_pointer(ctx)">
+ marshal_call_after="_mesa_glthread_AttribPointer(ctx);">
<param name="size" type="GLint"/>
<param name="type" type="GLenum"/>
<param name="stride" type="GLsizei"/>
<function name="FogCoordPointer" deprecated="3.1" marshal="async"
no_error="true"
- marshal_fail="_mesa_glthread_is_non_vbo_vertex_attrib_pointer(ctx)">
+ marshal_call_after="_mesa_glthread_AttribPointer(ctx);">
<param name="type" type="GLenum"/>
<param name="stride" type="GLsizei"/>
<param name="pointer" type="const GLvoid *"/>
<glx handcode="true"/>
</function>
- <function name="MultiDrawArrays" marshal="draw">
+ <function name="MultiDrawArrays" marshal="draw"
+ marshal_fail="_mesa_glthread_is_non_vbo_draw_arrays(ctx)">
<param name="mode" type="GLenum"/>
<param name="first" type="const GLint *" count="primcount"/>
<param name="count" type="const GLsizei *" count="primcount"/>
<function name="SecondaryColorPointer" deprecated="3.1" marshal="async"
no_error="true"
- marshal_fail="_mesa_glthread_is_non_vbo_vertex_attrib_pointer(ctx)">
+ marshal_call_after="_mesa_glthread_AttribPointer(ctx);">
<param name="size" type="GLint"/>
<param name="type" type="GLenum"/>
<param name="stride" type="GLsizei"/>
<function name="VertexAttribPointer" es2="2.0" marshal="async"
no_error="true"
- marshal_fail="_mesa_glthread_is_non_vbo_vertex_attrib_pointer(ctx)">
+ marshal_call_after="_mesa_glthread_AttribPointer(ctx);">
<param name="index" type="GLuint"/>
<param name="size" type="GLint"/>
<param name="type" type="GLenum"/>
</function>
<function name="ColorPointerEXT" deprecated="3.1" marshal="async"
- marshal_fail="_mesa_glthread_is_non_vbo_vertex_attrib_pointer(ctx)">
+ marshal_call_after="_mesa_glthread_AttribPointer(ctx);">
<param name="size" type="GLint"/>
<param name="type" type="GLenum"/>
<param name="stride" type="GLsizei"/>
</function>
<function name="EdgeFlagPointerEXT" deprecated="3.1" marshal="async"
- marshal_fail="_mesa_glthread_is_non_vbo_vertex_attrib_pointer(ctx)">
+ marshal_call_after="_mesa_glthread_AttribPointer(ctx);">
<param name="stride" type="GLsizei"/>
<param name="count" type="GLsizei"/>
<param name="pointer" type="const GLboolean *"/>
</function>
<function name="IndexPointerEXT" deprecated="3.1" marshal="async"
- marshal_fail="_mesa_glthread_is_non_vbo_vertex_attrib_pointer(ctx)">
+ marshal_call_after="_mesa_glthread_AttribPointer(ctx);">
<param name="type" type="GLenum"/>
<param name="stride" type="GLsizei"/>
<param name="count" type="GLsizei"/>
</function>
<function name="NormalPointerEXT" deprecated="3.1" marshal="async"
- marshal_fail="_mesa_glthread_is_non_vbo_vertex_attrib_pointer(ctx)">
+ marshal_call_after="_mesa_glthread_AttribPointer(ctx);">
<param name="type" type="GLenum"/>
<param name="stride" type="GLsizei"/>
<param name="count" type="GLsizei"/>
</function>
<function name="TexCoordPointerEXT" deprecated="3.1" marshal="async"
- marshal_fail="_mesa_glthread_is_non_vbo_vertex_attrib_pointer(ctx)">
+ marshal_call_after="_mesa_glthread_AttribPointer(ctx);">
<param name="size" type="GLint"/>
<param name="type" type="GLenum"/>
<param name="stride" type="GLsizei"/>
</function>
<function name="VertexPointerEXT" deprecated="3.1" marshal="async"
- marshal_fail="_mesa_glthread_is_non_vbo_vertex_attrib_pointer(ctx)">
+ marshal_call_after="_mesa_glthread_AttribPointer(ctx);">
<param name="size" type="GLint"/>
<param name="type" type="GLenum"/>
<param name="stride" type="GLsizei"/>
<category name="GL_IBM_multimode_draw_arrays" number="200">
<function name="MultiModeDrawArraysIBM" marshal="draw"
- marshal_fail="_mesa_glthread_is_non_vbo_draw_elements(ctx)">
+ marshal_fail="_mesa_glthread_is_non_vbo_draw_arrays(ctx)">
<param name="mode" type="const GLenum *" count="primcount"/>
<param name="first" type="const GLint *" count="primcount"/>
<param name="count" type="const GLsizei *" count="primcount"/>
main/glspirv.h \
main/glthread.c \
main/glthread.h \
+ main/glthread_varray.c \
main/glheader.h \
main/hash.c \
main/hash.h \
#include "main/mtypes.h"
#include "main/glthread.h"
#include "main/marshal.h"
+#include "main/hash.h"
#include "util/u_atomic.h"
#include "util/u_thread.h"
return;
}
+ glthread->VAOs = _mesa_NewHashTable();
+ if (!glthread->VAOs) {
+ util_queue_destroy(&glthread->queue);
+ free(glthread);
+ return;
+ }
+ glthread->CurrentVAO = &glthread->DefaultVAO;
+
ctx->MarshalExec = _mesa_create_marshal_table(ctx);
if (!ctx->MarshalExec) {
+ _mesa_DeleteHashTable(glthread->VAOs);
util_queue_destroy(&glthread->queue);
free(glthread);
return;
util_queue_fence_destroy(&fence);
}
+static void
+free_vao(GLuint key, void *data, void *userData)
+{
+ free(data);
+}
+
void
_mesa_glthread_destroy(struct gl_context *ctx)
{
for (unsigned i = 0; i < MARSHAL_MAX_BATCHES; i++)
util_queue_fence_destroy(&glthread->batches[i].fence);
+ _mesa_HashDeleteAll(glthread->VAOs, free_vao, NULL);
+ _mesa_DeleteHashTable(glthread->VAOs);
+
free(glthread);
ctx->GLThread = NULL;
#include <inttypes.h>
#include <stdbool.h>
#include "util/u_queue.h"
+#include "GL/gl.h"
enum marshal_dispatch_cmd_id;
struct gl_context;
+struct _mesa_HashTable;
+
+struct glthread_vao {
+ GLuint Name;
+ bool HasUserPointer;
+ bool IndexBufferIsUserPointer;
+};
/** A single batch of commands queued up for execution. */
struct glthread_batch
/** Index of the batch being filled and about to be submitted. */
unsigned next;
+ /** Vertex Array objects tracked by glthread independently of Mesa. */
+ struct _mesa_HashTable *VAOs;
+ struct glthread_vao *CurrentVAO;
+ struct glthread_vao *LastLookedUpVAO;
+ struct glthread_vao DefaultVAO;
+
/**
* Tracks on the main thread side whether the current vertex array binding
* is in a VBO.
* Tracks on the main thread side whether the current element array (index
* buffer) binding is in a VBO.
*/
- bool element_array_is_vbo;
bool draw_indirect_buffer_is_vbo;
};
void _mesa_glthread_finish(struct gl_context *ctx);
void _mesa_glthread_finish_before(struct gl_context *ctx, const char *func);
+void _mesa_glthread_BindVertexArray(struct gl_context *ctx, GLuint id);
+void _mesa_glthread_DeleteVertexArrays(struct gl_context *ctx,
+ GLsizei n, const GLuint *ids);
+void _mesa_glthread_GenVertexArrays(struct gl_context *ctx,
+ GLsizei n, GLuint *arrays);
+void _mesa_glthread_AttribPointer(struct gl_context *ctx);
+
#endif /* _GLTHREAD_H*/
--- /dev/null
+/*
+ * Copyright © 2020 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* This implements vertex array state tracking for glthread. It's separate
+ * from the rest of Mesa. Only minimum functionality is implemented here
+ * to serve glthread.
+ */
+
+#include "main/glthread.h"
+#include "main/mtypes.h"
+#include "main/hash.h"
+#include "main/dispatch.h"
+
+/* TODO:
+ * - Implement better tracking of user pointers
+ * - These can unbind user pointers:
+ * ARB_vertex_attrib_binding
+ * ARB_direct_state_access
+ * EXT_direct_state_access
+ */
+
+static struct glthread_vao *
+lookup_vao(struct gl_context *ctx, GLuint id)
+{
+ struct glthread_state *glthread = ctx->GLThread;
+ struct glthread_vao *vao;
+
+ assert(id != 0);
+
+ if (glthread->LastLookedUpVAO &&
+ glthread->LastLookedUpVAO->Name == id) {
+ vao = glthread->LastLookedUpVAO;
+ } else {
+ vao = _mesa_HashLookupLocked(glthread->VAOs, id);
+ if (!vao)
+ return NULL;
+
+ glthread->LastLookedUpVAO = vao;
+ }
+
+ return vao;
+}
+
+void
+_mesa_glthread_BindVertexArray(struct gl_context *ctx, GLuint id)
+{
+ struct glthread_state *glthread = ctx->GLThread;
+
+ if (id == 0) {
+ glthread->CurrentVAO = &glthread->DefaultVAO;
+ } else {
+ struct glthread_vao *vao = lookup_vao(ctx, id);
+
+ if (vao)
+ glthread->CurrentVAO = vao;
+ }
+}
+
+void
+_mesa_glthread_DeleteVertexArrays(struct gl_context *ctx,
+ GLsizei n, const GLuint *ids)
+{
+ struct glthread_state *glthread = ctx->GLThread;
+
+ if (!ids)
+ return;
+
+ for (int i = 0; i < n; i++) {
+ /* IDs equal to 0 should be silently ignored. */
+ if (!ids[i])
+ continue;
+
+ struct glthread_vao *vao = lookup_vao(ctx, ids[i]);
+ if (!vao)
+ continue;
+
+ /* If the array object is currently bound, the spec says "the binding
+ * for that object reverts to zero and the default vertex array
+ * becomes current."
+ */
+ if (glthread->CurrentVAO == vao)
+ glthread->CurrentVAO = &glthread->DefaultVAO;
+
+ if (glthread->LastLookedUpVAO == vao)
+ glthread->LastLookedUpVAO = NULL;
+
+ /* The ID is immediately freed for re-use */
+ _mesa_HashRemoveLocked(glthread->VAOs, vao->Name);
+ free(vao);
+ }
+}
+
+void
+_mesa_glthread_GenVertexArrays(struct gl_context *ctx,
+ GLsizei n, GLuint *arrays)
+{
+ struct glthread_state *glthread = ctx->GLThread;
+
+ if (!arrays)
+ return;
+
+ /* The IDs have been generated at this point. Create VAOs for glthread. */
+ for (int i = 0; i < n; i++) {
+ GLuint id = arrays[i];
+ struct glthread_vao *vao;
+
+ vao = malloc(sizeof(*vao));
+ if (!vao)
+ continue; /* Is that all we can do? */
+
+ vao->Name = id;
+ vao->HasUserPointer = false;
+ _mesa_HashInsertLocked(glthread->VAOs, id, vao);
+ }
+}
+
+void
+_mesa_glthread_AttribPointer(struct gl_context *ctx)
+{
+ struct glthread_state *glthread = ctx->GLThread;
+
+ if (ctx->API != API_OPENGL_CORE && !glthread->vertex_array_is_vbo)
+ glthread->CurrentVAO->HasUserPointer = true;
+}
* 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;
}
/**
- * Instead of conditionally handling marshaling previously-bound user vertex
- * array data in draw calls (deprecated and removed in GL core), we just
- * disable threading at the point where the user sets a user vertex array.
+ * Instead of conditionally handling marshaling immediate index data in draw
+ * calls (deprecated and removed in GL core), we just disable threading.
*/
static inline bool
-_mesa_glthread_is_non_vbo_vertex_attrib_pointer(const struct gl_context *ctx)
+_mesa_glthread_is_non_vbo_draw_elements(const struct gl_context *ctx)
{
struct glthread_state *glthread = ctx->GLThread;
- return ctx->API != API_OPENGL_CORE && !glthread->vertex_array_is_vbo;
+ return ctx->API != API_OPENGL_CORE &&
+ (glthread->CurrentVAO->IndexBufferIsUserPointer ||
+ glthread->CurrentVAO->HasUserPointer);
}
-/**
- * Instead of conditionally handling marshaling immediate index data in draw
- * calls (deprecated and removed in GL core), we just disable threading.
- */
static inline bool
-_mesa_glthread_is_non_vbo_draw_elements(const struct gl_context *ctx)
+_mesa_glthread_is_non_vbo_draw_arrays(const struct gl_context *ctx)
{
struct glthread_state *glthread = ctx->GLThread;
- return ctx->API != API_OPENGL_CORE && !glthread->element_array_is_vbo;
+ return ctx->API != API_OPENGL_CORE && glthread->CurrentVAO->HasUserPointer;
}
static inline bool
struct glthread_state *glthread = ctx->GLThread;
return ctx->API != API_OPENGL_CORE &&
- !glthread->draw_indirect_buffer_is_vbo;
+ (!glthread->draw_indirect_buffer_is_vbo ||
+ glthread->CurrentVAO->HasUserPointer );
}
static inline bool
return ctx->API != API_OPENGL_CORE &&
(!glthread->draw_indirect_buffer_is_vbo ||
- !glthread->element_array_is_vbo);
+ glthread->CurrentVAO->IndexBufferIsUserPointer ||
+ glthread->CurrentVAO->HasUserPointer);
}
#define DEBUG_MARSHAL_PRINT_CALLS 0
struct _glapi_table *
_mesa_create_marshal_table(const struct gl_context *ctx);
-
-/**
- * Checks whether we're on a compat context for code-generated
- * glBindVertexArray().
- *
- * In order to decide whether a draw call uses only VBOs for vertex and index
- * buffers, we track the current vertex and index buffer bindings by
- * glBindBuffer(). However, the index buffer binding is stored in the vertex
- * array as opposed to the context. If we were to accurately track whether
- * the index buffer was a user pointer ot not, we'd have to track it per
- * vertex array, which would mean synchronizing with the client thread and
- * looking into the hash table to find the actual vertex array object. That's
- * more tracking than we'd like to do in the main thread, if possible.
- *
- * Instead, just punt for now and disable threading on apps using vertex
- * arrays and compat contexts. Apps using vertex arrays can probably use a
- * core context.
- */
-static inline bool
-_mesa_glthread_is_compat_bind_vertex_array(const struct gl_context *ctx)
-{
- return ctx->API != API_OPENGL_CORE;
-}
-
struct marshal_cmd_ShaderSource;
struct marshal_cmd_BindBuffer;
struct marshal_cmd_BufferData;
'main/glspirv.h',
'main/glthread.c',
'main/glthread.h',
+ 'main/glthread_varray.c',
'main/glheader.h',
'main/hash.c',
'main/hash.h',