llvmpipe: Use a second LLVMContext for compiling sample functions

LLVMContextr is not thread safe. There are many code paths that use
llvmpipe_context::context and adding locking to all of them is
difficult and adds unnecessary overhead. This approach restricts locking
to lp_sampler_matrix, which makes covering all uses of the LLVMContext
easy and only adds overhead when running lavapipe.

Fixes: 7ebf7f4 ("llvmpipe: Compile sample functioins on demand")
Reviewed-by: Roland Scheidegger <roland.scheidegger@broadcom.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/29397>
This commit is contained in:
Konstantin Seurer
2024-05-25 12:00:59 +02:00
committed by Marge Bot
parent a93b1960af
commit c31038ef98
2 changed files with 37 additions and 4 deletions

View File

@@ -200,6 +200,20 @@ llvmpipe_sampler_matrix_destroy(struct llvmpipe_context *ctx)
gallivm_destroy(*gallivm);
util_dynarray_fini(&ctx->sampler_matrix.gallivms);
if (ctx->sampler_matrix.context)
LLVMContextDispose(ctx->sampler_matrix.context);
}
static LLVMContextRef
get_llvm_context(struct llvmpipe_context *ctx)
{
struct lp_sampler_matrix *matrix = &ctx->sampler_matrix;
if (!matrix->context)
matrix->context = LLVMContextCreate();
return matrix->context;
}
static void *
@@ -261,7 +275,7 @@ compile_image_function(struct llvmpipe_context *ctx, struct lp_static_texture_st
lp_disk_cache_find_shader(llvmpipe_screen(ctx->pipe.screen), &cached, cache_key);
bool needs_caching = !cached.data_size;
struct gallivm_state *gallivm = gallivm_create("sample_function", ctx->context, &cached);
struct gallivm_state *gallivm = gallivm_create("sample_function", get_llvm_context(ctx), &cached);
struct lp_image_static_state state = {
.image_state = *texture,
@@ -414,7 +428,7 @@ compile_sample_function(struct llvmpipe_context *ctx, struct lp_static_texture_s
lp_disk_cache_find_shader(llvmpipe_screen(ctx->pipe.screen), &cached, cache_key);
bool needs_caching = !cached.data_size;
struct gallivm_state *gallivm = gallivm_create("sample_function", ctx->context, &cached);
struct gallivm_state *gallivm = gallivm_create("sample_function", get_llvm_context(ctx), &cached);
struct lp_sampler_static_state state = {
.texture_state = *texture,
@@ -543,7 +557,7 @@ compile_jit_sample_function(struct llvmpipe_context *ctx, uint32_t sample_key)
lp_disk_cache_find_shader(llvmpipe_screen(ctx->pipe.screen), &cached, cache_key);
bool needs_caching = !cached.data_size;
struct gallivm_state *gallivm = gallivm_create("jit_sample_function", ctx->context, &cached);
struct gallivm_state *gallivm = gallivm_create("jit_sample_function", get_llvm_context(ctx), &cached);
struct lp_type type;
memset(&type, 0, sizeof type);
@@ -650,7 +664,7 @@ compile_size_function(struct llvmpipe_context *ctx, struct lp_static_texture_sta
lp_disk_cache_find_shader(llvmpipe_screen(ctx->pipe.screen), &cached, cache_key);
bool needs_caching = !cached.data_size;
struct gallivm_state *gallivm = gallivm_create("sample_function", ctx->context, &cached);
struct gallivm_state *gallivm = gallivm_create("sample_function", get_llvm_context(ctx), &cached);
struct lp_sampler_static_state state = {
.texture_state = *texture,
@@ -793,6 +807,8 @@ llvmpipe_register_texture(struct llvmpipe_context *ctx, struct lp_static_texture
else
entry->storage = true;
simple_mtx_lock(&matrix->lock);
if (entry->sampled) {
if (entry->sample_functions) {
entry->sample_functions = realloc(entry->sample_functions, matrix->sampler_count * sizeof(void **));
@@ -827,6 +843,8 @@ llvmpipe_register_texture(struct llvmpipe_context *ctx, struct lp_static_texture
if (!entry->image_functions[image_op])
entry->image_functions[image_op] = compile_image_function(ctx, state, image_op);
}
simple_mtx_unlock(&matrix->lock);
}
static void
@@ -842,6 +860,8 @@ llvmpipe_register_sampler(struct llvmpipe_context *ctx, struct lp_static_sampler
matrix->samplers[matrix->sampler_count - 1] = *state;
simple_mtx_lock(&matrix->lock);
for (uint32_t i = 0; i < matrix->texture_count; i++) {
struct lp_texture_functions *texture = matrix->textures[i];
if (!texture->sampled)
@@ -866,6 +886,8 @@ llvmpipe_register_sampler(struct llvmpipe_context *ctx, struct lp_static_sampler
*dst = NULL;
compile_sample_functions(ctx, &texture->state, state, dst);
}
simple_mtx_unlock(&matrix->lock);
}
static void
@@ -877,6 +899,8 @@ register_sample_key(struct llvmpipe_context *ctx, uint32_t sample_key)
BITSET_SET(matrix->sample_keys, sample_key);
simple_mtx_lock(&matrix->lock);
matrix->jit_sample_functions[sample_key] = compile_jit_sample_function(ctx, sample_key);
for (uint32_t texture_index = 0; texture_index < matrix->texture_count; texture_index++) {
@@ -902,6 +926,8 @@ register_sample_key(struct llvmpipe_context *ctx, uint32_t sample_key)
for (uint32_t sampler_index = 0; sampler_index < matrix->sampler_count; sampler_index++)
texture->sample_functions[sampler_index][sample_key] = matrix->jit_sample_functions[sample_key];
}
simple_mtx_unlock(&matrix->lock);
}
static void
@@ -913,11 +939,15 @@ register_image_op(struct llvmpipe_context *ctx, uint32_t op)
BITSET_SET(matrix->image_ops, op);
simple_mtx_lock(&matrix->lock);
for (uint32_t texture_index = 0; texture_index < matrix->texture_count; texture_index++) {
struct lp_texture_functions *texture = matrix->textures[texture_index];
if (texture->storage)
texture->image_functions[op] = compile_image_function(ctx, &texture->state, op);
}
simple_mtx_unlock(&matrix->lock);
}
static bool

View File

@@ -51,6 +51,9 @@ struct lp_sampler_matrix {
struct llvmpipe_context *ctx;
/* Use a separate LLVMContext since it is not thread safe but can be accessed by shaders. */
LLVMContextRef context;
struct util_dynarray gallivms;
};