llvmpipe: Use two LLVMContexts per OpenGL context instead of a global one.
authorMathias Fröhlich <Mathias.Froehlich@gmx.net>
Thu, 28 Aug 2014 17:49:35 +0000 (19:49 +0200)
committerMathias Fröhlich <Mathias.Froehlich@gmx.net>
Tue, 30 Sep 2014 18:45:19 +0000 (20:45 +0200)
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.

Reviewed-by: Jose Fonseca <jfonseca@vmware.com>
Signed-off-by: Mathias Froehlich <Mathias.Froehlich@web.de>
13 files changed:
src/gallium/auxiliary/draw/draw_llvm.c
src/gallium/auxiliary/draw/draw_llvm.h
src/gallium/auxiliary/gallivm/lp_bld_init.c
src/gallium/auxiliary/gallivm/lp_bld_init.h
src/gallium/drivers/llvmpipe/lp_context.c
src/gallium/drivers/llvmpipe/lp_context.h
src/gallium/drivers/llvmpipe/lp_state_fs.c
src/gallium/drivers/llvmpipe/lp_state_setup.c
src/gallium/drivers/llvmpipe/lp_test_arit.c
src/gallium/drivers/llvmpipe/lp_test_blend.c
src/gallium/drivers/llvmpipe/lp_test_conv.c
src/gallium/drivers/llvmpipe/lp_test_format.c
src/gallium/drivers/llvmpipe/lp_test_printf.c

index 504f3efab2eb76c8d11be381863f6ab1c031493b..8469d6999b1063e55d14edfef1b4af529ad319f2 100644 (file)
@@ -493,6 +493,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);
 
@@ -500,6 +504,10 @@ draw_llvm_create(struct draw_context *draw)
    make_empty_list(&llvm->gs_variants_list);
 
    return llvm;
+
+fail:
+   draw_llvm_destroy(llvm);
+   return NULL;
 }
 
 
@@ -509,6 +517,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);
 }
@@ -540,7 +551,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);
 
@@ -2195,7 +2206,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);
 
index ed97cf7211545193b666e289885ea2d5b38cb0d6..a4bd1edcf0d38caa43f6ad8e429edca8c83d95d7 100644 (file)
@@ -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;
 
index 75ef935eb22969fcbc9bea5f548bc14be75c09f0..8a484978f1e1be6b932c19641c9bc0a576872938 100644 (file)
 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;
 
@@ -209,8 +198,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;
@@ -301,7 +289,8 @@ 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);
@@ -309,11 +298,8 @@ init_gallivm_state(struct gallivm_state *gallivm, const char *name)
    if (!lp_build_init())
       return FALSE;
 
-   if (USE_GLOBAL_CONTEXT) {
-      gallivm->context = LLVMGetGlobalContext();
-   } else {
-      gallivm->context = LLVMContextCreate();
-   }
+   gallivm->context = context;
+
    if (!gallivm->context)
       goto fail;
 
@@ -495,13 +481,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;
       }
index 64c5278c24e14ecd1fcb8b631c8830044e051709..6e9f52554a3d0e989ba3a4f4b163e44b569acb23 100644 (file)
@@ -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);
index d9696c2067d70be8a882de21e141530243b85f04..3a9b4c22a9b44ab10a36e603ec0756672b27ba64 100644 (file)
@@ -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.
     */
index ee0831fbb6d438ec2247d0d0e2d8a10158c9513f..0d47c0d517cede0a12bb80966f849da6f64ac0aa 100644 (file)
@@ -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;
 };
 
 
index 0b74d15cc6428fec34b33647659477eefd256136..ff2939d4db4036a27a09100b77ec02727c520fdd 100644 (file)
@@ -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;
index 63c92d588c96db742dfda97a7a11bec283a98f72..49741db66f03993340c2382bba714a3a851dfce5 100644 (file)
@@ -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;
    }
index bf405a54ae10b6eac9577543b6cd7a1f9124c830..660ad4db02e7dda1714c8f7e523c716689bdee4c 100644 (file)
@@ -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);
 
index 4775aff877bdcd859229c1606063515a66af6248..37420b024424082de43c3681364678c75e49d381 100644 (file)
@@ -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);
 
index 948a218d7f73f1eb4e88277046aa3c710d0dd784..8290da4004bf40ebd4d55d3ca4b6f24f3332d67e 100644 (file)
@@ -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);
 
index 2c8321939ae174c6fd03cb3700bbb0ac78670cff..8a81151f5972bba8b64cecfec1ac7b98e2cfb92d 100644 (file)
@@ -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());
 
index 4b74ae96a7a87d257e9e7b25b247503e1502a637..fe4ce0fc5d7c74ecbd6d584c1bccad4250c56a80 100644 (file)
@@ -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);