summaryrefslogtreecommitdiff
path: root/src/mesa
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa')
-rw-r--r--src/mesa/pipe/draw/draw_private.h8
-rw-r--r--src/mesa/pipe/draw/draw_vertex_shader.c10
-rw-r--r--src/mesa/pipe/draw/draw_vertex_shader_llvm.c2
-rw-r--r--src/mesa/pipe/llvm/llvmtgsi.cpp86
-rw-r--r--src/mesa/pipe/llvm/llvmtgsi.h13
-rw-r--r--src/mesa/state_tracker/st_program.c4
6 files changed, 97 insertions, 26 deletions
diff --git a/src/mesa/pipe/draw/draw_private.h b/src/mesa/pipe/draw/draw_private.h
index ac47d2a76f..f52ff0bd44 100644
--- a/src/mesa/pipe/draw/draw_private.h
+++ b/src/mesa/pipe/draw/draw_private.h
@@ -50,6 +50,8 @@
#include "pipe/tgsi/exec/tgsi_core.h"
+struct gallivm_prog;
+struct gallivm_cpu_engine;
/**
* Basic vertex info.
* Carry some useful information around with the vertices in the prim pipe.
@@ -127,6 +129,9 @@ struct draw_vertex_shader {
#if defined(__i386__) || defined(__386__)
struct x86_function sse2_program;
#endif
+#ifdef MESA_LLVM
+ struct gallivm_prog *llvm_prog;
+#endif
};
/**
@@ -226,6 +231,9 @@ struct draw_context
} pq;
int use_sse : 1;
+#ifdef MESA_LLVM
+ struct gallivm_cpu_engine *engine;
+#endif
};
diff --git a/src/mesa/pipe/draw/draw_vertex_shader.c b/src/mesa/pipe/draw/draw_vertex_shader.c
index 9dbb317f2a..7fd17292b8 100644
--- a/src/mesa/pipe/draw/draw_vertex_shader.c
+++ b/src/mesa/pipe/draw/draw_vertex_shader.c
@@ -39,6 +39,7 @@
#include "x86/rtasm/x86sse.h"
#include "pipe/tgsi/exec/tgsi_core.h"
+#include "pipe/llvm/llvmtgsi.h"
#define DBG 0
@@ -187,7 +188,7 @@ void draw_vertex_shader_queue_flush( struct draw_context *draw )
// fprintf(stderr, " q(%d) ", draw->vs.queue_nr );
#ifdef MESA_LLVM
- if (draw->vertex_shader->state->llvm_prog) {
+ if (draw->vertex_shader->llvm_prog) {
draw_vertex_shader_queue_flush_llvm(draw);
return;
}
@@ -233,6 +234,13 @@ draw_create_vertex_shader(struct draw_context *draw,
tgsi_emit_sse2( sh->tokens, &vs->sse2_program );
}
#endif
+#ifdef MESA_LLVM
+ vs->llvm_prog = gallivm_from_tgsi(shader->tokens);
+ if (!draw->engine)
+ draw->engine = gallivm_cpu_engine_create(vs->llvm_prog);
+ else
+ gallivm_cpu_jit_compile(draw->engine, vs->llvm_prog);
+#endif
return vs;
}
diff --git a/src/mesa/pipe/draw/draw_vertex_shader_llvm.c b/src/mesa/pipe/draw/draw_vertex_shader_llvm.c
index c0720d2872..b340ab38fd 100644
--- a/src/mesa/pipe/draw/draw_vertex_shader_llvm.c
+++ b/src/mesa/pipe/draw/draw_vertex_shader_llvm.c
@@ -125,7 +125,7 @@ void draw_vertex_shader_queue_flush_llvm(struct draw_context *draw)
float inputs[VS_QUEUE_LENGTH][PIPE_MAX_SHADER_INPUTS][4];
float outputs[VS_QUEUE_LENGTH][PIPE_MAX_SHADER_INPUTS][4];
float (*consts)[4] = (float (*)[4]) draw->mapped_constants;
- struct gallivm_prog *prog = (struct gallivm_prog *)draw->vertex_shader->state->llvm_prog;
+ struct gallivm_prog *prog = draw->vertex_shader->llvm_prog;
const float *scale = draw->viewport.scale;
const float *trans = draw->viewport.translate;
diff --git a/src/mesa/pipe/llvm/llvmtgsi.cpp b/src/mesa/pipe/llvm/llvmtgsi.cpp
index af602326ae..b57a0f8366 100644
--- a/src/mesa/pipe/llvm/llvmtgsi.cpp
+++ b/src/mesa/pipe/llvm/llvmtgsi.cpp
@@ -70,12 +70,16 @@
#ifdef MESA_LLVM
struct gallivm_prog {
- void *module;
+ llvm::Module *module;
void *function;
int num_consts;
int id;
};
+struct gallivm_cpu_engine {
+ llvm::ExecutionEngine *engine;
+};
+
using namespace llvm;
#include "llvm_base_shader.cpp"
@@ -698,13 +702,21 @@ tgsi_to_llvm(struct gallivm_prog *prog, const struct tgsi_token *tokens)
return mod;
}
+/*!
+ Translates the TGSI tokens into LLVM format. Translated representation
+ is stored in the gallivm_prog and returned.
+ After calling this function the gallivm_prog can either be used with a custom
+ code generator to generate machine code for the GPU which the code generator
+ addresses or it can be jit compiled with gallivm_cpu_jit_compile and executed
+ with gallivm_prog_exec to run the module on the CPU.
+ */
struct gallivm_prog *
-gallivm_from_tgsi(struct pipe_context *pipe, const struct tgsi_token *tokens)
+gallivm_from_tgsi(const struct tgsi_token *tokens)
{
std::cout << "Creating llvm from: " <<std::endl;
++GLOBAL_ID;
struct gallivm_prog *gallivm =
- (struct gallivm_prog *)malloc(sizeof(struct gallivm_prog));
+ (struct gallivm_prog *)calloc(1, sizeof(struct gallivm_prog));
gallivm->id = GLOBAL_ID;
tgsi_dump(tokens, 0);
@@ -718,20 +730,8 @@ gallivm_from_tgsi(struct pipe_context *pipe, const struct tgsi_token *tokens)
AddStandardCompilePasses(passes);
passes.run(*mod);
- llvm::ExistingModuleProvider *mp = new llvm::ExistingModuleProvider(mod);
- llvm::ExecutionEngine *ee = 0;
- if (!pipe->llvm_execution_engine) {
- ee = llvm::ExecutionEngine::create(mp, false);
- pipe->llvm_execution_engine = ee;
- } else {
- ee = (llvm::ExecutionEngine*)pipe->llvm_execution_engine;
- ee->addModuleProvider(mp);
- }
gallivm->module = mod;
- Function *func = mod->getFunction("run_vertex_shader");
- gallivm->function = ee->getPointerToFunctionOrStub(func);
-
gallivm_prog_dump(gallivm, 0);
return gallivm;
@@ -754,6 +754,12 @@ typedef void (*vertex_shader_runner)(float (*ainputs)[PIPE_MAX_SHADER_INPUTS][4]
int num_attribs,
int num_consts);
+
+/*!
+ This function is used to execute the gallivm_prog in software. Before calling
+ this function the gallivm_prog has to be JIT compiled with the gallivm_cpu_jit_compile
+ function.
+ */
int gallivm_prog_exec(struct gallivm_prog *prog,
float (*inputs)[PIPE_MAX_SHADER_INPUTS][4],
float (*dests)[PIPE_MAX_SHADER_INPUTS][4],
@@ -763,6 +769,7 @@ int gallivm_prog_exec(struct gallivm_prog *prog,
int num_attribs)
{
vertex_shader_runner runner = reinterpret_cast<vertex_shader_runner>(prog->function);
+ assert(runner);
runner(inputs, dests, consts, num_vertices, num_inputs,
num_attribs, prog->num_consts);
@@ -803,4 +810,53 @@ void gallivm_prog_dump(struct gallivm_prog *prog, const char *file_prefix)
}
}
+
+/*!
+ This function creates a CPU based execution engine for the given gallivm_prog.
+ gallivm_cpu_engine should be used as a singleton throughout the library. Before
+ executing gallivm_prog_exec one needs to call gallivm_cpu_jit_compile.
+ The gallivm_prog instance which is being passed to the constructor is being
+ automatically JIT compiled so one shouldn't call gallivm_cpu_jit_compile
+ with it again.
+ */
+struct gallivm_cpu_engine * gallivm_cpu_engine_create(struct gallivm_prog *prog)
+{
+ struct gallivm_cpu_engine *cpu = (struct gallivm_cpu_engine *)
+ calloc(1, sizeof(struct gallivm_cpu_engine));
+ llvm::Module *mod = static_cast<llvm::Module*>(prog->module);
+ llvm::ExistingModuleProvider *mp = new llvm::ExistingModuleProvider(mod);
+ llvm::ExecutionEngine *ee = llvm::ExecutionEngine::create(mp, false);
+ cpu->engine = ee;
+
+ llvm::Function *func = mod->getFunction("run_vertex_shader");
+ prog->function = ee->getPointerToFunctionOrStub(func);
+ return cpu;
+}
+
+
+/*!
+ This function JIT compiles the given gallivm_prog with the given cpu based execution engine.
+ The reference to the generated machine code entry point will be stored
+ in the gallivm_prog program. After executing this function one can call gallivm_prog_exec
+ in order to execute the gallivm_prog on the CPU.
+ */
+void gallivm_cpu_jit_compile(struct gallivm_cpu_engine *cpu, struct gallivm_prog *prog)
+{
+ llvm::Module *mod = static_cast<llvm::Module*>(prog->module);
+ llvm::ExistingModuleProvider *mp = new llvm::ExistingModuleProvider(mod);
+ llvm::ExecutionEngine *ee = cpu->engine;
+ assert(ee);
+ ee->addModuleProvider(mp);
+
+ llvm::Function *func = mod->getFunction("run_vertex_shader");
+ prog->function = ee->getPointerToFunctionOrStub(func);
+}
+
+void gallivm_cpu_engine_delete(struct gallivm_cpu_engine *cpu)
+{
+ free(cpu);
+}
+
#endif /* MESA_LLVM */
+
+
diff --git a/src/mesa/pipe/llvm/llvmtgsi.h b/src/mesa/pipe/llvm/llvmtgsi.h
index d4cf61ca97..a76dfd60b5 100644
--- a/src/mesa/pipe/llvm/llvmtgsi.h
+++ b/src/mesa/pipe/llvm/llvmtgsi.h
@@ -44,15 +44,12 @@ extern "C" {
struct tgsi_exec_machine;
struct tgsi_token;
struct tgsi_sampler;
-struct pipe_context;
struct gallivm_prog;
+struct gallivm_cpu_engine;
-struct gallivm_prog *
-gallivm_from_tgsi(struct pipe_context *pipe, const struct tgsi_token *tokens);
-
+struct gallivm_prog *gallivm_from_tgsi(const struct tgsi_token *tokens);
void gallivm_prog_delete(struct gallivm_prog *prog);
-
int gallivm_prog_exec(struct gallivm_prog *prog,
float (*inputs)[PIPE_MAX_SHADER_INPUTS][4],
float (*dests)[PIPE_MAX_SHADER_INPUTS][4],
@@ -60,9 +57,13 @@ int gallivm_prog_exec(struct gallivm_prog *prog,
int num_vertices,
int num_inputs,
int num_attribs);
-
void gallivm_prog_dump(struct gallivm_prog *prog, const char *file_prefix);
+
+struct gallivm_cpu_engine *gallivm_cpu_engine_create(struct gallivm_prog *prog);
+void gallivm_cpu_jit_compile(struct gallivm_cpu_engine *ee, struct gallivm_prog *prog);
+void gallivm_cpu_engine_delete(struct gallivm_cpu_engine *ee);
+
#endif /* MESA_LLVM */
#if defined __cplusplus
diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c
index 8c61815b9b..706238cbf5 100644
--- a/src/mesa/state_tracker/st_program.c
+++ b/src/mesa/state_tracker/st_program.c
@@ -251,9 +251,7 @@ st_translate_vertex_program(struct st_context *st,
tokensOut, maxTokens);
vs.tokens = tokensOut;
-#ifdef MESA_LLVM
- vs.llvm_prog = (void*)gallivm_from_tgsi(st->pipe, vs.tokens);
-#endif
+
cso = st_cached_vs_state(st, &vs);
stvp->vs = cso;