[Mesa-dev] [PATCH 12/26] mesa: Create pointers for multithread marshalling dispatch table.

Marek Olšák maraeo at gmail.com
Wed Feb 8 18:03:26 UTC 2017


From: Paul Berry <stereotype441 at gmail.com>

This patch splits the context's CurrentDispatch pointer into two
pointers, CurrentClientDispatch, and CurrentServerDispatch, so that
when doing multithread marshalling, we can distinguish between the
dispatch table that's being used by the client (to serialize GL calls
into the marshal buffer) and the dispatch table that's being used by
the server (to execute the GL calls).
---
 src/mapi/glapi/gen/gl_apitemp.py |  8 ++++----
 src/mesa/main/context.c          | 13 +++++++------
 src/mesa/main/dlist.c            | 28 ++++++++++++++++++++--------
 src/mesa/main/glthread.c         |  7 +++++++
 src/mesa/main/mtypes.h           | 21 ++++++++++++++++++---
 src/mesa/main/robustness.c       |  4 ++--
 src/mesa/main/varray.c           |  8 ++++----
 src/mesa/vbo/vbo_exec_api.c      | 14 +++++++-------
 8 files changed, 69 insertions(+), 34 deletions(-)

diff --git a/src/mapi/glapi/gen/gl_apitemp.py b/src/mapi/glapi/gen/gl_apitemp.py
index 5e985a2..4951692 100644
--- a/src/mapi/glapi/gen/gl_apitemp.py
+++ b/src/mapi/glapi/gen/gl_apitemp.py
@@ -127,25 +127,25 @@ class PrintGlOffsets(gl_XML.gl_print_base):
  *   KEYWORD2 - usually nothing, but might be __stdcall on Win32
  *   NAME(n)  - builds the final function name (usually add "gl" prefix)
  *   DISPATCH(func, args, msg) - code to do dispatch of named function.
  *                               msg is a printf-style debug message.
  *   RETURN_DISPATCH(func, args, msg) - code to do dispatch with a return value
  *
  * Here is an example which generates the usual OpenGL functions:
  *   #define KEYWORD1
  *   #define KEYWORD2
  *   #define NAME(func)  gl##func
- *   #define DISPATCH(func, args, msg)                           \\
- *          struct _glapi_table *dispatch = CurrentDispatch;     \\
+ *   #define DISPATCH(func, args, msg)                             \\
+ *          struct _glapi_table *dispatch = CurrentClientDispatch; \\
  *          (*dispatch->func) args
- *   #define RETURN DISPATCH(func, args, msg)                    \\
- *          struct _glapi_table *dispatch = CurrentDispatch;     \\
+ *   #define RETURN DISPATCH(func, args, msg)                      \\
+ *          struct _glapi_table *dispatch = CurrentClientDispatch; \\
  *          return (*dispatch->func) args
  *
  */
 
 
 #if defined( NAME )
 #ifndef KEYWORD1
 #define KEYWORD1
 #endif
 
diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c
index 837b389..c00cced 100644
--- a/src/mesa/main/context.c
+++ b/src/mesa/main/context.c
@@ -1204,21 +1204,21 @@ _mesa_initialize_context(struct gl_context *ctx,
    _mesa_reference_shared_state(ctx, &ctx->Shared, shared);
 
    if (!init_attrib_groups( ctx ))
       goto fail;
 
    /* setup the API dispatch tables with all nop functions */
    ctx->OutsideBeginEnd = alloc_dispatch_table();
    if (!ctx->OutsideBeginEnd)
       goto fail;
    ctx->Exec = ctx->OutsideBeginEnd;
-   ctx->CurrentDispatch = ctx->OutsideBeginEnd;
+   ctx->CurrentClientDispatch = ctx->CurrentServerDispatch = ctx->OutsideBeginEnd;
 
    ctx->FragmentProgram._MaintainTexEnvProgram
       = (getenv("MESA_TEX_PROG") != NULL);
 
    ctx->VertexProgram._MaintainTnlProgram
       = (getenv("MESA_TNL_PROG") != NULL);
    if (ctx->VertexProgram._MaintainTnlProgram) {
       /* this is required... */
       ctx->FragmentProgram._MaintainTexEnvProgram = GL_TRUE;
    }
@@ -1335,20 +1335,21 @@ _mesa_free_context_data( struct gl_context *ctx )
    _mesa_reference_buffer_object(ctx, &ctx->Pack.BufferObj, NULL);
    _mesa_reference_buffer_object(ctx, &ctx->Unpack.BufferObj, NULL);
    _mesa_reference_buffer_object(ctx, &ctx->DefaultPacking.BufferObj, NULL);
    _mesa_reference_buffer_object(ctx, &ctx->Array.ArrayBufferObj, NULL);
 
    /* free dispatch tables */
    free(ctx->BeginEnd);
    free(ctx->OutsideBeginEnd);
    free(ctx->Save);
    free(ctx->ContextLost);
+   free(ctx->MarshalExec);
 
    ralloc_free(ctx->Cache);
 
    /* Shared context state (display lists, textures, etc) */
    _mesa_reference_shared_state(ctx, &ctx->Shared, NULL);
 
    /* needs to be after freeing shared state */
    _mesa_free_display_list_data(ctx);
 
    _mesa_free_errors_data(ctx);
@@ -1661,21 +1662,21 @@ _mesa_make_current( struct gl_context *newCtx,
    assert(_mesa_get_current_context() == newCtx);
 
    if (!newCtx) {
       _glapi_set_dispatch(NULL);  /* none current */
       if (curCtx) {
          _mesa_reference_framebuffer(&curCtx->WinSysDrawBuffer, NULL);
          _mesa_reference_framebuffer(&curCtx->WinSysReadBuffer, NULL);
       }
    }
    else {
-      _glapi_set_dispatch(newCtx->CurrentDispatch);
+      _glapi_set_dispatch(newCtx->CurrentClientDispatch);
 
       if (drawBuffer && readBuffer) {
          assert(_mesa_is_winsys_fbo(drawBuffer));
          assert(_mesa_is_winsys_fbo(readBuffer));
          _mesa_reference_framebuffer(&newCtx->WinSysDrawBuffer, drawBuffer);
          _mesa_reference_framebuffer(&newCtx->WinSysReadBuffer, readBuffer);
 
          /*
           * Only set the context's Draw/ReadBuffer fields if they're NULL
           * or not bound to a user-created FBO.
@@ -1763,33 +1764,33 @@ _mesa_share_state(struct gl_context *ctx, struct gl_context *ctxToShare)
 struct gl_context *
 _mesa_get_current_context( void )
 {
    return (struct gl_context *) _glapi_get_context();
 }
 
 
 /**
  * Get context's current API dispatch table.
  *
- * It'll either be the immediate-mode execute dispatcher or the display list
- * compile dispatcher.
+ * It'll either be the immediate-mode execute dispatcher, the display list
+ * compile dispatcher, or the thread marshalling dispatcher.
  *
  * \param ctx GL context.
  *
  * \return pointer to dispatch_table.
  *
- * Simply returns __struct gl_contextRec::CurrentDispatch.
+ * Simply returns __struct gl_contextRec::CurrentClientDispatch.
  */
 struct _glapi_table *
 _mesa_get_dispatch(struct gl_context *ctx)
 {
-   return ctx->CurrentDispatch;
+   return ctx->CurrentClientDispatch;
 }
 
 /*@}*/
 
 
 /**********************************************************************/
 /** \name Miscellaneous functions                                     */
 /**********************************************************************/
 /*@{*/
 
diff --git a/src/mesa/main/dlist.c b/src/mesa/main/dlist.c
index 2976f62..7e44054 100644
--- a/src/mesa/main/dlist.c
+++ b/src/mesa/main/dlist.c
@@ -9333,22 +9333,25 @@ _mesa_NewList(GLuint name, GLenum mode)
    /* Reset accumulated list state */
    invalidate_saved_current_state( ctx );
 
    /* Allocate new display list */
    ctx->ListState.CurrentList = make_list(name, BLOCK_SIZE);
    ctx->ListState.CurrentBlock = ctx->ListState.CurrentList->Head;
    ctx->ListState.CurrentPos = 0;
 
    vbo_save_NewList(ctx, name, mode);
 
-   ctx->CurrentDispatch = ctx->Save;
-   _glapi_set_dispatch(ctx->CurrentDispatch);
+   ctx->CurrentServerDispatch = ctx->Save;
+   _glapi_set_dispatch(ctx->CurrentServerDispatch);
+   if (ctx->MarshalExec == NULL) {
+      ctx->CurrentClientDispatch = ctx->CurrentServerDispatch;
+   }
 }
 
 
 /**
  * End definition of current display list.
  */
 void GLAPIENTRY
 _mesa_EndList(void)
 {
    GET_CURRENT_CONTEXT(ctx);
@@ -9389,22 +9392,25 @@ _mesa_EndList(void)
 
    if (MESA_VERBOSE & VERBOSE_DISPLAY_LIST)
       mesa_print_display_list(ctx->ListState.CurrentList->Name);
 
    ctx->ListState.CurrentList = NULL;
    ctx->ListState.CurrentBlock = NULL;
    ctx->ListState.CurrentPos = 0;
    ctx->ExecuteFlag = GL_TRUE;
    ctx->CompileFlag = GL_FALSE;
 
-   ctx->CurrentDispatch = ctx->Exec;
-   _glapi_set_dispatch(ctx->CurrentDispatch);
+   ctx->CurrentServerDispatch = ctx->Exec;
+   _glapi_set_dispatch(ctx->CurrentServerDispatch);
+   if (ctx->MarshalExec == NULL) {
+      ctx->CurrentClientDispatch = ctx->CurrentServerDispatch;
+   }
 }
 
 
 void GLAPIENTRY
 _mesa_CallList(GLuint list)
 {
    GLboolean save_compile_flag;
    GET_CURRENT_CONTEXT(ctx);
    FLUSH_CURRENT(ctx, 0);
 
@@ -9425,22 +9431,25 @@ _mesa_CallList(GLuint list)
    save_compile_flag = ctx->CompileFlag;
    if (save_compile_flag) {
       ctx->CompileFlag = GL_FALSE;
    }
 
    execute_list(ctx, list);
    ctx->CompileFlag = save_compile_flag;
 
    /* also restore API function pointers to point to "save" versions */
    if (save_compile_flag) {
-      ctx->CurrentDispatch = ctx->Save;
-      _glapi_set_dispatch(ctx->CurrentDispatch);
+      ctx->CurrentServerDispatch = ctx->Save;
+       _glapi_set_dispatch(ctx->CurrentServerDispatch);
+      if (ctx->MarshalExec == NULL) {
+         ctx->CurrentClientDispatch = ctx->CurrentServerDispatch;
+      }
    }
 }
 
 
 /**
  * Try to execute a glCallLists() command where the display lists contain
  * glBitmap commands with a texture atlas.
  * \return true for success, false otherwise
  */
 static bool
@@ -9548,22 +9557,25 @@ _mesa_CallLists(GLsizei n, GLenum type, const GLvoid * lists)
 
    for (i = 0; i < n; i++) {
       GLuint list = (GLuint) (ctx->List.ListBase + translate_id(i, type, lists));
       execute_list(ctx, list);
    }
 
    ctx->CompileFlag = save_compile_flag;
 
    /* also restore API function pointers to point to "save" versions */
    if (save_compile_flag) {
-      ctx->CurrentDispatch = ctx->Save;
-      _glapi_set_dispatch(ctx->CurrentDispatch);
+      ctx->CurrentServerDispatch = ctx->Save;
+      _glapi_set_dispatch(ctx->CurrentServerDispatch);
+      if (ctx->MarshalExec == NULL) {
+         ctx->CurrentClientDispatch = ctx->CurrentServerDispatch;
+      }
    }
 }
 
 
 /**
  * Set the offset added to list numbers in glCallLists.
  */
 void GLAPIENTRY
 _mesa_ListBase(GLuint base)
 {
diff --git a/src/mesa/main/glthread.c b/src/mesa/main/glthread.c
index 76eb0cf..8877a69 100644
--- a/src/mesa/main/glthread.c
+++ b/src/mesa/main/glthread.c
@@ -47,20 +47,22 @@ glthread_allocate_batch(struct gl_context *ctx)
    /* TODO: handle memory allocation failure. */
    glthread->batch = calloc(1, sizeof(*glthread->batch));
    if (!glthread->batch)
       return;
    glthread->batch->buffer = malloc(MARSHAL_MAX_CMD_SIZE);
 }
 
 static void
 glthread_unmarshal_batch(struct gl_context *ctx, struct glthread_batch *batch)
 {
+   _glapi_set_dispatch(ctx->CurrentServerDispatch);
+
    free(batch->buffer);
    free(batch);
 }
 
 static void *
 glthread_worker(void *data)
 {
    struct gl_context *ctx = data;
    struct glthread_state *glthread = ctx->GLThread;
 
@@ -149,20 +151,24 @@ _mesa_glthread_destroy(struct gl_context *ctx)
    /* Due to the join above, there should be one empty batch allocated at this
     * point, and no batches queued.
     */
    assert(!glthread->batch->used);
    assert(!glthread->batch->next);
    free(glthread->batch);
    assert(!glthread->batch_queue);
 
    free(glthread);
    ctx->GLThread = NULL;
+
+   /* Remove ourselves from the dispatch table. */
+   ctx->CurrentClientDispatch = ctx->CurrentServerDispatch;
+   _glapi_set_dispatch(ctx->CurrentClientDispatch);
 }
 
 void
 _mesa_glthread_flush_batch(struct gl_context *ctx)
 {
    struct glthread_state *glthread = ctx->GLThread;
    struct glthread_batch *batch;
 
    if (!glthread)
       return;
@@ -176,20 +182,21 @@ _mesa_glthread_flush_batch(struct gl_context *ctx)
     */
    glthread_allocate_batch(ctx);
 
    /* Debug: execute the batch immediately from this thread.
     *
     * Note that glthread_unmarshal_batch() changes the dispatch table so we'll
     * need to restore it when it returns.
     */
    if (false) {
       glthread_unmarshal_batch(ctx, batch);
+      _glapi_set_dispatch(ctx->CurrentClientDispatch);
       return;
    }
 
    pthread_mutex_lock(&glthread->mutex);
    *glthread->batch_queue_tail = batch;
    glthread->batch_queue_tail = &batch->next;
    pthread_cond_broadcast(&glthread->new_work);
    pthread_mutex_unlock(&glthread->mutex);
 }
 
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 72d8b9d..0a8cbd1 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -4328,20 +4328,21 @@ struct gl_subroutine_index_binding
  * sub classes.
  */
 struct gl_context
 {
    /** State possibly shared with other contexts in the address space */
    struct gl_shared_state *Shared;
 
    /** \name API function pointer tables */
    /*@{*/
    gl_api API;
+
    /**
     * The current dispatch table for non-displaylist-saving execution, either
     * BeginEnd or OutsideBeginEnd
     */
    struct _glapi_table *Exec;
    /**
     * The normal dispatch table for non-displaylist-saving, non-begin/end
     */
    struct _glapi_table *OutsideBeginEnd;
    /** The dispatch table used between glNewList() and glEndList() */
@@ -4350,24 +4351,38 @@ struct gl_context
     * The dispatch table used between glBegin() and glEnd() (outside of a
     * display list).  Only valid functions between those two are set, which is
     * mostly just the set in a GLvertexformat struct.
     */
    struct _glapi_table *BeginEnd;
    /**
     * Dispatch table for when a graphics reset has happened.
     */
    struct _glapi_table *ContextLost;
    /**
-    * Tracks the current dispatch table out of the 4 above, so that it can be
-    * re-set on glXMakeCurrent().
+    * Dispatch table used to marshal API calls from the client program to a
+    * separate server thread.  NULL if API calls are not being marshalled to
+    * another thread.
+    */
+   struct _glapi_table *MarshalExec;
+   /**
+    * Dispatch table currently in use for fielding API calls from the client
+    * program.  If API calls are being marshalled to another thread, this ==
+    * MarshalExec.  Otherwise it == CurrentServerDispatch.
     */
-   struct _glapi_table *CurrentDispatch;
+   struct _glapi_table *CurrentClientDispatch;
+
+   /**
+    * Dispatch table currently in use for performing API calls.  == Save or
+    * Exec.
+    */
+   struct _glapi_table *CurrentServerDispatch;
+
    /*@}*/
 
    struct glthread_state *GLThread;
 
    struct gl_config Visual;
    struct gl_framebuffer *DrawBuffer;	/**< buffer for writing */
    struct gl_framebuffer *ReadBuffer;	/**< buffer for reading */
    struct gl_framebuffer *WinSysDrawBuffer;  /**< set with MakeCurrent */
    struct gl_framebuffer *WinSysReadBuffer;  /**< set with MakeCurrent */
 
diff --git a/src/mesa/main/robustness.c b/src/mesa/main/robustness.c
index f54d9f3..47402a2 100644
--- a/src/mesa/main/robustness.c
+++ b/src/mesa/main/robustness.c
@@ -94,22 +94,22 @@ _mesa_set_context_lost_dispatch(struct gl_context *ctx)
        *
        *        + GetQueryObjectuiv with <pname> QUERY_RESULT_AVAILABLE
        *          ignores the other parameters and returns TRUE in <params>."
        */
       SET_GetError(ctx->ContextLost, _mesa_GetError);
       SET_GetGraphicsResetStatusARB(ctx->ContextLost, _mesa_GetGraphicsResetStatusARB);
       SET_GetSynciv(ctx->ContextLost, _context_lost_GetSynciv);
       SET_GetQueryObjectuiv(ctx->ContextLost, _context_lost_GetQueryObjectuiv);
    }
 
-   ctx->CurrentDispatch = ctx->ContextLost;
-   _glapi_set_dispatch(ctx->CurrentDispatch);
+   ctx->CurrentServerDispatch = ctx->ContextLost;
+   _glapi_set_dispatch(ctx->CurrentServerDispatch);
 }
 
 /**
  * Returns an error code specified by GL_ARB_robustness, or GL_NO_ERROR.
  * \return current context status
  */
 GLenum GLAPIENTRY
 _mesa_GetGraphicsResetStatusARB( void )
 {
    GET_CURRENT_CONTEXT(ctx);
diff --git a/src/mesa/main/varray.c b/src/mesa/main/varray.c
index c428355..92e3f4d 100644
--- a/src/mesa/main/varray.c
+++ b/src/mesa/main/varray.c
@@ -1551,41 +1551,41 @@ void GLAPIENTRY
 _mesa_MultiDrawArrays( GLenum mode, const GLint *first,
                           const GLsizei *count, GLsizei primcount )
 {
    GET_CURRENT_CONTEXT(ctx);
    GLint i;
 
    FLUSH_VERTICES(ctx, 0);
 
    for (i = 0; i < primcount; i++) {
       if (count[i] > 0) {
-         CALL_DrawArrays(ctx->CurrentDispatch, (mode, first[i], count[i]));
+         CALL_DrawArrays(ctx->CurrentClientDispatch, (mode, first[i], count[i]));
       }
    }
 }
 
 
 /* GL_IBM_multimode_draw_arrays */
 void GLAPIENTRY
 _mesa_MultiModeDrawArraysIBM( const GLenum * mode, const GLint * first,
 			      const GLsizei * count,
 			      GLsizei primcount, GLint modestride )
 {
    GET_CURRENT_CONTEXT(ctx);
    GLint i;
 
    FLUSH_VERTICES(ctx, 0);
 
    for ( i = 0 ; i < primcount ; i++ ) {
       if ( count[i] > 0 ) {
          GLenum m = *((GLenum *) ((GLubyte *) mode + i * modestride));
-	 CALL_DrawArrays(ctx->CurrentDispatch, ( m, first[i], count[i] ));
+	 CALL_DrawArrays(ctx->CurrentServerDispatch, ( m, first[i], count[i] ));
       }
    }
 }
 
 
 /* GL_IBM_multimode_draw_arrays */
 void GLAPIENTRY
 _mesa_MultiModeDrawElementsIBM( const GLenum * mode, const GLsizei * count,
 				GLenum type, const GLvoid * const * indices,
 				GLsizei primcount, GLint modestride )
@@ -1593,22 +1593,22 @@ _mesa_MultiModeDrawElementsIBM( const GLenum * mode, const GLsizei * count,
    GET_CURRENT_CONTEXT(ctx);
    GLint i;
 
    FLUSH_VERTICES(ctx, 0);
 
    /* XXX not sure about ARB_vertex_buffer_object handling here */
 
    for ( i = 0 ; i < primcount ; i++ ) {
       if ( count[i] > 0 ) {
          GLenum m = *((GLenum *) ((GLubyte *) mode + i * modestride));
-	 CALL_DrawElements(ctx->CurrentDispatch, ( m, count[i], type,
-                                                   indices[i] ));
+	 CALL_DrawElements(ctx->CurrentServerDispatch, ( m, count[i], type,
+							 indices[i] ));
       }
    }
 }
 
 
 /**
  * GL_NV_primitive_restart and GL 3.1
  */
 void GLAPIENTRY
 _mesa_PrimitiveRestartIndex(GLuint index)
diff --git a/src/mesa/vbo/vbo_exec_api.c b/src/mesa/vbo/vbo_exec_api.c
index fffff0b..f08fd4c 100644
--- a/src/mesa/vbo/vbo_exec_api.c
+++ b/src/mesa/vbo/vbo_exec_api.c
@@ -790,25 +790,25 @@ vbo_exec_Begin(GLenum mode)
    exec->vtx.prim[i].num_instances = 1;
    exec->vtx.prim[i].base_instance = 0;
    exec->vtx.prim[i].is_indirect = 0;
 
    ctx->Driver.CurrentExecPrimitive = mode;
 
    ctx->Exec = ctx->BeginEnd;
    /* We may have been called from a display list, in which case we should
     * leave dlist.c's dispatch table in place.
     */
-   if (ctx->CurrentDispatch == ctx->OutsideBeginEnd) {
-      ctx->CurrentDispatch = ctx->BeginEnd;
-      _glapi_set_dispatch(ctx->CurrentDispatch);
+   if (ctx->CurrentClientDispatch == ctx->OutsideBeginEnd) {
+      ctx->CurrentClientDispatch = ctx->BeginEnd;
+      _glapi_set_dispatch(ctx->CurrentClientDispatch);
    } else {
-      assert(ctx->CurrentDispatch == ctx->Save);
+      assert(ctx->CurrentClientDispatch == ctx->Save);
    }
 }
 
 
 /**
  * Try to merge / concatenate the two most recent VBO primitives.
  */
 static void
 try_vbo_merge(struct vbo_exec_context *exec)
 {
@@ -842,23 +842,23 @@ vbo_exec_End(void)
 {
    GET_CURRENT_CONTEXT( ctx );
    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
 
    if (!_mesa_inside_begin_end(ctx)) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glEnd");
       return;
    }
 
    ctx->Exec = ctx->OutsideBeginEnd;
-   if (ctx->CurrentDispatch == ctx->BeginEnd) {
-      ctx->CurrentDispatch = ctx->OutsideBeginEnd;
-      _glapi_set_dispatch(ctx->CurrentDispatch);
+   if (ctx->CurrentClientDispatch == ctx->BeginEnd) {
+      ctx->CurrentClientDispatch = ctx->OutsideBeginEnd;
+      _glapi_set_dispatch(ctx->CurrentClientDispatch);
    }
 
    if (exec->vtx.prim_count > 0) {
       /* close off current primitive */
       struct _mesa_prim *last_prim = &exec->vtx.prim[exec->vtx.prim_count - 1];
 
       last_prim->end = 1;
       last_prim->count = exec->vtx.vert_count - last_prim->start;
 
       /* Special handling for GL_LINE_LOOP */
-- 
2.7.4



More information about the mesa-dev mailing list