Create LLVMDrawers class as the external interface to the drawers

This commit is contained in:
Magnus Norddahl 2016-09-29 02:10:14 +02:00
parent 3aea3a0bee
commit bfa291b02f
8 changed files with 302 additions and 226 deletions

View file

@ -1426,6 +1426,7 @@ set (PCH_SOURCES
fragglescript/t_spec.cpp fragglescript/t_spec.cpp
fragglescript/t_variable.cpp fragglescript/t_variable.cpp
fragglescript/t_cmd.cpp fragglescript/t_cmd.cpp
r_compiler/llvmdrawers.cpp
r_compiler/ssa/ssa_bool.cpp r_compiler/ssa/ssa_bool.cpp
r_compiler/ssa/ssa_float.cpp r_compiler/ssa/ssa_float.cpp
r_compiler/ssa/ssa_float_ptr.cpp r_compiler/ssa/ssa_float_ptr.cpp

View file

@ -11,151 +11,6 @@
#include "r_compiler/ssa/ssa_value.h" #include "r_compiler/ssa/ssa_value.h"
#include "r_compiler/ssa/ssa_barycentric_weight.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<bool> 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::Model>(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<LLVMContext>();
auto moduleOwner = std::make_unique<Module>("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<legacy::PassManager>();
mFunctionPassManager = std::make_unique<legacy::FunctionPassManager>(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<void(const RenderArgs *)>("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<llvm::Type *> 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) void DrawSpanCodegen::Generate(SSAValue args)
{ {
destorg = args[0][0].load(); destorg = args[0][0].load();

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "r_compiler/llvmdrawers.h"
#include "r_compiler/ssa/ssa_value.h" #include "r_compiler/ssa/ssa_value.h"
#include "r_compiler/ssa/ssa_vec4f.h" #include "r_compiler/ssa/ssa_vec4f.h"
#include "r_compiler/ssa/ssa_vec4i.h" #include "r_compiler/ssa/ssa_vec4i.h"
@ -17,66 +18,6 @@
#include "r_compiler/ssa/ssa_barycentric_weight.h" #include "r_compiler/ssa/ssa_barycentric_weight.h"
#include "r_compiler/llvm_include.h" #include "r_compiler/llvm_include.h"
class RenderProgram
{
public:
RenderProgram();
~RenderProgram();
template<typename Func>
Func *GetProcAddress(const char *name) { return reinterpret_cast<Func*>(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<llvm::LLVMContext> mContext;
llvm::Module *mModule;
std::unique_ptr<llvm::ExecutionEngine> mEngine;
std::unique_ptr<llvm::legacy::PassManager> mModulePassManager;
std::unique_ptr<llvm::legacy::FunctionPassManager> 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 class SSAShadeConstants
{ {
public: public:
@ -144,18 +85,3 @@ private:
SSABool is_nearest_filter; SSABool is_nearest_filter;
SSAShadeConstants shade_constants; SSAShadeConstants shade_constants;
}; };
class FixedFunction
{
public:
FixedFunction();
void(*DrawSpan)(const RenderArgs *) = nullptr;
private:
void CodegenDrawSpan();
static llvm::Type *GetRenderArgsStruct(llvm::LLVMContext &context);
RenderProgram mProgram;
};

View file

@ -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<typename Func>
Func *GetProcAddress(const char *name) { return reinterpret_cast<Func*>(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<llvm::LLVMContext> mContext;
llvm::Module *mModule;
std::unique_ptr<llvm::ExecutionEngine> mEngine;
std::unique_ptr<llvm::legacy::PassManager> mModulePassManager;
std::unique_ptr<llvm::legacy::FunctionPassManager> 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<void(const RenderArgs *)>("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<llvm::Type *> 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<bool> 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::Model>(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<LLVMContext>();
auto moduleOwner = std::make_unique<Module>("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<legacy::PassManager>();
mFunctionPassManager = std::make_unique<legacy::FunctionPassManager>(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;
}

View file

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

View file

@ -38,7 +38,7 @@
#include "r_data/colormaps.h" #include "r_data/colormaps.h"
#include "r_plane.h" #include "r_plane.h"
#include "r_draw_rgba.h" #include "r_draw_rgba.h"
#include "r_compiler/fixedfunction/fixedfunction.h" #include "r_compiler/llvmdrawers.h"
#include "gi.h" #include "gi.h"
#include "stats.h" #include "stats.h"
@ -303,7 +303,6 @@ void DrawerCommandQueue::StopThreads()
class DrawSpanLLVMCommand : public DrawerCommand class DrawSpanLLVMCommand : public DrawerCommand
{ {
RenderArgs args; RenderArgs args;
FixedFunction *_ff;
public: public:
DrawSpanLLVMCommand() DrawSpanLLVMCommand()
@ -337,16 +336,13 @@ public:
args.flags |= RenderArgs::simple_shade; args.flags |= RenderArgs::simple_shade;
if (!SampleBgra::span_sampler_setup(args.source, args.xbits, args.ybits, args.xstep, args.ystep, ds_source_mipmapped)) if (!SampleBgra::span_sampler_setup(args.source, args.xbits, args.ybits, args.xstep, args.ystep, ds_source_mipmapped))
args.flags |= RenderArgs::nearest_filter; args.flags |= RenderArgs::nearest_filter;
static FixedFunction ff;
_ff = &ff;
} }
void Execute(DrawerThread *thread) override void Execute(DrawerThread *thread) override
{ {
if (thread->skipped_by_thread(args.y)) if (thread->skipped_by_thread(args.y))
return; return;
_ff->DrawSpan(&args); LLVMDrawers::Instance()->DrawSpan(&args);
} }
}; };

View file

@ -43,6 +43,7 @@
#include "textures/textures.h" #include "textures/textures.h"
#include "r_data/voxels.h" #include "r_data/voxels.h"
#include "r_draw_rgba.h" #include "r_draw_rgba.h"
#include "r_compiler/llvmdrawers.h"
EXTERN_CVAR(Bool, r_shadercolormaps) EXTERN_CVAR(Bool, r_shadercolormaps)
@ -51,6 +52,16 @@ void R_SetupColormap(player_t *);
void R_SetupFreelook(); void R_SetupFreelook();
void R_InitRenderer(); void R_InitRenderer();
FSoftwareRenderer::FSoftwareRenderer()
{
LLVMDrawers::Create();
}
FSoftwareRenderer::~FSoftwareRenderer()
{
LLVMDrawers::Destroy();
}
//========================================================================== //==========================================================================
// //
// DCanvas :: Init // DCanvas :: Init

View file

@ -5,6 +5,9 @@
struct FSoftwareRenderer : public FRenderer struct FSoftwareRenderer : public FRenderer
{ {
FSoftwareRenderer();
~FSoftwareRenderer();
// Can be overridden so that the colormaps for sector color/fade won't be built. // Can be overridden so that the colormaps for sector color/fade won't be built.
virtual bool UsesColormap() const override; virtual bool UsesColormap() const override;