diff --git a/CMakeLists.txt b/CMakeLists.txt index 2867228..2f77eeb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/src/bluebell.cpp b/src/bluebell.cpp index e169c4d..5d2ffd4 100644 --- a/src/bluebell.cpp +++ b/src/bluebell.cpp @@ -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(frame), 3072); + image.flush(); + image.close(); + runtime->delete_shader_context(ctx); } \ No newline at end of file diff --git a/src/runtime.cpp b/src/runtime.cpp index 5254d79..d2fe814 100644 --- a/src/runtime.cpp +++ b/src/runtime.cpp @@ -12,16 +12,53 @@ #include #include #include +#include #include +#include +#include +#include #include +#include + +// 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 passManager; std::unique_ptr jit; + llvm::DataLayout dataLayout; + std::unique_ptr 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 session, llvm::orc::JITTargetMachineBuilder &machineBuilder, + llvm::DataLayout &layout): + dataLayout(layout), + executionSession(std::move(session)), + mangle(*executionSession, dataLayout), + main_dylib(this->executionSession->createBareJITDylib("
")), + objectLayer(*this->executionSession, [](){return std::make_unique(); }), + compileLayer(*executionSession, objectLayer, std::make_unique(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(); @@ -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(symbol.getAddress()); + } + if (auto err = executionSession->lookup({&main_dylib}, "setup_frame").moveInto(symbol)) { + return err; + } else { + setup_frame = reinterpret_cast(symbol.getAddress()); + } + if (auto err = executionSession->lookup({&main_dylib}, "render_pixel").moveInto(symbol)) { + return err; + } else { + render_pixel = reinterpret_cast(symbol.getAddress()); } return llvm::Error::success(); } + + ~RuntimeImpl() { + if (auto err = executionSession->endSession()) { + executionSession->reportError(std::move(err)); + } + } }; -Runtime::Runtime(): impl(std::make_unique()) { - -} +Runtime::Runtime(std::unique_ptr impl) : impl(std::move(impl)) {} Runtime::~Runtime() = default; +llvm::Expected Runtime::Create() { + // construct the needful for the runtime + auto epc = llvm::orc::SelfExecutorProcessControl::Create(); + if (!epc) { + return epc.takeError(); + } + auto session = std::make_unique(std::move(*epc)); + llvm::orc::JITTargetMachineBuilder jtmb(session->getExecutorProcessControl().getTargetTriple()); + auto dataLayout = jtmb.getDefaultDataLayoutForTarget(); + if (!dataLayout) return dataLayout.takeError(); + auto impl = std::make_unique(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(buf); +} + +void Runtime::delete_shader_context(shader_ctx *ctx) { + delete reinterpret_cast(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]); + } + } + } } diff --git a/src/runtime.hpp b/src/runtime.hpp index c415bfd..7abaca4 100644 --- a/src/runtime.hpp +++ b/src/runtime.hpp @@ -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 impl; + explicit Runtime(std::unique_ptr impl); public: - Runtime(); + Runtime(Runtime&& other) noexcept; ~Runtime(); + static llvm::Expected 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); }; \ No newline at end of file diff --git a/src/runtime_support.c b/src/runtime_support.c new file mode 100644 index 0000000..97f5f37 --- /dev/null +++ b/src/runtime_support.c @@ -0,0 +1,4 @@ +// +// Created by thequux on 5/28/22. +// +