Can now load the compiled shader and render a frame

This commit is contained in:
2022-05-28 16:28:45 +02:00
parent 6729ad02e3
commit 95fc9717de
5 changed files with 157 additions and 23 deletions

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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]);
}
}
}
}

View File

@@ -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
View File

@@ -0,0 +1,4 @@
//
// Created by thequux on 5/28/22.
//