Can now load the compiled shader and render a frame
This commit is contained in:
@@ -49,7 +49,7 @@ add_definitions(${LLVM_DEFINITIONS})
|
||||
|
||||
add_executable(bluebell
|
||||
src/bluebell.cpp src/bluebell.hpp
|
||||
src/pre-compiler.cpp src/pre-compiler.hpp src/compiler.cpp src/compiler.hpp src/spv_meta.cpp src/spv_meta.hpp src/runtime.cpp src/runtime.hpp)
|
||||
src/pre-compiler.cpp src/pre-compiler.hpp src/compiler.cpp src/compiler.hpp src/spv_meta.cpp src/spv_meta.hpp src/runtime.cpp src/runtime.hpp src/runtime_support.c)
|
||||
|
||||
add_executable(render_stub
|
||||
src/render_frame/render_stub.c)
|
||||
|
||||
@@ -53,9 +53,31 @@ int main(int argc, char** argv) {
|
||||
if (!module) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to build module";
|
||||
}
|
||||
Runtime runtime;
|
||||
if(auto err = runtime.set_module(std::move(module.getValue()))) {
|
||||
auto runtime = Runtime::Create();
|
||||
if (!runtime) {
|
||||
llvm::report_fatal_error(runtime.takeError());
|
||||
}
|
||||
if(auto err = runtime->set_module(std::move(module.getValue()))) {
|
||||
report_fatal_error(std::move(err), false);
|
||||
}
|
||||
|
||||
Uniforms uniforms = {
|
||||
{32.f, 32.f},
|
||||
0.f, 0.f, 0.f, {0.f},
|
||||
{0.f},
|
||||
{0.f},
|
||||
0.f, {{}}
|
||||
};
|
||||
|
||||
auto ctx = runtime->creeate_shader_context();
|
||||
|
||||
uint8_t frame[32][32][3];
|
||||
runtime->render_frame(ctx, uniforms, frame);
|
||||
|
||||
std::ofstream image("frame.ppm");
|
||||
image << "P6\n32 32\n255\n";
|
||||
image.write(reinterpret_cast<const char *>(frame), 3072);
|
||||
image.flush();
|
||||
image.close();
|
||||
runtime->delete_shader_context(ctx);
|
||||
}
|
||||
139
src/runtime.cpp
139
src/runtime.cpp
@@ -12,16 +12,53 @@
|
||||
#include <llvm/Transforms/Scalar/DCE.h>
|
||||
#include <llvm/Transforms/IPO.h>
|
||||
#include <llvm/Transforms/Utils.h>
|
||||
#include <llvm/ExecutionEngine/Orc/CompileUtils.h>
|
||||
#include <llvm/ExecutionEngine/Orc/LLJIT.h>
|
||||
#include <llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h>
|
||||
#include <llvm/ExecutionEngine/JITSymbol.h>
|
||||
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
// support functions
|
||||
void shs_debug_a3f(float f1, float f2, float f3) {
|
||||
(void)f1, f2, f3;
|
||||
}
|
||||
|
||||
struct shader_ctx; // opaque
|
||||
|
||||
// we need libm, so import it
|
||||
struct RuntimeImpl {
|
||||
|
||||
friend class Runtime;
|
||||
std::unique_ptr<llvm::legacy::PassManager> passManager;
|
||||
std::unique_ptr<llvm::orc::LLJIT> jit;
|
||||
llvm::DataLayout dataLayout;
|
||||
std::unique_ptr<llvm::orc::ExecutionSession> executionSession;
|
||||
llvm::orc::MangleAndInterner mangle;
|
||||
llvm::orc::JITDylib &main_dylib;
|
||||
llvm::orc::RTDyldObjectLinkingLayer objectLayer;
|
||||
llvm::orc::IRCompileLayer compileLayer;
|
||||
|
||||
explicit RuntimeImpl() {
|
||||
// addresses within module
|
||||
uint32_t (*get_context_size)();
|
||||
void (*render_pixel)(shader_ctx* ctx, float x, float y, float dst[3]);
|
||||
void (*setup_frame)(shader_ctx *ctx, const Uniforms* uniforms);
|
||||
|
||||
RuntimeImpl(std::unique_ptr<llvm::orc::ExecutionSession> session, llvm::orc::JITTargetMachineBuilder &machineBuilder,
|
||||
llvm::DataLayout &layout):
|
||||
dataLayout(layout),
|
||||
executionSession(std::move(session)),
|
||||
mangle(*executionSession, dataLayout),
|
||||
main_dylib(this->executionSession->createBareJITDylib("<main>")),
|
||||
objectLayer(*this->executionSession, [](){return std::make_unique<llvm::SectionMemoryManager>(); }),
|
||||
compileLayer(*executionSession, objectLayer, std::make_unique<llvm::orc::ConcurrentIRCompiler>(machineBuilder))
|
||||
{
|
||||
main_dylib.addGenerator(llvm::cantFail(llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(dataLayout.getGlobalPrefix())));
|
||||
build_pm();
|
||||
add_support_functions();
|
||||
}
|
||||
|
||||
void build_pm() {
|
||||
|
||||
// construct the pass manager
|
||||
passManager = std::make_unique<llvm::legacy::PassManager>();
|
||||
@@ -37,41 +74,107 @@ struct RuntimeImpl {
|
||||
// probably good for now, but need to look into further passes
|
||||
}
|
||||
|
||||
void add_support_functions() {
|
||||
llvm::orc::SymbolMap symbols;
|
||||
auto mangled = mangle("shs_debug_a3f");
|
||||
std::cerr << "Mangled: " << (*mangled).str() << std::endl;
|
||||
symbols[mangle("shs_debug_a3f")] = llvm::JITEvaluatedSymbol::fromPointer(shs_debug_a3f);
|
||||
llvm::cantFail(main_dylib.define(llvm::orc::absoluteSymbols(symbols)));
|
||||
}
|
||||
|
||||
llvm::Error setModule(llvm::orc::ThreadSafeModule mod) {
|
||||
mod.withModuleDo([&] (llvm::Module &mod1){
|
||||
passManager->run(mod1);
|
||||
});
|
||||
auto rt = main_dylib.getDefaultResourceTracker();
|
||||
// mod.withModuleDo([&] (llvm::Module &mod1){
|
||||
// passManager->run(mod1);
|
||||
// });
|
||||
|
||||
// construct the runtime
|
||||
auto jit_builder = llvm::orc::LLJITBuilder();
|
||||
jit = cantFail(jit_builder.create(), "Failed to create JIT");
|
||||
|
||||
if (auto err = jit->addIRModule(std::move(mod))) {
|
||||
if (auto err = compileLayer.add(main_dylib, std::move(mod))) {
|
||||
return err;
|
||||
}
|
||||
llvm::JITEvaluatedSymbol get_context_size;
|
||||
// construct the runtime
|
||||
llvm::JITEvaluatedSymbol symbol;
|
||||
|
||||
float foo = cosf(0.);
|
||||
|
||||
if (auto err = jit->lookup("get_context_size").moveInto(get_context_size)) {
|
||||
if (auto err = executionSession->lookup({&main_dylib}, "get_context_size").moveInto(symbol)) {
|
||||
return err;
|
||||
} else {
|
||||
this->get_context_size = reinterpret_cast<uint32_t (*)()>(symbol.getAddress());
|
||||
}
|
||||
if (auto err = executionSession->lookup({&main_dylib}, "setup_frame").moveInto(symbol)) {
|
||||
return err;
|
||||
} else {
|
||||
setup_frame = reinterpret_cast<void (*)(shader_ctx *, const Uniforms *)>(symbol.getAddress());
|
||||
}
|
||||
if (auto err = executionSession->lookup({&main_dylib}, "render_pixel").moveInto(symbol)) {
|
||||
return err;
|
||||
} else {
|
||||
render_pixel = reinterpret_cast<void (*)(shader_ctx *, float, float, float[3])>(symbol.getAddress());
|
||||
}
|
||||
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
~RuntimeImpl() {
|
||||
if (auto err = executionSession->endSession()) {
|
||||
executionSession->reportError(std::move(err));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Runtime::Runtime(): impl(std::make_unique<RuntimeImpl>()) {
|
||||
|
||||
}
|
||||
Runtime::Runtime(std::unique_ptr<RuntimeImpl> impl) : impl(std::move(impl)) {}
|
||||
Runtime::~Runtime() = default;
|
||||
|
||||
llvm::Expected<Runtime> Runtime::Create() {
|
||||
// construct the needful for the runtime
|
||||
auto epc = llvm::orc::SelfExecutorProcessControl::Create();
|
||||
if (!epc) {
|
||||
return epc.takeError();
|
||||
}
|
||||
auto session = std::make_unique<llvm::orc::ExecutionSession>(std::move(*epc));
|
||||
llvm::orc::JITTargetMachineBuilder jtmb(session->getExecutorProcessControl().getTargetTriple());
|
||||
auto dataLayout = jtmb.getDefaultDataLayoutForTarget();
|
||||
if (!dataLayout) return dataLayout.takeError();
|
||||
auto impl = std::make_unique<RuntimeImpl>(std::move(session), jtmb, *dataLayout);
|
||||
Runtime runtime(std::move(impl));
|
||||
return {std::move(runtime)};
|
||||
}
|
||||
|
||||
llvm::Error Runtime::set_module(llvm::orc::ThreadSafeModule module) {
|
||||
return impl->setModule(std::move(module));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Runtime::render_frame(const Uniforms &uniforms, float buf[32][32][3]) {
|
||||
Runtime::Runtime(Runtime &&other) noexcept: impl(std::move(other.impl)) {}
|
||||
|
||||
shader_ctx *Runtime::creeate_shader_context() {
|
||||
auto size = impl->get_context_size();
|
||||
auto buf = new uint8_t[size];
|
||||
return reinterpret_cast<shader_ctx *>(buf);
|
||||
}
|
||||
|
||||
void Runtime::delete_shader_context(shader_ctx *ctx) {
|
||||
delete reinterpret_cast<uint8_t *>(ctx);
|
||||
}
|
||||
|
||||
inline uint8_t float_to_byte(float f) {
|
||||
f *= 256;
|
||||
if (f < 0) { return 0; }
|
||||
else if (f > 255) { return 255; }
|
||||
else { return uint8_t(f); }
|
||||
}
|
||||
|
||||
void Runtime::render_frame(shader_ctx* ctx, const Uniforms &uniforms, uint8_t buf[32][32][3]) {
|
||||
impl->setup_frame(ctx, &uniforms);
|
||||
for (int i = 0; i < 32; i++) {
|
||||
for (int j = 0; j < 32; j++) {
|
||||
// float result[3] = {float(i)/32, float(j)/32, 0.f};
|
||||
float result[3] = {0.f, 0.f, 0.f};
|
||||
float rx = float(j) + 0.5f;
|
||||
float ry = float(31-i) + 0.5f; // shader origin is *bottom* left
|
||||
impl->render_pixel(ctx, rx, ry, result);
|
||||
for (int px = 0; px < 3; px++) {
|
||||
buf[i][j][px] = float_to_byte(result[px]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,14 +22,19 @@ struct Uniforms {
|
||||
float iChannelResolution[3][4];
|
||||
};
|
||||
|
||||
struct shader_ctx;
|
||||
class Runtime {
|
||||
// the compiler will construct this from its internals
|
||||
friend class Compiler;
|
||||
std::unique_ptr<struct RuntimeImpl> impl;
|
||||
explicit Runtime(std::unique_ptr<RuntimeImpl> impl);
|
||||
public:
|
||||
Runtime();
|
||||
Runtime(Runtime&& other) noexcept;
|
||||
~Runtime();
|
||||
|
||||
static llvm::Expected<Runtime> Create();
|
||||
llvm::Error set_module(llvm::orc::ThreadSafeModule module);
|
||||
void render_frame(const Uniforms &uniforms, float buf[32][32][3]);
|
||||
void render_frame(shader_ctx *ctx, const Uniforms &uniforms, uint8_t buf[32][32][3]);
|
||||
shader_ctx* creeate_shader_context();
|
||||
void delete_shader_context(shader_ctx* ctx);
|
||||
};
|
||||
4
src/runtime_support.c
Normal file
4
src/runtime_support.c
Normal file
@@ -0,0 +1,4 @@
|
||||
//
|
||||
// Created by thequux on 5/28/22.
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user