[Mesa-dev] [PATCH 25/25] gallium: implement the backend of threaded GL dispatch

Timothy Arceri tarceri at itsqueeze.com
Tue Mar 7 06:21:37 UTC 2017


From: Marek Olšák <marek.olsak at amd.com>

---
 src/gallium/include/state_tracker/st_api.h      | 19 +++++++++++++++++++
 src/gallium/state_trackers/dri/dri_context.c    | 10 ++++++++++
 src/gallium/state_trackers/dri/dri_drawable.c   |  6 ++++++
 src/gallium/state_trackers/dri/dri_screen.c     | 21 +++++++++++++++++++++
 src/mesa/drivers/dri/common/xmlpool/t_options.h |  4 ++++
 src/mesa/state_tracker/st_context.c             | 13 +++++++++++++
 src/mesa/state_tracker/st_manager.c             | 19 +++++++++++++++++++
 7 files changed, 92 insertions(+)

diff --git a/src/gallium/include/state_tracker/st_api.h b/src/gallium/include/state_tracker/st_api.h
index a999774..bf9a7e9 100644
--- a/src/gallium/include/state_tracker/st_api.h
+++ b/src/gallium/include/state_tracker/st_api.h
@@ -410,20 +410,33 @@ struct st_context_iface
    boolean (*share)(struct st_context_iface *stctxi,
                     struct st_context_iface *stsrci);
 
    /**
     * Look up and return the info of a resource for EGLImage.
     *
     * This function is optional.
     */
    boolean (*get_resource_for_egl_image)(struct st_context_iface *stctxi,
                                          struct st_context_resource *stres);
+
+   /**
+    * Start the thread if the API has a worker thread.
+    * Called after the context has been created and fully initialized on both
+    * sides (e.g. st/mesa and st/dri).
+    */
+   void (*start_thread)(struct st_context_iface *stctxi);
+
+   /**
+    * If the API is multithreaded, wait for all queued commands to complete.
+    * Called from the main thread.
+    */
+   void (*thread_finish)(struct st_context_iface *stctxi);
 };
 
 
 /**
  * Represent a state tracker manager.
  *
  * This interface is implemented by the state tracker manager.  It corresponds
  * to a "display" in the window system.
  */
 struct st_manager
@@ -447,20 +460,26 @@ struct st_manager
     */
    boolean (*get_egl_image)(struct st_manager *smapi,
                             void *egl_image,
                             struct st_egl_image *out);
 
    /**
     * Query an manager param.
     */
    int (*get_param)(struct st_manager *smapi,
                     enum st_manager_param param);
+
+   /**
+    * Call the loader function setBackgroundContext. Called from the worker
+    * thread.
+    */
+   void (*set_background_context)(struct st_context_iface *stctxi);
 };
 
 /**
  * Represent a rendering API such as OpenGL or OpenVG.
  *
  * Implemented by the state tracker and used by the state tracker manager.
  */
 struct st_api
 {
    /**
diff --git a/src/gallium/state_trackers/dri/dri_context.c b/src/gallium/state_trackers/dri/dri_context.c
index 3d8af65..91d2d1f 100644
--- a/src/gallium/state_trackers/dri/dri_context.c
+++ b/src/gallium/state_trackers/dri/dri_context.c
@@ -149,20 +149,27 @@ dri_create_context(gl_api api, const struct gl_config * visual,
       goto fail;
    }
    ctx->st->st_manager_private = (void *) ctx;
    ctx->stapi = stapi;
 
    if (ctx->st->cso_context) {
       ctx->pp = pp_init(ctx->st->pipe, screen->pp_enabled, ctx->st->cso_context);
       ctx->hud = hud_create(ctx->st->pipe, ctx->st->cso_context);
    }
 
+   /* Do this last. */
+   if (ctx->st->start_thread &&
+       /* the driver loader must implement this */
+       screen->sPriv->dri2.backgroundCallable &&
+       driQueryOptionb(&screen->optionCache, "mesa_glthread"))
+      ctx->st->start_thread(ctx->st);
+
    *error = __DRI_CTX_ERROR_SUCCESS;
    return GL_TRUE;
 
  fail:
    if (ctx && ctx->st)
       ctx->st->destroy(ctx->st);
 
    free(ctx);
    return GL_FALSE;
 }
@@ -215,20 +222,23 @@ GLboolean
 dri_make_current(__DRIcontext * cPriv,
 		 __DRIdrawable * driDrawPriv,
 		 __DRIdrawable * driReadPriv)
 {
    /* dri_util.c ensures cPriv is not null */
    struct dri_context *ctx = dri_context(cPriv);
    struct dri_drawable *draw = dri_drawable(driDrawPriv);
    struct dri_drawable *read = dri_drawable(driReadPriv);
    struct st_context_iface *old_st = ctx->stapi->get_current(ctx->stapi);
 
+   if (old_st && old_st->thread_finish)
+      old_st->thread_finish(old_st);
+
    /* Flush the old context here so we don't have to flush on unbind() */
    if (old_st && old_st != ctx->st)
       old_st->flush(old_st, ST_FLUSH_FRONT, NULL);
 
    ++ctx->bind_count;
 
    if (!draw && !read)
       return ctx->stapi->make_current(ctx->stapi, ctx->st, NULL, NULL);
    else if (!draw || !read)
       return GL_FALSE;
diff --git a/src/gallium/state_trackers/dri/dri_drawable.c b/src/gallium/state_trackers/dri/dri_drawable.c
index fd3b458..3c2e307 100644
--- a/src/gallium/state_trackers/dri/dri_drawable.c
+++ b/src/gallium/state_trackers/dri/dri_drawable.c
@@ -210,23 +210,27 @@ dri_drawable_validate_att(struct dri_context *ctx,
 }
 
 /**
  * These are used for GLX_EXT_texture_from_pixmap
  */
 static void
 dri_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target,
                     GLint format, __DRIdrawable *dPriv)
 {
    struct dri_context *ctx = dri_context(pDRICtx);
+   struct st_context_iface *st = ctx->st;
    struct dri_drawable *drawable = dri_drawable(dPriv);
    struct pipe_resource *pt;
 
+   if (st->thread_finish)
+      st->thread_finish(st);
+
    dri_drawable_validate_att(ctx, drawable, ST_ATTACHMENT_FRONT_LEFT);
 
    /* Use the pipe resource associated with the X drawable */
    pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
 
    if (pt) {
       enum pipe_format internal_format = pt->format;
 
       if (format == __DRI_TEXTURE_FORMAT_RGB)  {
          /* only need to cover the formats recognized by dri_fill_st_visual */
@@ -446,20 +450,22 @@ dri_flush(__DRIcontext *cPriv,
    struct st_context_iface *st;
    unsigned flush_flags;
    boolean swap_msaa_buffers = FALSE;
 
    if (!ctx) {
       assert(0);
       return;
    }
 
    st = ctx->st;
+   if (st->thread_finish)
+      st->thread_finish(st);
 
    if (drawable) {
       /* prevent recursion */
       if (drawable->flushing)
          return;
 
       drawable->flushing = TRUE;
    }
    else {
       flags &= ~__DRI2_FLUSH_DRAWABLE;
diff --git a/src/gallium/state_trackers/dri/dri_screen.c b/src/gallium/state_trackers/dri/dri_screen.c
index 9b37dff..799a264 100644
--- a/src/gallium/state_trackers/dri/dri_screen.c
+++ b/src/gallium/state_trackers/dri/dri_screen.c
@@ -26,40 +26,45 @@
  **************************************************************************/
 /*
  * Author: Keith Whitwell <keithw at vmware.com>
  * Author: Jakob Bornecrantz <wallbraker at gmail.com>
  */
 
 #include "utils.h"
 #include "xmlpool.h"
 
 #include "dri_screen.h"
+#include "dri_context.h"
 
 #include "util/u_inlines.h"
 #include "pipe/p_screen.h"
 #include "pipe/p_format.h"
 #include "pipe-loader/pipe_loader.h"
 #include "state_tracker/st_gl_api.h" /* for st_gl_api_create */
 #include "state_tracker/drm_driver.h"
 
 #include "util/u_debug.h"
 #include "util/u_format_s3tc.h"
 
 #define MSAA_VISUAL_MAX_SAMPLES 32
 
 #undef false
 
 const __DRIconfigOptionsExtension gallium_config_options = {
    .base = { __DRI_CONFIG_OPTIONS, 1 },
    .xml =
 
    DRI_CONF_BEGIN
+      DRI_CONF_SECTION_PERFORMANCE
+         DRI_CONF_MESA_GLTHREAD("false")
+      DRI_CONF_SECTION_END
+
       DRI_CONF_SECTION_QUALITY
          DRI_CONF_FORCE_S3TC_ENABLE("false")
          DRI_CONF_PP_CELSHADE(0)
          DRI_CONF_PP_NORED(0)
          DRI_CONF_PP_NOGREEN(0)
          DRI_CONF_PP_NOBLUE(0)
          DRI_CONF_PP_JIMENEZMLAA(0, 0, 32)
          DRI_CONF_PP_JIMENEZMLAA_COLOR(0, 0, 32)
       DRI_CONF_SECTION_END
 
@@ -425,28 +430,44 @@ static void
 dri_postprocessing_init(struct dri_screen *screen)
 {
    unsigned i;
 
    for (i = 0; i < PP_FILTERS; i++) {
       screen->pp_enabled[i] = driQueryOptioni(&screen->optionCache,
                                               pp_filters[i].name);
    }
 }
 
+static void
+dri_set_background_context(struct st_context_iface *st)
+{
+   struct dri_context *ctx = (struct dri_context *)st->st_manager_private;
+   const __DRIbackgroundCallableExtension *backgroundCallable =
+      ctx->sPriv->dri2.backgroundCallable;
+
+   /* Note: Mesa will only call this function if GL multithreading is enabled
+    * We only do that if the loader exposed the __DRI_BACKGROUND_CALLABLE
+    * extension. So we know that backgroundCallable is not NULL.
+    */
+   assert(backgroundCallable);
+   backgroundCallable->setBackgroundContext(ctx->cPriv->loaderPrivate);
+}
+
 const __DRIconfig **
 dri_init_screen_helper(struct dri_screen *screen,
                        struct pipe_screen *pscreen,
                        const char* driver_name)
 {
    screen->base.screen = pscreen;
    screen->base.get_egl_image = dri_get_egl_image;
    screen->base.get_param = dri_get_param;
+   screen->base.set_background_context = dri_set_background_context;
 
    screen->st_api = st_gl_api_create();
    if (!screen->st_api)
       return NULL;
 
    if(pscreen->get_param(pscreen, PIPE_CAP_NPOT_TEXTURES))
       screen->target = PIPE_TEXTURE_2D;
    else
       screen->target = PIPE_TEXTURE_RECT;
 
diff --git a/src/mesa/drivers/dri/common/xmlpool/t_options.h b/src/mesa/drivers/dri/common/xmlpool/t_options.h
index f200093..c7c658d 100644
--- a/src/mesa/drivers/dri/common/xmlpool/t_options.h
+++ b/src/mesa/drivers/dri/common/xmlpool/t_options.h
@@ -306,20 +306,24 @@ DRI_CONF_OPT_END
 #define DRI_CONF_TEXTURE_HEAPS_GART 2
 #define DRI_CONF_TEXTURE_HEAPS(def) \
 DRI_CONF_OPT_BEGIN_V(texture_heaps,enum,def,"0:2") \
 	DRI_CONF_DESC_BEGIN(en,gettext("Used types of texture memory")) \
 		DRI_CONF_ENUM(0,gettext("All available memory")) \
 		DRI_CONF_ENUM(1,gettext("Only card memory (if available)")) \
 		DRI_CONF_ENUM(2,gettext("Only GART (AGP/PCIE) memory (if available)")) \
 	DRI_CONF_DESC_END \
 DRI_CONF_OPT_END
 
+#define DRI_CONF_MESA_GLTHREAD(def) \
+DRI_CONF_OPT_BEGIN_B(mesa_glthread, def) \
+        DRI_CONF_DESC(en,gettext("Enable offloading GL driver work to a separate thread")) \
+DRI_CONF_OPT_END
 
 
 /**
  * \brief Software-fallback options.  To allow using features (like
  * GL_ARB_vertex_program) on GPUs that don't otherwise support the feature.
  */
 #define DRI_CONF_SECTION_SOFTWARE \
 DRI_CONF_SECTION_BEGIN \
         DRI_CONF_DESC(en,gettext("Features that are not hardware-accelerated"))
 
diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c
index 5855258..411f546 100644
--- a/src/mesa/state_tracker/st_context.c
+++ b/src/mesa/state_tracker/st_context.c
@@ -22,20 +22,21 @@
  * 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.
  * 
  **************************************************************************/
 
 #include "main/imports.h"
 #include "main/accum.h"
 #include "main/api_exec.h"
 #include "main/context.h"
+#include "main/glthread.h"
 #include "main/samplerobj.h"
 #include "main/shaderobj.h"
 #include "main/version.h"
 #include "main/vtxfmt.h"
 #include "main/hash.h"
 #include "program/prog_cache.h"
 #include "vbo/vbo.h"
 #include "glapi/glapi.h"
 #include "st_context.h"
 #include "st_debug.h"
@@ -605,20 +606,31 @@ void st_destroy_context( struct st_context *st )
    free(ctx);
 }
 
 static void
 st_emit_string_marker(struct gl_context *ctx, const GLchar *string, GLsizei len)
 {
    struct st_context *st = ctx->st;
    st->pipe->emit_string_marker(st->pipe, string, len);
 }
 
+static void
+st_set_background_context(struct gl_context *ctx)
+{
+   struct st_context *st = ctx->st;
+   struct st_manager *smapi =
+      (struct st_manager*)st->iface.st_context_private;
+
+   assert(smapi->set_background_context);
+   smapi->set_background_context(&st->iface);
+}
+
 void st_init_driver_functions(struct pipe_screen *screen,
                               struct dd_function_table *functions)
 {
    _mesa_init_shader_object_functions(functions);
    _mesa_init_sampler_object_functions(functions);
 
    st_init_blit_functions(functions);
    st_init_bufferobject_functions(screen, functions);
    st_init_clear_functions(functions);
    st_init_bitmap_functions(functions);
@@ -649,11 +661,12 @@ void st_init_driver_functions(struct pipe_screen *screen,
    st_init_syncobj_functions(functions);
 
    st_init_vdpau_functions(functions);
 
    if (screen->get_param(screen, PIPE_CAP_STRING_MARKER))
       functions->EmitStringMarker = st_emit_string_marker;
 
    functions->Enable = st_Enable;
    functions->UpdateState = st_invalidate_state;
    functions->QueryMemoryInfo = st_query_memory_info;
+   functions->SetBackgroundContext = st_set_background_context;
 }
diff --git a/src/mesa/state_tracker/st_manager.c b/src/mesa/state_tracker/st_manager.c
index e663b01..dad408a 100644
--- a/src/mesa/state_tracker/st_manager.c
+++ b/src/mesa/state_tracker/st_manager.c
@@ -22,20 +22,21 @@
  * DEALINGS IN THE SOFTWARE.
  *
  * Authors:
  *    Chia-I Wu <olv at lunarg.com>
  */
 
 #include "main/mtypes.h"
 #include "main/extensions.h"
 #include "main/context.h"
 #include "main/debug_output.h"
+#include "main/glthread.h"
 #include "main/texobj.h"
 #include "main/teximage.h"
 #include "main/texstate.h"
 #include "main/errors.h"
 #include "main/framebuffer.h"
 #include "main/fbobject.h"
 #include "main/renderbuffer.h"
 #include "main/version.h"
 #include "st_texture.h"
 
@@ -622,20 +623,36 @@ st_context_share(struct st_context_iface *stctxi,
    return _mesa_share_state(st->ctx, src->ctx);
 }
 
 static void
 st_context_destroy(struct st_context_iface *stctxi)
 {
    struct st_context *st = (struct st_context *) stctxi;
    st_destroy_context(st);
 }
 
+static void
+st_start_thread(struct st_context_iface *stctxi)
+{
+   struct st_context *st = (struct st_context *) stctxi;
+
+   _mesa_glthread_init(st->ctx);
+}
+
+static void
+st_thread_finish(struct st_context_iface *stctxi)
+{
+   struct st_context *st = (struct st_context *) stctxi;
+
+   _mesa_glthread_finish(st->ctx);
+}
+
 static struct st_context_iface *
 st_api_create_context(struct st_api *stapi, struct st_manager *smapi,
                       const struct st_context_attribs *attribs,
                       enum st_context_error *error,
                       struct st_context_iface *shared_stctxi)
 {
    struct st_context *shared_ctx = (struct st_context *) shared_stctxi;
    struct st_context *st;
    struct pipe_context *pipe;
    struct gl_config mode;
@@ -716,20 +733,22 @@ st_api_create_context(struct st_api *stapi, struct st_manager *smapi,
    }
 
    st->invalidate_on_gl_viewport =
       smapi->get_param(smapi, ST_MANAGER_BROKEN_INVALIDATE);
 
    st->iface.destroy = st_context_destroy;
    st->iface.flush = st_context_flush;
    st->iface.teximage = st_context_teximage;
    st->iface.copy = st_context_copy;
    st->iface.share = st_context_share;
+   st->iface.start_thread = st_start_thread;
+   st->iface.thread_finish = st_thread_finish;
    st->iface.st_context_private = (void *) smapi;
    st->iface.cso_context = st->cso_context;
    st->iface.pipe = st->pipe;
 
    *error = ST_CONTEXT_SUCCESS;
    return &st->iface;
 }
 
 static struct st_context_iface *
 st_api_get_current(struct st_api *stapi)
-- 
2.9.3



More information about the mesa-dev mailing list