#pragma once #include #include #include #include namespace llvm { class CallInst; class Function; class Module; class Type; } // Combines DXIL raytracing shaders together into a compute shader. // // The incoming module should contain the following functions if the corresponding // intrinsic are called by the specified shaders, // if called: // Fallback_TraceRay() // Fallback_Ignore() // Fallback_AcceptHitAndEndSearch() // Fallback_ReportHit() // // Fallback_TraceRay() will be called with the original arguments, substituting // the offset of the payload on the stack for the actual payload. // Fallback_TraceRay() will also be used to replace calls to TraceRayTest(). // // ReportHit() returns a boolean. But to handle the abort of the intersection // shader when AcceptHitAndEndSearch() is called we need a third return value. // Fallback_ReportHit() should return an integer < 0 for end search, 0 for ignore, // and > 0 for accept. // // The module should also contain a single call to Fallback_Scheduler() in the // entry shader for the raytracing compute shader. // // resizeStack() needs to be called after inlining everything in the compute // shader. // // Currently the main scheduling loop and the implementation for intrinsic // functions come from an internal runtime module. class DxrFallbackCompiler { public: typedef std::map IntToFuncNameMap; // If findCalledShaders is true, then the list of shaderNames is expanded to // include shader functions (functions with attribute "exp-shader") that are // called by functions in shaderNames. Shader entry state IDs are still // returned only for those originally in shaderNames. findCalledShaders used // for testing. DxrFallbackCompiler(llvm::Module* mod, const std::vector& shaderNames, unsigned maxAttributeSize, unsigned stackSizeInBytes, bool findCalledShaders = false); // 0 - no debug output // 1 - dump initial combined module, compiled module, and final linked module // 2 - dump intermediate stages of SFT to console // 3 - dump intermediate stages of SFT to file void setDebugOutputLevel(int val); // Returns the entry state id for each of shaderNames. The transformations // are performed in place on the module. void compile(std::vector& shaderEntryStateIds, std::vector &shaderStackSizes, IntToFuncNameMap *pCachedMap); void link(std::vector& shaderEntryStateIds, std::vector &shaderStackSizes, IntToFuncNameMap *pCachedMap); // TODO: Ideally we would run this after inlining everything at the end of compile. // Until we figure out to do this, we will call the function after the final link. static void resizeStack(llvm::Function* F, unsigned stackSizeInBytes); private: typedef std::map IntToFuncMap; typedef std::map StringToFuncMap; llvm::Module* m_module = nullptr; const std::vector& m_entryShaderNames; unsigned m_stackSizeInBytes = 0; unsigned m_maxAttributeSize = 0; bool m_findCalledShaders = false; int m_debugOutputLevel = 0; StringToFuncMap m_shaderMap; void initShaderMap(std::vector& shaderNames); void linkRuntime(); void lowerAnyHitControlFlowFuncs(); void lowerReportHit(); void lowerTraceRay(llvm::Type* runtimeDataArgTy); void createStateFunctions(IntToFuncMap& stateFunctionMap, std::vector& shaderEntryStateIds, std::vector& shaderStackSizes, int baseStateId, const std::vector& shaderNames, llvm::Type* runtimeDataArgTy); void createLaunchParams(llvm::Function* func); void createStack(llvm::Function* func); void createStateDispatch(llvm::Function* func, const IntToFuncMap& stateFunctionMap, llvm::Type* runtimeDataArgTy); void lowerIntrinsics(); llvm::Type* getRuntimeDataArgType(); llvm::Function* createDispatchFunction(const IntToFuncMap &stateFunctionMap, llvm::Type* runtimeDataArgTy); // These functions return calls only in shaders in m_shaderMap. std::vector getCallsInShadersToFunction(const std::string& funcName); std::vector getCallsInShadersToFunctionWithPrefix(const std::string& funcNamePrefix); };