diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4b81a24f4..508951510 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1426,6 +1426,7 @@ set (PCH_SOURCES fragglescript/t_spec.cpp fragglescript/t_variable.cpp fragglescript/t_cmd.cpp + r_compiler/llvmdrawers.cpp r_compiler/ssa/ssa_bool.cpp r_compiler/ssa/ssa_float.cpp r_compiler/ssa/ssa_float_ptr.cpp diff --git a/src/r_compiler/fixedfunction/fixedfunction.cpp b/src/r_compiler/fixedfunction/fixedfunction.cpp index cc53a069a..fffd2c885 100644 --- a/src/r_compiler/fixedfunction/fixedfunction.cpp +++ b/src/r_compiler/fixedfunction/fixedfunction.cpp @@ -11,151 +11,6 @@ #include "r_compiler/ssa/ssa_value.h" #include "r_compiler/ssa/ssa_barycentric_weight.h" -RenderProgram::RenderProgram() -{ - using namespace llvm; - - install_fatal_error_handler([](void *user_data, const std::string& reason, bool gen_crash_diag) { - I_FatalError("LLVM fatal error: %s", reason.c_str()); - }); - - InitializeNativeTarget(); - InitializeNativeTargetAsmPrinter(); - InitializeNativeTargetAsmParser(); - - std::string errorstring; - - std::string targetTriple = sys::getProcessTriple(); - std::string cpuName = sys::getHostCPUName(); - StringMap cpuFeatures; - sys::getHostCPUFeatures(cpuFeatures); - std::string cpuFeaturesStr; - for (const auto &it : cpuFeatures) - { - if (!cpuFeaturesStr.empty()) - cpuFeaturesStr.push_back(' '); - cpuFeaturesStr.push_back(it.getValue() ? '+' : '-'); - cpuFeaturesStr += it.getKey(); - } - - //Printf("LLVM target triple: %s\n", targetTriple.c_str()); - //Printf("LLVM CPU and features: %s, %s\n", cpuName.c_str(), cpuFeaturesStr.c_str()); - - const Target *target = TargetRegistry::lookupTarget(targetTriple, errorstring); - if (!target) - I_FatalError("Could not find LLVM target: %s", errorstring.c_str()); - - TargetOptions opt; - auto relocModel = Optional(Reloc::Static); - TargetMachine *machine = target->createTargetMachine(targetTriple, cpuName, cpuFeaturesStr, opt, relocModel, CodeModel::Default, CodeGenOpt::Aggressive); - if (!machine) - I_FatalError("Could not create LLVM target machine"); - - mContext = std::make_unique(); - - auto moduleOwner = std::make_unique("render", context()); - mModule = moduleOwner.get(); - mModule->setTargetTriple(targetTriple); - mModule->setDataLayout(machine->createDataLayout()); - - EngineBuilder engineBuilder(std::move(moduleOwner)); - engineBuilder.setErrorStr(&errorstring); - engineBuilder.setOptLevel(CodeGenOpt::Aggressive); - engineBuilder.setRelocationModel(Reloc::Static); - engineBuilder.setEngineKind(EngineKind::JIT); - mEngine.reset(engineBuilder.create(machine)); - if (!mEngine) - I_FatalError("Could not create LLVM execution engine: %s", errorstring.c_str()); - - mModulePassManager = std::make_unique(); - mFunctionPassManager = std::make_unique(mModule); - - PassManagerBuilder passManagerBuilder; - passManagerBuilder.OptLevel = 3; - passManagerBuilder.SizeLevel = 0; - passManagerBuilder.Inliner = createFunctionInliningPass(); - passManagerBuilder.populateModulePassManager(*mModulePassManager.get()); - passManagerBuilder.populateFunctionPassManager(*mFunctionPassManager.get()); -} - -RenderProgram::~RenderProgram() -{ - mEngine.reset(); - mContext.reset(); -} - -void *RenderProgram::PointerToFunction(const char *name) -{ - llvm::Function *function = mModule->getFunction(name); - if (!function) - return nullptr; - return mEngine->getPointerToFunction(function); -} - -///////////////////////////////////////////////////////////////////////////// - -FixedFunction::FixedFunction() -{ - CodegenDrawSpan(); - mProgram.engine()->finalizeObject(); - mProgram.modulePassManager()->run(*mProgram.module()); - - DrawSpan = mProgram.GetProcAddress("DrawSpan"); -} - -void FixedFunction::CodegenDrawSpan() -{ - llvm::IRBuilder<> builder(mProgram.context()); - SSAScope ssa_scope(&mProgram.context(), mProgram.module(), &builder); - - SSAFunction function("DrawSpan"); - function.add_parameter(GetRenderArgsStruct(mProgram.context())); - function.create_public(); - - DrawSpanCodegen codegen; - codegen.Generate(function.parameter(0)); - - builder.CreateRetVoid(); - - if (llvm::verifyFunction(*function.func)) - I_FatalError("verifyFunction failed for " __FUNCTION__); - - mProgram.functionPassManager()->run(*function.func); -} - -llvm::Type *FixedFunction::GetRenderArgsStruct(llvm::LLVMContext &context) -{ - std::vector elements; - elements.push_back(llvm::Type::getInt8PtrTy(context)); // uint8_t *destorg; - elements.push_back(llvm::Type::getInt8PtrTy(context)); // const uint8_t *source; - elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t destpitch; - elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t xfrac; - elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t yfrac; - elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t xstep; - elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t ystep; - elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t x1; - elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t x2; - elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t y; - elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t xbits; - elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t ybits; - elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t light; - elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t srcalpha; - elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t destalpha; - elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_alpha; - elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_red; - elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_green; - elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_blue; - elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_alpha; - elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_red; - elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_green; - elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_blue; - elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t desaturate; - elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t flags; - return llvm::StructType::get(context, elements, false)->getPointerTo(); -} - -///////////////////////////////////////////////////////////////////////////// - void DrawSpanCodegen::Generate(SSAValue args) { destorg = args[0][0].load(); diff --git a/src/r_compiler/fixedfunction/fixedfunction.h b/src/r_compiler/fixedfunction/fixedfunction.h index d9b8f042e..4b5bfc8b7 100644 --- a/src/r_compiler/fixedfunction/fixedfunction.h +++ b/src/r_compiler/fixedfunction/fixedfunction.h @@ -1,6 +1,7 @@ #pragma once +#include "r_compiler/llvmdrawers.h" #include "r_compiler/ssa/ssa_value.h" #include "r_compiler/ssa/ssa_vec4f.h" #include "r_compiler/ssa/ssa_vec4i.h" @@ -17,66 +18,6 @@ #include "r_compiler/ssa/ssa_barycentric_weight.h" #include "r_compiler/llvm_include.h" -class RenderProgram -{ -public: - RenderProgram(); - ~RenderProgram(); - - template - Func *GetProcAddress(const char *name) { return reinterpret_cast(PointerToFunction(name)); } - - llvm::LLVMContext &context() { return *mContext; } - llvm::Module *module() { return mModule; } - llvm::ExecutionEngine *engine() { return mEngine.get(); } - llvm::legacy::PassManager *modulePassManager() { return mModulePassManager.get(); } - llvm::legacy::FunctionPassManager *functionPassManager() { return mFunctionPassManager.get(); } - -private: - void *PointerToFunction(const char *name); - - std::unique_ptr mContext; - llvm::Module *mModule; - std::unique_ptr mEngine; - std::unique_ptr mModulePassManager; - std::unique_ptr mFunctionPassManager; -}; - -struct RenderArgs -{ - uint32_t *destorg; - const uint32_t *source; - int32_t destpitch; - int32_t xfrac; - int32_t yfrac; - int32_t xstep; - int32_t ystep; - int32_t x1; - int32_t x2; - int32_t y; - int32_t xbits; - int32_t ybits; - uint32_t light; - uint32_t srcalpha; - uint32_t destalpha; - - uint16_t light_alpha; - uint16_t light_red; - uint16_t light_green; - uint16_t light_blue; - uint16_t fade_alpha; - uint16_t fade_red; - uint16_t fade_green; - uint16_t fade_blue; - uint16_t desaturate; - uint32_t flags; - enum Flags - { - simple_shade = 1, - nearest_filter = 2 - }; -}; - class SSAShadeConstants { public: @@ -144,18 +85,3 @@ private: SSABool is_nearest_filter; SSAShadeConstants shade_constants; }; - -class FixedFunction -{ -public: - FixedFunction(); - - void(*DrawSpan)(const RenderArgs *) = nullptr; - -private: - void CodegenDrawSpan(); - - static llvm::Type *GetRenderArgsStruct(llvm::LLVMContext &context); - - RenderProgram mProgram; -}; diff --git a/src/r_compiler/llvmdrawers.cpp b/src/r_compiler/llvmdrawers.cpp new file mode 100644 index 000000000..408213707 --- /dev/null +++ b/src/r_compiler/llvmdrawers.cpp @@ -0,0 +1,232 @@ + +#include "i_system.h" +#include "r_compiler/fixedfunction/fixedfunction.h" +#include "r_compiler/ssa/ssa_function.h" +#include "r_compiler/ssa/ssa_scope.h" +#include "r_compiler/ssa/ssa_for_block.h" +#include "r_compiler/ssa/ssa_if_block.h" +#include "r_compiler/ssa/ssa_stack.h" +#include "r_compiler/ssa/ssa_function.h" +#include "r_compiler/ssa/ssa_struct_type.h" +#include "r_compiler/ssa/ssa_value.h" +#include "r_compiler/ssa/ssa_barycentric_weight.h" + +class LLVMProgram +{ +public: + LLVMProgram(); + ~LLVMProgram(); + + void StopLogFatalErrors(); + + template + Func *GetProcAddress(const char *name) { return reinterpret_cast(PointerToFunction(name)); } + + llvm::LLVMContext &context() { return *mContext; } + llvm::Module *module() { return mModule; } + llvm::ExecutionEngine *engine() { return mEngine.get(); } + llvm::legacy::PassManager *modulePassManager() { return mModulePassManager.get(); } + llvm::legacy::FunctionPassManager *functionPassManager() { return mFunctionPassManager.get(); } + +private: + void *PointerToFunction(const char *name); + + std::unique_ptr mContext; + llvm::Module *mModule; + std::unique_ptr mEngine; + std::unique_ptr mModulePassManager; + std::unique_ptr mFunctionPassManager; +}; + +class LLVMDrawersImpl : public LLVMDrawers +{ +public: + LLVMDrawersImpl(); + +private: + void CodegenDrawSpan(); + static llvm::Type *GetRenderArgsStruct(llvm::LLVMContext &context); + + LLVMProgram mProgram; +}; + +///////////////////////////////////////////////////////////////////////////// + +LLVMDrawers *LLVMDrawers::Singleton = nullptr; + +void LLVMDrawers::Create() +{ + if (!Singleton) + Singleton = new LLVMDrawersImpl(); +} + +void LLVMDrawers::Destroy() +{ + delete Singleton; + Singleton = nullptr; +} + +LLVMDrawers *LLVMDrawers::Instance() +{ + return Singleton; +} + +///////////////////////////////////////////////////////////////////////////// + +LLVMDrawersImpl::LLVMDrawersImpl() +{ + CodegenDrawSpan(); + mProgram.engine()->finalizeObject(); + mProgram.modulePassManager()->run(*mProgram.module()); + + DrawSpan = mProgram.GetProcAddress("DrawSpan"); + + mProgram.StopLogFatalErrors(); +} + +void LLVMDrawersImpl::CodegenDrawSpan() +{ + llvm::IRBuilder<> builder(mProgram.context()); + SSAScope ssa_scope(&mProgram.context(), mProgram.module(), &builder); + + SSAFunction function("DrawSpan"); + function.add_parameter(GetRenderArgsStruct(mProgram.context())); + function.create_public(); + + DrawSpanCodegen codegen; + codegen.Generate(function.parameter(0)); + + builder.CreateRetVoid(); + + if (llvm::verifyFunction(*function.func)) + I_FatalError("verifyFunction failed for " __FUNCTION__); + + mProgram.functionPassManager()->run(*function.func); +} + +llvm::Type *LLVMDrawersImpl::GetRenderArgsStruct(llvm::LLVMContext &context) +{ + std::vector elements; + elements.push_back(llvm::Type::getInt8PtrTy(context)); // uint8_t *destorg; + elements.push_back(llvm::Type::getInt8PtrTy(context)); // const uint8_t *source; + elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t destpitch; + elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t xfrac; + elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t yfrac; + elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t xstep; + elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t ystep; + elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t x1; + elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t x2; + elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t y; + elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t xbits; + elements.push_back(llvm::Type::getInt32Ty(context)); // int32_t ybits; + elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t light; + elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t srcalpha; + elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t destalpha; + elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_alpha; + elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_red; + elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_green; + elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t light_blue; + elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_alpha; + elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_red; + elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_green; + elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t fade_blue; + elements.push_back(llvm::Type::getInt16Ty(context)); // uint16_t desaturate; + elements.push_back(llvm::Type::getInt32Ty(context)); // uint32_t flags; + return llvm::StructType::get(context, elements, false)->getPointerTo(); +} + +///////////////////////////////////////////////////////////////////////////// + +namespace { static bool LogFatalErrors = false; } + +LLVMProgram::LLVMProgram() +{ + using namespace llvm; + + // We have to extra careful about this because both LLVM and ZDoom made + // the very unwise decision to hook atexit. To top it off, LLVM decided + // to log something in the atexit handler.. + LogFatalErrors = true; + + install_fatal_error_handler([](void *user_data, const std::string& reason, bool gen_crash_diag) { + if (LogFatalErrors) + I_FatalError("LLVM fatal error: %s", reason.c_str()); + }); + + InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); + InitializeNativeTargetAsmParser(); + + std::string errorstring; + + std::string targetTriple = sys::getProcessTriple(); + std::string cpuName = sys::getHostCPUName(); + StringMap cpuFeatures; + sys::getHostCPUFeatures(cpuFeatures); + std::string cpuFeaturesStr; + for (const auto &it : cpuFeatures) + { + if (!cpuFeaturesStr.empty()) + cpuFeaturesStr.push_back(' '); + cpuFeaturesStr.push_back(it.getValue() ? '+' : '-'); + cpuFeaturesStr += it.getKey(); + } + + //Printf("LLVM target triple: %s\n", targetTriple.c_str()); + //Printf("LLVM CPU and features: %s, %s\n", cpuName.c_str(), cpuFeaturesStr.c_str()); + + const Target *target = TargetRegistry::lookupTarget(targetTriple, errorstring); + if (!target) + I_FatalError("Could not find LLVM target: %s", errorstring.c_str()); + + TargetOptions opt; + auto relocModel = Optional(Reloc::Static); + TargetMachine *machine = target->createTargetMachine(targetTriple, cpuName, cpuFeaturesStr, opt, relocModel, CodeModel::Default, CodeGenOpt::Aggressive); + if (!machine) + I_FatalError("Could not create LLVM target machine"); + + mContext = std::make_unique(); + + auto moduleOwner = std::make_unique("render", context()); + mModule = moduleOwner.get(); + mModule->setTargetTriple(targetTriple); + mModule->setDataLayout(machine->createDataLayout()); + + EngineBuilder engineBuilder(std::move(moduleOwner)); + engineBuilder.setErrorStr(&errorstring); + engineBuilder.setOptLevel(CodeGenOpt::Aggressive); + engineBuilder.setRelocationModel(Reloc::Static); + engineBuilder.setEngineKind(EngineKind::JIT); + mEngine.reset(engineBuilder.create(machine)); + if (!mEngine) + I_FatalError("Could not create LLVM execution engine: %s", errorstring.c_str()); + + mModulePassManager = std::make_unique(); + mFunctionPassManager = std::make_unique(mModule); + + PassManagerBuilder passManagerBuilder; + passManagerBuilder.OptLevel = 3; + passManagerBuilder.SizeLevel = 0; + passManagerBuilder.Inliner = createFunctionInliningPass(); + passManagerBuilder.populateModulePassManager(*mModulePassManager.get()); + passManagerBuilder.populateFunctionPassManager(*mFunctionPassManager.get()); +} + +LLVMProgram::~LLVMProgram() +{ + mEngine.reset(); + mContext.reset(); +} + +void *LLVMProgram::PointerToFunction(const char *name) +{ + llvm::Function *function = mModule->getFunction(name); + if (!function) + return nullptr; + return mEngine->getPointerToFunction(function); +} + +void LLVMProgram::StopLogFatalErrors() +{ + LogFatalErrors = false; +} diff --git a/src/r_compiler/llvmdrawers.h b/src/r_compiler/llvmdrawers.h new file mode 100644 index 000000000..2ad6c3d52 --- /dev/null +++ b/src/r_compiler/llvmdrawers.h @@ -0,0 +1,52 @@ + +#pragma once + +struct RenderArgs +{ + uint32_t *destorg; + const uint32_t *source; + int32_t destpitch; + int32_t xfrac; + int32_t yfrac; + int32_t xstep; + int32_t ystep; + int32_t x1; + int32_t x2; + int32_t y; + int32_t xbits; + int32_t ybits; + uint32_t light; + uint32_t srcalpha; + uint32_t destalpha; + + uint16_t light_alpha; + uint16_t light_red; + uint16_t light_green; + uint16_t light_blue; + uint16_t fade_alpha; + uint16_t fade_red; + uint16_t fade_green; + uint16_t fade_blue; + uint16_t desaturate; + uint32_t flags; + enum Flags + { + simple_shade = 1, + nearest_filter = 2 + }; +}; + +class LLVMDrawers +{ +public: + virtual ~LLVMDrawers() { } + + static void Create(); + static void Destroy(); + static LLVMDrawers *Instance(); + + void(*DrawSpan)(const RenderArgs *) = nullptr; + +private: + static LLVMDrawers *Singleton; +}; diff --git a/src/r_draw_rgba.cpp b/src/r_draw_rgba.cpp index 665e6b84e..9c2cd6293 100644 --- a/src/r_draw_rgba.cpp +++ b/src/r_draw_rgba.cpp @@ -38,7 +38,7 @@ #include "r_data/colormaps.h" #include "r_plane.h" #include "r_draw_rgba.h" -#include "r_compiler/fixedfunction/fixedfunction.h" +#include "r_compiler/llvmdrawers.h" #include "gi.h" #include "stats.h" @@ -303,7 +303,6 @@ void DrawerCommandQueue::StopThreads() class DrawSpanLLVMCommand : public DrawerCommand { RenderArgs args; - FixedFunction *_ff; public: DrawSpanLLVMCommand() @@ -337,16 +336,13 @@ public: args.flags |= RenderArgs::simple_shade; if (!SampleBgra::span_sampler_setup(args.source, args.xbits, args.ybits, args.xstep, args.ystep, ds_source_mipmapped)) args.flags |= RenderArgs::nearest_filter; - - static FixedFunction ff; - _ff = &ff; } void Execute(DrawerThread *thread) override { if (thread->skipped_by_thread(args.y)) return; - _ff->DrawSpan(&args); + LLVMDrawers::Instance()->DrawSpan(&args); } }; diff --git a/src/r_swrenderer.cpp b/src/r_swrenderer.cpp index 5be847502..b9a9ea7fd 100644 --- a/src/r_swrenderer.cpp +++ b/src/r_swrenderer.cpp @@ -43,6 +43,7 @@ #include "textures/textures.h" #include "r_data/voxels.h" #include "r_draw_rgba.h" +#include "r_compiler/llvmdrawers.h" EXTERN_CVAR(Bool, r_shadercolormaps) @@ -51,6 +52,16 @@ void R_SetupColormap(player_t *); void R_SetupFreelook(); void R_InitRenderer(); +FSoftwareRenderer::FSoftwareRenderer() +{ + LLVMDrawers::Create(); +} + +FSoftwareRenderer::~FSoftwareRenderer() +{ + LLVMDrawers::Destroy(); +} + //========================================================================== // // DCanvas :: Init diff --git a/src/r_swrenderer.h b/src/r_swrenderer.h index f9d5609a0..fc3ec2551 100644 --- a/src/r_swrenderer.h +++ b/src/r_swrenderer.h @@ -5,6 +5,9 @@ struct FSoftwareRenderer : public FRenderer { + FSoftwareRenderer(); + ~FSoftwareRenderer(); + // Can be overridden so that the colormaps for sector color/fade won't be built. virtual bool UsesColormap() const override;