[Mesa-dev] [PATCH 1/2] llvmpipe: Use two LLVMContexts per OpenGL context instead of a global one.

Mathias.Froehlich at gmx.net Mathias.Froehlich at gmx.net
Sun Aug 31 01:06:23 PDT 2014


From: Mathias Fröhlich <Mathias.Froehlich at gmx.net>

This is one step to make llvmpipe thread safe as mandated by the OpenGL
standard. Using the global LLVMContext is obviously a problem for
that kind of use pattern. The patch introduces two LLVMContext
instances that are private to an OpenGL context and used for all
compiles. One is put into struct draw_llvm and the other
one into struct llvmpipe_context.

Signed-off-by: Mathias Froehlich <Mathias.Froehlich at web.de>
---
 src/gallium/auxiliary/draw/draw_llvm.c        | 15 ++++++++++++--
 src/gallium/auxiliary/draw/draw_llvm.h        |  2 ++
 src/gallium/auxiliary/gallivm/lp_bld_init.c   | 28 +++++++--------------------
 src/gallium/auxiliary/gallivm/lp_bld_init.h   |  2 +-
 src/gallium/drivers/llvmpipe/lp_context.c     |  7 +++++++
 src/gallium/drivers/llvmpipe/lp_context.h     |  3 +++
 src/gallium/drivers/llvmpipe/lp_state_fs.c    |  2 +-
 src/gallium/drivers/llvmpipe/lp_state_setup.c |  2 +-
 src/gallium/drivers/llvmpipe/lp_test_arit.c   |  2 +-
 src/gallium/drivers/llvmpipe/lp_test_blend.c  |  2 +-
 src/gallium/drivers/llvmpipe/lp_test_conv.c   |  2 +-
 src/gallium/drivers/llvmpipe/lp_test_format.c |  2 +-
 src/gallium/drivers/llvmpipe/lp_test_printf.c |  2 +-
 13 files changed, 40 insertions(+), 31 deletions(-)

diff --git a/src/gallium/auxiliary/draw/draw_llvm.c b/src/gallium/auxiliary/draw/draw_llvm.c
index e8e837a..ae14fed 100644
--- a/src/gallium/auxiliary/draw/draw_llvm.c
+++ b/src/gallium/auxiliary/draw/draw_llvm.c
@@ -492,6 +492,10 @@ draw_llvm_create(struct draw_context *draw)
 
    llvm->draw = draw;
 
+   llvm->context = LLVMContextCreate();
+   if (!llvm->context)
+      goto fail;
+
    llvm->nr_variants = 0;
    make_empty_list(&llvm->vs_variants_list);
 
@@ -499,6 +503,10 @@ draw_llvm_create(struct draw_context *draw)
    make_empty_list(&llvm->gs_variants_list);
 
    return llvm;
+
+fail:
+   draw_llvm_destroy(llvm);
+   return NULL;
 }
 
 
@@ -508,6 +516,9 @@ draw_llvm_create(struct draw_context *draw)
 void
 draw_llvm_destroy(struct draw_llvm *llvm)
 {
+   LLVMContextDispose(llvm->context);
+   llvm->context = NULL;
+
    /* XXX free other draw_llvm data? */
    FREE(llvm);
 }
@@ -539,7 +550,7 @@ draw_llvm_create_variant(struct draw_llvm *llvm,
    util_snprintf(module_name, sizeof(module_name), "draw_llvm_vs_variant%u",
                  variant->shader->variants_cached);
 
-   variant->gallivm = gallivm_create(module_name);
+   variant->gallivm = gallivm_create(module_name, llvm->context);
 
    create_jit_types(variant);
 
@@ -2194,7 +2205,7 @@ draw_gs_llvm_create_variant(struct draw_llvm *llvm,
    util_snprintf(module_name, sizeof(module_name), "draw_llvm_gs_variant%u",
                  variant->shader->variants_cached);
 
-   variant->gallivm = gallivm_create(module_name);
+   variant->gallivm = gallivm_create(module_name, llvm->context);
 
    create_gs_jit_types(variant);
 
diff --git a/src/gallium/auxiliary/draw/draw_llvm.h b/src/gallium/auxiliary/draw/draw_llvm.h
index ed97cf7..a4bd1ed 100644
--- a/src/gallium/auxiliary/draw/draw_llvm.h
+++ b/src/gallium/auxiliary/draw/draw_llvm.h
@@ -461,6 +461,8 @@ struct llvm_geometry_shader {
 struct draw_llvm {
    struct draw_context *draw;
 
+   LLVMContextRef context;
+
    struct draw_jit_context jit_context;
    struct draw_gs_jit_context gs_jit_context;
 
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_init.c b/src/gallium/auxiliary/gallivm/lp_bld_init.c
index 8b8686d..dfc28b4 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_init.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_init.c
@@ -69,17 +69,6 @@
 void LLVMLinkInMCJIT();
 #endif
 
-/*
- * LLVM has several global caches which pointing/derived from objects
- * owned by the context, so if we freeing contexts causes
- * memory leaks and false cache hits when these objects are destroyed.
- *
- * TODO: For thread safety on multi-threaded OpenGL we should use one LLVM
- * context per thread, and put them in a pool when threads are destroyed.
- */
-#define USE_GLOBAL_CONTEXT 1
-
-
 #ifdef DEBUG
 unsigned gallivm_debug = 0;
 
@@ -193,8 +182,7 @@ gallivm_free_ir(struct gallivm_state *gallivm)
    if (gallivm->builder)
       LLVMDisposeBuilder(gallivm->builder);
 
-   if (!USE_GLOBAL_CONTEXT && gallivm->context)
-      LLVMContextDispose(gallivm->context);
+   /* The LLVMContext should be owned by the parent of gallivm. */
 
    gallivm->engine = NULL;
    gallivm->target = NULL;
@@ -285,18 +273,16 @@ fail:
  * \return  TRUE for success, FALSE for failure
  */
 static boolean
-init_gallivm_state(struct gallivm_state *gallivm, const char *name)
+init_gallivm_state(struct gallivm_state *gallivm, const char *name,
+                   LLVMContextRef context)
 {
    assert(!gallivm->context);
    assert(!gallivm->module);
 
    lp_build_init();
 
-   if (USE_GLOBAL_CONTEXT) {
-      gallivm->context = LLVMGetGlobalContext();
-   } else {
-      gallivm->context = LLVMContextCreate();
-   }
+   gallivm->context = context;
+
    if (!gallivm->context)
       goto fail;
 
@@ -469,13 +455,13 @@ lp_build_init(void)
  * Create a new gallivm_state object.
  */
 struct gallivm_state *
-gallivm_create(const char *name)
+gallivm_create(const char *name, LLVMContextRef context)
 {
    struct gallivm_state *gallivm;
 
    gallivm = CALLOC_STRUCT(gallivm_state);
    if (gallivm) {
-      if (!init_gallivm_state(gallivm, name)) {
+      if (!init_gallivm_state(gallivm, name, context)) {
          FREE(gallivm);
          gallivm = NULL;
       }
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_init.h b/src/gallium/auxiliary/gallivm/lp_bld_init.h
index 2e32cf8..8f20158 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_init.h
+++ b/src/gallium/auxiliary/gallivm/lp_bld_init.h
@@ -54,7 +54,7 @@ lp_build_init(void);
 
 
 struct gallivm_state *
-gallivm_create(const char *name);
+gallivm_create(const char *name, LLVMContextRef context);
 
 void
 gallivm_destroy(struct gallivm_state *gallivm);
diff --git a/src/gallium/drivers/llvmpipe/lp_context.c b/src/gallium/drivers/llvmpipe/lp_context.c
index d9696c2..3a9b4c2 100644
--- a/src/gallium/drivers/llvmpipe/lp_context.c
+++ b/src/gallium/drivers/llvmpipe/lp_context.c
@@ -93,6 +93,9 @@ static void llvmpipe_destroy( struct pipe_context *pipe )
 
    lp_delete_setup_variants(llvmpipe);
 
+   LLVMContextDispose(llvmpipe->context);
+   llvmpipe->context = NULL;
+
    align_free( llvmpipe );
 }
 
@@ -161,6 +164,10 @@ llvmpipe_create_context( struct pipe_screen *screen, void *priv )
    llvmpipe_init_context_resource_funcs( &llvmpipe->pipe );
    llvmpipe_init_surface_functions(llvmpipe);
 
+   llvmpipe->context = LLVMContextCreate();
+   if (!llvmpipe->context)
+      goto fail;
+
    /*
     * Create drawing context and plug our rendering stage into it.
     */
diff --git a/src/gallium/drivers/llvmpipe/lp_context.h b/src/gallium/drivers/llvmpipe/lp_context.h
index ee0831f..0d47c0d 100644
--- a/src/gallium/drivers/llvmpipe/lp_context.h
+++ b/src/gallium/drivers/llvmpipe/lp_context.h
@@ -153,6 +153,9 @@ struct llvmpipe_context {
    struct pipe_query *render_cond_query;
    uint render_cond_mode;
    boolean render_cond_cond;
+
+   /** The LLVMContext to use for LLVM related work */
+   LLVMContextRef context;
 };
 
 
diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs.c b/src/gallium/drivers/llvmpipe/lp_state_fs.c
index 0b74d15..ff2939d 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_fs.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_fs.c
@@ -2565,7 +2565,7 @@ generate_variant(struct llvmpipe_context *lp,
    util_snprintf(module_name, sizeof(module_name), "fs%u_variant%u",
                  shader->no, shader->variants_created);
 
-   variant->gallivm = gallivm_create(module_name);
+   variant->gallivm = gallivm_create(module_name, lp->context);
    if (!variant->gallivm) {
       FREE(variant);
       return NULL;
diff --git a/src/gallium/drivers/llvmpipe/lp_state_setup.c b/src/gallium/drivers/llvmpipe/lp_state_setup.c
index 63c92d5..49741db 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_setup.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_setup.c
@@ -731,7 +731,7 @@ generate_setup_variant(struct lp_setup_variant_key *key,
    util_snprintf(func_name, sizeof(func_name), "setup_variant_%u",
                  variant->no);
 
-   variant->gallivm = gallivm = gallivm_create(func_name);
+   variant->gallivm = gallivm = gallivm_create(func_name, lp->context);
    if (!variant->gallivm) {
       goto fail;
    }
diff --git a/src/gallium/drivers/llvmpipe/lp_test_arit.c b/src/gallium/drivers/llvmpipe/lp_test_arit.c
index bf405a5..660ad4d 100644
--- a/src/gallium/drivers/llvmpipe/lp_test_arit.c
+++ b/src/gallium/drivers/llvmpipe/lp_test_arit.c
@@ -354,7 +354,7 @@ test_unary(unsigned verbose, FILE *fp, const struct unary_test_t *test)
       in[i] = 1.0;
    }
 
-   gallivm = gallivm_create("test_module");
+   gallivm = gallivm_create("test_module", LLVMGetGlobalContext());
 
    test_func = build_unary_test_func(gallivm, test);
 
diff --git a/src/gallium/drivers/llvmpipe/lp_test_blend.c b/src/gallium/drivers/llvmpipe/lp_test_blend.c
index 4775aff..37420b0 100644
--- a/src/gallium/drivers/llvmpipe/lp_test_blend.c
+++ b/src/gallium/drivers/llvmpipe/lp_test_blend.c
@@ -450,7 +450,7 @@ test_one(unsigned verbose,
    if(verbose >= 1)
       dump_blend_type(stdout, blend, type);
 
-   gallivm = gallivm_create("test_module");
+   gallivm = gallivm_create("test_module", LLVMGetGlobalContext());
 
    func = add_blend_test(gallivm, blend, type);
 
diff --git a/src/gallium/drivers/llvmpipe/lp_test_conv.c b/src/gallium/drivers/llvmpipe/lp_test_conv.c
index 948a218..8290da4 100644
--- a/src/gallium/drivers/llvmpipe/lp_test_conv.c
+++ b/src/gallium/drivers/llvmpipe/lp_test_conv.c
@@ -211,7 +211,7 @@ test_one(unsigned verbose,
 
    eps = MAX2(lp_const_eps(src_type), lp_const_eps(dst_type));
 
-   gallivm = gallivm_create("test_module");
+   gallivm = gallivm_create("test_module", LLVMGetGlobalContext());
 
    func = add_conv_test(gallivm, src_type, num_srcs, dst_type, num_dsts);
 
diff --git a/src/gallium/drivers/llvmpipe/lp_test_format.c b/src/gallium/drivers/llvmpipe/lp_test_format.c
index 2c83219..8a81151 100644
--- a/src/gallium/drivers/llvmpipe/lp_test_format.c
+++ b/src/gallium/drivers/llvmpipe/lp_test_format.c
@@ -138,7 +138,7 @@ test_format_float(unsigned verbose, FILE *fp,
    boolean success = TRUE;
    unsigned i, j, k, l;
 
-   gallivm = gallivm_create("test_module_float");
+   gallivm = gallivm_create("test_module_float", LLVMGetGlobalContext());
 
    fetch = add_fetch_rgba_test(gallivm, verbose, desc, lp_float32_vec4_type());
 
diff --git a/src/gallium/drivers/llvmpipe/lp_test_printf.c b/src/gallium/drivers/llvmpipe/lp_test_printf.c
index 4b74ae9..fe4ce0f 100644
--- a/src/gallium/drivers/llvmpipe/lp_test_printf.c
+++ b/src/gallium/drivers/llvmpipe/lp_test_printf.c
@@ -94,7 +94,7 @@ test_printf(unsigned verbose, FILE *fp,
    test_printf_t test_printf_func;
    boolean success = TRUE;
 
-   gallivm = gallivm_create("test_module");
+   gallivm = gallivm_create("test_module", LLVMGetGlobalContext());
 
    test = add_printf_test(gallivm);
 
-- 
1.9.3



More information about the mesa-dev mailing list