Mesa (master): glthread: add display list support to fix state tracking with display lists

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Jan 21 00:30:50 UTC 2021


Module: Mesa
Branch: master
Commit: 33ad9e77c531fc191e2b747814cc146889d082eb
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=33ad9e77c531fc191e2b747814cc146889d082eb

Author: Marek Olšák <marek.olsak at amd.com>
Date:   Wed Dec 23 17:19:14 2020 -0500

glthread: add display list support to fix state tracking with display lists

The existing display list code is reused to call display lists from the app
thread. The util_queue_fence_wait call waits for the last call that modifies
display lists (such as glEndList and glDeleteLists), which ensures that
accessing display lists from a non-mesa thread is thread safe because
the wait guarantees that display lists are immutable during the asynchronous
display list execution.

Display lists are executed just like normal display lists except that they
call glthread functions instead of the default GL dispatch. Many calls in
display lists are skipped because glthread only tracks a few states.

Acked-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer at amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8297>

---

 src/mapi/glapi/gen/gl_API.xml    |  20 ++--
 src/mesa/main/dlist.c            |  82 +++++++++++++++
 src/mesa/main/glthread.c         |   4 +-
 src/mesa/main/glthread.h         |   9 ++
 src/mesa/main/glthread_marshal.h | 215 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 321 insertions(+), 9 deletions(-)

diff --git a/src/mapi/glapi/gen/gl_API.xml b/src/mapi/glapi/gen/gl_API.xml
index 704028a3e73..9abc045ce87 100644
--- a/src/mapi/glapi/gen/gl_API.xml
+++ b/src/mapi/glapi/gen/gl_API.xml
@@ -1111,23 +1111,25 @@
     <type name="DEBUGPROC" size="4" pointer="true"/>
 
     <function name="NewList" deprecated="3.1"
-              marshal_call_after="ctx->GLThread.ListMode = mode;">
+              marshal_call_after="_mesa_glthread_NewList(ctx, list, mode);">
         <param name="list" type="GLuint"/>
         <param name="mode" type="GLenum"/>
         <glx sop="101"/>
     </function>
 
     <function name="EndList" deprecated="3.1"
-              marshal_call_after="ctx->GLThread.ListMode = 0;">
+              marshal_call_after="_mesa_glthread_EndList(ctx);">
         <glx sop="102"/>
     </function>
 
-    <function name="CallList" deprecated="3.1">
+    <function name="CallList" deprecated="3.1"
+              marshal_call_after="_mesa_glthread_CallList(ctx, list);">
         <param name="list" type="GLuint"/>
         <glx rop="1"/>
     </function>
 
-    <function name="CallLists" deprecated="3.1">
+    <function name="CallLists" deprecated="3.1"
+              marshal_call_after="_mesa_glthread_CallLists(ctx, n, type, lists);">
         <param name="n" type="GLsizei" counter="true"/>
         <param name="type" type="GLenum"/>
         <param name="lists" type="const GLvoid *" variable_param="type" count="n"
@@ -1135,7 +1137,8 @@
         <glx rop="2" large="true"/>
     </function>
 
-    <function name="DeleteLists" deprecated="3.1">
+    <function name="DeleteLists" deprecated="3.1"
+              marshal_call_after="_mesa_glthread_DeleteLists(ctx, range);">
         <param name="list" type="GLuint"/>
         <param name="range" type="GLsizei"/>
         <glx sop="103"/>
@@ -1147,7 +1150,8 @@
         <glx sop="104"/>
     </function>
 
-    <function name="ListBase" deprecated="3.1">
+    <function name="ListBase" deprecated="3.1"
+              marshal_call_after="_mesa_glthread_ListBase(ctx, base);">
         <param name="base" type="GLuint"/>
         <glx rop="3"/>
     </function>
@@ -2376,13 +2380,13 @@
     </function>
 
     <function name="Disable" es1="1.0" es2="2.0"
-              marshal_call_after="if (cap == GL_PRIMITIVE_RESTART || cap == GL_PRIMITIVE_RESTART_FIXED_INDEX) _mesa_glthread_set_prim_restart(ctx, cap, false);">
+              marshal_call_after="_mesa_glthread_Disable(ctx, cap);">
         <param name="cap" type="GLenum"/>
         <glx rop="138" handcode="client"/>
     </function>
 
     <function name="Enable" es1="1.0" es2="2.0"
-              marshal_call_after='if (cap == GL_PRIMITIVE_RESTART || cap == GL_PRIMITIVE_RESTART_FIXED_INDEX) { _mesa_glthread_set_prim_restart(ctx, cap, true); } else if (cap == GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB) { _mesa_glthread_disable(ctx, "Enable(DEBUG_OUTPUT_SYNCHRONOUS)"); }'>
+              marshal_call_after='_mesa_glthread_Enable(ctx, cap);'>
         <param name="cap" type="GLenum"/>
         <glx rop="139" handcode="client"/>
     </function>
diff --git a/src/mesa/main/dlist.c b/src/mesa/main/dlist.c
index 5c8985e8755..067fda4cad8 100644
--- a/src/mesa/main/dlist.c
+++ b/src/mesa/main/dlist.c
@@ -63,6 +63,7 @@
 #include "varray.h"
 #include "arbprogram.h"
 #include "transformfeedback.h"
+#include "glthread_marshal.h"
 
 #include "math/m_matrix.h"
 
@@ -14990,6 +14991,87 @@ print_list(struct gl_context *ctx, GLuint list, const char *fname)
 }
 
 
+void
+_mesa_glthread_execute_list(struct gl_context *ctx, GLuint list)
+{
+   struct gl_display_list *dlist;
+
+   if (list == 0 ||
+       ctx->GLThread.ListCallDepth == MAX_LIST_NESTING ||
+       !_mesa_get_list(ctx, list, &dlist))
+      return;
+
+   ctx->GLThread.ListCallDepth++;
+
+   Node *n = dlist->Head;
+
+   while (1) {
+      const OpCode opcode = n[0].opcode;
+
+      if (is_ext_opcode(opcode)) {
+         n += ctx->ListExt->Opcode[n[0].opcode - OPCODE_EXT_0].Size;
+      } else {
+         switch (opcode) {
+         case OPCODE_CALL_LIST:
+            /* Generated by glCallList(), don't add ListBase */
+            if (ctx->GLThread.ListCallDepth < MAX_LIST_NESTING)
+               _mesa_glthread_execute_list(ctx, n[1].ui);
+            break;
+         case OPCODE_CALL_LISTS:
+            if (ctx->GLThread.ListCallDepth < MAX_LIST_NESTING)
+               _mesa_glthread_CallLists(ctx, n[1].i, n[2].e, get_pointer(&n[3]));
+            break;
+         case OPCODE_DISABLE:
+            _mesa_glthread_Disable(ctx, n[1].e);
+            break;
+         case OPCODE_ENABLE:
+            _mesa_glthread_Enable(ctx, n[1].e);
+            break;
+         case OPCODE_LIST_BASE:
+            _mesa_glthread_ListBase(ctx, n[1].ui);
+            break;
+         case OPCODE_MATRIX_MODE:
+            _mesa_glthread_MatrixMode(ctx, n[1].e);
+            break;
+         case OPCODE_POP_ATTRIB:
+            _mesa_glthread_PopAttrib(ctx);
+            break;
+         case OPCODE_POP_MATRIX:
+            _mesa_glthread_PopMatrix(ctx);
+            break;
+         case OPCODE_PUSH_ATTRIB:
+            _mesa_glthread_PushAttrib(ctx, n[1].bf);
+            break;
+         case OPCODE_PUSH_MATRIX:
+            _mesa_glthread_PushMatrix(ctx);
+            break;
+         case OPCODE_ACTIVE_TEXTURE:   /* GL_ARB_multitexture */
+            _mesa_glthread_ActiveTexture(ctx, n[1].e);
+            break;
+         case OPCODE_MATRIX_PUSH:
+            _mesa_glthread_MatrixPushEXT(ctx, n[1].e);
+            break;
+         case OPCODE_MATRIX_POP:
+            _mesa_glthread_MatrixPopEXT(ctx, n[1].e);
+            break;
+         case OPCODE_CONTINUE:
+            n = (Node *)get_pointer(&n[1]);
+            continue;
+         case OPCODE_END_OF_LIST:
+            ctx->GLThread.ListCallDepth--;
+            return;
+         default:
+            /* ignore */
+            break;
+         }
+
+         /* increment n to point to next compiled command */
+         assert(InstSize[opcode] > 0);
+         n += InstSize[opcode];
+      }
+   }
+}
+
 
 /**
  * Clients may call this function to help debug display list problems.
diff --git a/src/mesa/main/glthread.c b/src/mesa/main/glthread.c
index 6316cad4e32..883d6bcc283 100644
--- a/src/mesa/main/glthread.c
+++ b/src/mesa/main/glthread.c
@@ -76,7 +76,7 @@ glthread_unmarshal_batch(void *job, int thread_index)
    unsigned batch_index = batch - ctx->GLThread.batches;
    /* Atomically set this to -1 if it's equal to batch_index. */
    p_atomic_cmpxchg(&ctx->GLThread.LastProgramChangeBatch, batch_index, -1);
-
+   p_atomic_cmpxchg(&ctx->GLThread.LastDListChangeBatchIndex, batch_index, -1);
 }
 
 static void
@@ -139,6 +139,8 @@ _mesa_glthread_init(struct gl_context *ctx)
 
    ctx->CurrentClientDispatch = ctx->MarshalExec;
 
+   glthread->LastDListChangeBatchIndex = -1;
+
    /* Execute the thread initialization function in the thread. */
    struct util_queue_fence fence;
    util_queue_fence_init(&fence);
diff --git a/src/mesa/main/glthread.h b/src/mesa/main/glthread.h
index bc1b751c86b..a7893af364e 100644
--- a/src/mesa/main/glthread.h
+++ b/src/mesa/main/glthread.h
@@ -155,6 +155,8 @@ struct glthread_state
 
    /** Display lists. */
    GLenum ListMode; /**< Zero if not inside display list, else list mode. */
+   unsigned ListBase;
+   unsigned ListCallDepth;
 
    /** For L3 cache pinning. */
    unsigned pin_thread_counter;
@@ -210,6 +212,12 @@ struct glthread_state
     */
    int LastProgramChangeBatch;
 
+   /**
+    * The batch index of the last occurence of glEndList or
+    * glDeleteLists or -1 if there is no such enqueued call.
+    */
+   int LastDListChangeBatchIndex;
+
    /** Basic matrix state tracking. */
    int ActiveTexture;
    GLenum MatrixMode;
@@ -234,6 +242,7 @@ void _mesa_glthread_upload(struct gl_context *ctx, const void *data,
 void _mesa_glthread_reset_vao(struct glthread_vao *vao);
 void _mesa_error_glthread_safe(struct gl_context *ctx, GLenum error,
                                bool glthread, const char *format, ...);
+void _mesa_glthread_execute_list(struct gl_context *ctx, GLuint list);
 
 void _mesa_glthread_BindBuffer(struct gl_context *ctx, GLenum target,
                                GLuint buffer);
diff --git a/src/mesa/main/glthread_marshal.h b/src/mesa/main/glthread_marshal.h
index 0607dc4397a..5d91095edeb 100644
--- a/src/mesa/main/glthread_marshal.h
+++ b/src/mesa/main/glthread_marshal.h
@@ -423,9 +423,36 @@ _mesa_get_matrix_index(struct gl_context *ctx, GLenum mode)
    return M_DUMMY;
 }
 
+static inline void
+_mesa_glthread_Enable(struct gl_context *ctx, GLenum cap)
+{
+   if (ctx->GLThread.ListMode == GL_COMPILE)
+      return;
+
+   if (cap == GL_PRIMITIVE_RESTART ||
+       cap == GL_PRIMITIVE_RESTART_FIXED_INDEX)
+      _mesa_glthread_set_prim_restart(ctx, cap, true);
+   else if (cap == GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB)
+      _mesa_glthread_disable(ctx, "Enable(DEBUG_OUTPUT_SYNCHRONOUS)");
+}
+
+static inline void
+_mesa_glthread_Disable(struct gl_context *ctx, GLenum cap)
+{
+   if (ctx->GLThread.ListMode == GL_COMPILE)
+      return;
+
+   if (cap == GL_PRIMITIVE_RESTART ||
+       cap == GL_PRIMITIVE_RESTART_FIXED_INDEX)
+      _mesa_glthread_set_prim_restart(ctx, cap, false);
+}
+
 static inline void
 _mesa_glthread_PushAttrib(struct gl_context *ctx, GLbitfield mask)
 {
+   if (ctx->GLThread.ListMode == GL_COMPILE)
+      return;
+
    struct glthread_attrib_node *attr =
       &ctx->GLThread.AttribStack[ctx->GLThread.AttribStackDepth++];
 
@@ -441,6 +468,9 @@ _mesa_glthread_PushAttrib(struct gl_context *ctx, GLbitfield mask)
 static inline void
 _mesa_glthread_PopAttrib(struct gl_context *ctx)
 {
+   if (ctx->GLThread.ListMode == GL_COMPILE)
+      return;
+
    struct glthread_attrib_node *attr =
       &ctx->GLThread.AttribStack[--ctx->GLThread.AttribStackDepth];
    unsigned mask = attr->Mask;
@@ -457,18 +487,27 @@ _mesa_glthread_PopAttrib(struct gl_context *ctx)
 static inline void
 _mesa_glthread_MatrixPushEXT(struct gl_context *ctx, GLenum matrixMode)
 {
+   if (ctx->GLThread.ListMode == GL_COMPILE)
+      return;
+
    ctx->GLThread.MatrixStackDepth[_mesa_get_matrix_index(ctx, matrixMode)]++;
 }
 
 static inline void
 _mesa_glthread_MatrixPopEXT(struct gl_context *ctx, GLenum matrixMode)
 {
+   if (ctx->GLThread.ListMode == GL_COMPILE)
+      return;
+
    ctx->GLThread.MatrixStackDepth[_mesa_get_matrix_index(ctx, matrixMode)]--;
 }
 
 static inline void
 _mesa_glthread_ActiveTexture(struct gl_context *ctx, GLenum texture)
 {
+   if (ctx->GLThread.ListMode == GL_COMPILE)
+      return;
+
    ctx->GLThread.ActiveTexture = texture - GL_TEXTURE0;
    if (ctx->GLThread.MatrixMode == GL_TEXTURE)
       ctx->GLThread.MatrixIndex = _mesa_get_matrix_index(ctx, texture);
@@ -477,20 +516,196 @@ _mesa_glthread_ActiveTexture(struct gl_context *ctx, GLenum texture)
 static inline void
 _mesa_glthread_PushMatrix(struct gl_context *ctx)
 {
+   if (ctx->GLThread.ListMode == GL_COMPILE)
+      return;
+
    ctx->GLThread.MatrixStackDepth[ctx->GLThread.MatrixIndex]++;
 }
 
 static inline void
 _mesa_glthread_PopMatrix(struct gl_context *ctx)
 {
+   if (ctx->GLThread.ListMode == GL_COMPILE)
+      return;
+
    ctx->GLThread.MatrixStackDepth[ctx->GLThread.MatrixIndex]--;
 }
 
 static inline void
 _mesa_glthread_MatrixMode(struct gl_context *ctx, GLenum mode)
 {
+   if (ctx->GLThread.ListMode == GL_COMPILE)
+      return;
+
    ctx->GLThread.MatrixIndex = _mesa_get_matrix_index(ctx, mode);
    ctx->GLThread.MatrixMode = mode;
 }
 
+static inline void
+_mesa_glthread_ListBase(struct gl_context *ctx, GLuint base)
+{
+   if (ctx->GLThread.ListMode == GL_COMPILE)
+      return;
+
+   ctx->GLThread.ListBase = base;
+}
+
+static inline void
+_mesa_glthread_CallList(struct gl_context *ctx, GLuint list)
+{
+   if (ctx->GLThread.ListMode == GL_COMPILE)
+      return;
+
+   /* Wait for all glEndList and glDeleteLists calls to finish to ensure that
+    * all display lists are up to date and the driver thread is not
+    * modifiying them. We will be executing them in the application thread.
+    */
+   int batch = p_atomic_read(&ctx->GLThread.LastDListChangeBatchIndex);
+   if (batch != -1) {
+      util_queue_fence_wait(&ctx->GLThread.batches[batch].fence);
+      p_atomic_set(&ctx->GLThread.LastDListChangeBatchIndex, -1);
+   }
+
+   /* Clear GL_COMPILE_AND_EXECUTE if needed. We only execute here. */
+   unsigned saved_mode = ctx->GLThread.ListMode;
+   ctx->GLThread.ListMode = 0;
+
+   _mesa_glthread_execute_list(ctx, list);
+
+   ctx->GLThread.ListMode = saved_mode;
+}
+
+static inline void
+_mesa_glthread_CallLists(struct gl_context *ctx, GLsizei n, GLenum type,
+                         const GLvoid *lists)
+{
+   if (ctx->GLThread.ListMode == GL_COMPILE)
+      return;
+
+   if (n <= 0 || !lists)
+      return;
+
+   /* Wait for all glEndList and glDeleteLists calls to finish to ensure that
+    * all display lists are up to date and the driver thread is not
+    * modifiying them. We will be executing them in the application thread.
+    */
+   int batch = p_atomic_read(&ctx->GLThread.LastDListChangeBatchIndex);
+   if (batch != -1) {
+      util_queue_fence_wait(&ctx->GLThread.batches[batch].fence);
+      p_atomic_set(&ctx->GLThread.LastDListChangeBatchIndex, -1);
+   }
+
+   /* Clear GL_COMPILE_AND_EXECUTE if needed. We only execute here. */
+   unsigned saved_mode = ctx->GLThread.ListMode;
+   ctx->GLThread.ListMode = 0;
+
+   unsigned base = ctx->GLThread.ListBase;
+
+   GLbyte *bptr;
+   GLubyte *ubptr;
+   GLshort *sptr;
+   GLushort *usptr;
+   GLint *iptr;
+   GLuint *uiptr;
+   GLfloat *fptr;
+
+   switch (type) {
+   case GL_BYTE:
+      bptr = (GLbyte *) lists;
+      for (unsigned i = 0; i < n; i++)
+         _mesa_glthread_CallList(ctx, base + bptr[i]);
+      break;
+   case GL_UNSIGNED_BYTE:
+      ubptr = (GLubyte *) lists;
+      for (unsigned i = 0; i < n; i++)
+         _mesa_glthread_CallList(ctx, base + ubptr[i]);
+      break;
+   case GL_SHORT:
+      sptr = (GLshort *) lists;
+      for (unsigned i = 0; i < n; i++)
+         _mesa_glthread_CallList(ctx, base + sptr[i]);
+      break;
+   case GL_UNSIGNED_SHORT:
+      usptr = (GLushort *) lists;
+      for (unsigned i = 0; i < n; i++)
+         _mesa_glthread_CallList(ctx, base + usptr[i]);
+      break;
+   case GL_INT:
+      iptr = (GLint *) lists;
+      for (unsigned i = 0; i < n; i++)
+         _mesa_glthread_CallList(ctx, base + iptr[i]);
+      break;
+   case GL_UNSIGNED_INT:
+      uiptr = (GLuint *) lists;
+      for (unsigned i = 0; i < n; i++)
+         _mesa_glthread_CallList(ctx, base + uiptr[i]);
+      break;
+   case GL_FLOAT:
+      fptr = (GLfloat *) lists;
+      for (unsigned i = 0; i < n; i++)
+         _mesa_glthread_CallList(ctx, base + fptr[i]);
+      break;
+   case GL_2_BYTES:
+      ubptr = (GLubyte *) lists;
+      for (unsigned i = 0; i < n; i++) {
+         _mesa_glthread_CallList(ctx, base +
+                                 (GLint)ubptr[2 * i] * 256 +
+                                 (GLint)ubptr[2 * i + 1]);
+      }
+      break;
+   case GL_3_BYTES:
+      ubptr = (GLubyte *) lists;
+      for (unsigned i = 0; i < n; i++) {
+         _mesa_glthread_CallList(ctx, base +
+                                 (GLint)ubptr[3 * i] * 65536 +
+                                 (GLint)ubptr[3 * i + 1] * 256 +
+                                 (GLint)ubptr[3 * i + 2]);
+      }
+      break;
+   case GL_4_BYTES:
+      ubptr = (GLubyte *) lists;
+      for (unsigned i = 0; i < n; i++) {
+         _mesa_glthread_CallList(ctx, base +
+                                 (GLint)ubptr[4 * i] * 16777216 +
+                                 (GLint)ubptr[4 * i + 1] * 65536 +
+                                 (GLint)ubptr[4 * i + 2] * 256 +
+                                 (GLint)ubptr[4 * i + 3]);
+      }
+      break;
+   }
+
+   ctx->GLThread.ListMode = saved_mode;
+}
+
+static inline void
+_mesa_glthread_NewList(struct gl_context *ctx, GLuint list, GLuint mode)
+{
+   if (!ctx->GLThread.ListMode)
+      ctx->GLThread.ListMode = mode;
+}
+
+static inline void
+_mesa_glthread_EndList(struct gl_context *ctx)
+{
+   if (!ctx->GLThread.ListMode)
+      return;
+
+   ctx->GLThread.ListMode = 0;
+
+   /* Track the last display list change. */
+   p_atomic_set(&ctx->GLThread.LastDListChangeBatchIndex, ctx->GLThread.next);
+   _mesa_glthread_flush_batch(ctx);
+}
+
+static inline void
+_mesa_glthread_DeleteLists(struct gl_context *ctx, GLsizei range)
+{
+   if (range < 0)
+      return;
+
+   /* Track the last display list change. */
+   p_atomic_set(&ctx->GLThread.LastDListChangeBatchIndex, ctx->GLThread.next);
+   _mesa_glthread_flush_batch(ctx);
+}
+
 #endif /* MARSHAL_H */



More information about the mesa-commit mailing list